|
|
1.1 ! root 1: # include <stdio.h> ! 2: # include <ctype.h> ! 3: # include "dlvrmail.h" ! 4: ! 5: static char SccsId[] = "@(#)parse.c 1.7 10/21/80"; ! 6: ! 7: /* ! 8: ** PARSE -- Parse an address ! 9: ** ! 10: ** Parses an address and breaks it up into three parts: a ! 11: ** net to transmit the message on, the host to transmit it ! 12: ** to, and a user on that host. These are loaded into an ! 13: ** addrq header with the values squirreled away if necessary. ! 14: ** The "user" part may not be a real user; the process may ! 15: ** just reoccur on that machine. For example, on a machine ! 16: ** with an arpanet connection, the address ! 17: ** csvax.bill@berkeley ! 18: ** will break up to a "user" of 'csvax.bill' and a host ! 19: ** of 'berkeley' -- to be transmitted over the arpanet. ! 20: ** ! 21: ** Parameters: ! 22: ** addr -- the address to parse. ! 23: ** a -- a pointer to the address descriptor buffer. ! 24: ** If NULL, a header will be created. ! 25: ** copyf -- determines what shall be copied: ! 26: ** -1 -- don't copy anything. The printname ! 27: ** (q_paddr) is just addr, and the ! 28: ** user & host are allocated internally ! 29: ** to parse. ! 30: ** 0 -- copy out the parsed user & host, but ! 31: ** don't copy the printname. ! 32: ** +1 -- copy everything. ! 33: ** ! 34: ** Returns: ! 35: ** A pointer to the address descriptor header (`a' if ! 36: ** `a' is non-NULL). ! 37: ** NULL on error. ! 38: ** ! 39: ** Side Effects: ! 40: ** none ! 41: ** ! 42: ** Called By: ! 43: ** main ! 44: ** sendto ! 45: ** alias ! 46: ** savemail ! 47: */ ! 48: ! 49: addrq * ! 50: parse(addr, a, copyf) ! 51: char *addr; ! 52: register addrq *a; ! 53: int copyf; ! 54: { ! 55: register char *p; ! 56: register struct parsetab *t; ! 57: extern struct parsetab ParseTab[]; ! 58: static char buf[MAXNAME]; ! 59: register char c; ! 60: register char *q; ! 61: bool got_one; ! 62: extern char *prescan(); ! 63: extern char *xalloc(); ! 64: char **pvp; ! 65: ! 66: /* ! 67: ** Initialize and prescan address. ! 68: */ ! 69: ! 70: To = addr; ! 71: if (prescan(addr, buf, &buf[sizeof buf], '\0') == NULL) ! 72: return (NULL); ! 73: ! 74: /* ! 75: ** Scan parse table. ! 76: ** Look for the first entry designating a character ! 77: ** that is contained in the address. ! 78: ** Arrange for q to point to that character. ! 79: ** Check to see that there is only one of the char ! 80: ** if it must be unique. ! 81: ** Find the last one if the host is on the RHS. ! 82: ** Insist that the host name is atomic. ! 83: ** If just doing a map, do the map and then start all ! 84: ** over. ! 85: */ ! 86: ! 87: rescan: ! 88: got_one = FALSE; ! 89: for (t = ParseTab; t->p_char != '\0'; t++) ! 90: { ! 91: q = NULL; ! 92: for (p = buf; (c = *p) != '\0'; p++) ! 93: { ! 94: /* find the end of this token */ ! 95: while (isalnum(c) || c == '-' || c == '_') ! 96: c = *++p; ! 97: if (c == '\0') ! 98: break; ! 99: ! 100: if (c == t->p_char) ! 101: { ! 102: got_one = TRUE; ! 103: ! 104: /* do mapping as appropriate */ ! 105: if (flagset(P_MAP, t->p_flags)) ! 106: { ! 107: *p = t->p_arg[0]; ! 108: if (flagset(P_ONE, t->p_flags)) ! 109: goto rescan; ! 110: else ! 111: continue; ! 112: } ! 113: ! 114: /* arrange for q to point to it */ ! 115: if (q != NULL && flagset(P_ONE, t->p_flags)) ! 116: { ! 117: usrerr("multichar error"); ! 118: ExitStat = EX_USAGE; ! 119: return (NULL); ! 120: } ! 121: if (q == NULL || flagset(P_HLAST, t->p_flags)) ! 122: q = p; ! 123: } ! 124: else ! 125: { ! 126: /* insist that host name is atomic */ ! 127: if (flagset(P_HLAST, t->p_flags)) ! 128: q = NULL; ! 129: else ! 130: break; ! 131: } ! 132: } ! 133: ! 134: if (q != NULL) ! 135: break; ! 136: } ! 137: ! 138: /* ! 139: ** If we matched nothing cleanly, but we did match something ! 140: ** somewhere in the process of scanning, then we have a ! 141: ** syntax error. This can happen on things like a@b:c where ! 142: ** @ has a right host and : has a left host. ! 143: ** ! 144: ** We also set `q' to the null string, in case someone forgets ! 145: ** to put the P_MOVE bit in the local mailer entry of the ! 146: ** configuration table. ! 147: */ ! 148: ! 149: if (q == NULL) ! 150: { ! 151: q = ""; ! 152: if (got_one) ! 153: { ! 154: usrerr("syntax error"); ! 155: ExitStat = EX_USAGE; ! 156: return (NULL); ! 157: } ! 158: } ! 159: ! 160: /* ! 161: ** Interpret entry. ! 162: ** t points to the entry for the mailer we will use. ! 163: ** q points to the significant character. ! 164: */ ! 165: ! 166: if (a == NULL) ! 167: a = (addrq *) xalloc(sizeof *a); ! 168: if (copyf > 0) ! 169: { ! 170: p = xalloc((unsigned) strlen(addr) + 1); ! 171: strcpy(p, addr); ! 172: a->q_paddr = p; ! 173: } ! 174: else ! 175: a->q_paddr = addr; ! 176: a->q_mailer = &Mailer[t->p_mailer]; ! 177: ! 178: if (flagset(P_MOVE, t->p_flags)) ! 179: { ! 180: /* send the message to another host & retry */ ! 181: a->q_host = t->p_arg; ! 182: if (copyf >= 0) ! 183: { ! 184: p = xalloc((unsigned) strlen(buf) + 1); ! 185: strcpy(p, buf); ! 186: a->q_user = p; ! 187: } ! 188: else ! 189: a->q_user = buf; ! 190: } ! 191: else ! 192: { ! 193: /* ! 194: ** Make local copies of the host & user and then ! 195: ** transport them out. ! 196: */ ! 197: ! 198: *q++ = '\0'; ! 199: if (flagset(P_HLAST, t->p_flags)) ! 200: { ! 201: a->q_host = q; ! 202: a->q_user = buf; ! 203: } ! 204: else ! 205: { ! 206: a->q_host = buf; ! 207: a->q_user = q; ! 208: } ! 209: ! 210: /* ! 211: ** Don't go to the net if already on the target host. ! 212: ** This is important on the berkeley network, since ! 213: ** it get confused if we ask to send to ourselves. ! 214: ** For nets like the ARPANET, we probably will have ! 215: ** the local list set to NULL to simplify testing. ! 216: ** The canonical representation of the name is also set ! 217: ** to be just the local name so the duplicate letter ! 218: ** suppression algorithm will work. ! 219: */ ! 220: ! 221: if ((pvp = a->q_mailer->m_local) != NULL) ! 222: { ! 223: while (*pvp != NULL) ! 224: { ! 225: auto char buf2[MAXNAME]; ! 226: ! 227: strcpy(buf2, a->q_host); ! 228: if (!flagset(P_HST_UPPER, t->p_flags)) ! 229: makelower(buf2); ! 230: if (strcmp(*pvp++, buf2) == 0) ! 231: { ! 232: strcpy(buf2, a->q_user); ! 233: p = a->q_paddr; ! 234: if (parse(buf2, a, -1) == NULL) ! 235: { ! 236: To = addr; ! 237: return (NULL); ! 238: } ! 239: To = a->q_paddr = p; ! 240: break; ! 241: } ! 242: } ! 243: } ! 244: ! 245: /* make copies if specified */ ! 246: if (copyf >= 0) ! 247: { ! 248: p = xalloc((unsigned) strlen(a->q_host) + 1); ! 249: strcpy(p, a->q_host); ! 250: a->q_host = p; ! 251: p = xalloc((unsigned) strlen(a->q_user) + 1); ! 252: strcpy(p, a->q_user); ! 253: a->q_user = p; ! 254: } ! 255: } ! 256: ! 257: /* ! 258: ** Do UPPER->lower case mapping unless inhibited. ! 259: */ ! 260: ! 261: if (!flagset(P_HST_UPPER, t->p_flags)) ! 262: makelower(a->q_host); ! 263: if (!flagset(P_USR_UPPER, t->p_flags)) ! 264: makelower(a->q_user); ! 265: ! 266: /* ! 267: ** Compute return value. ! 268: */ ! 269: ! 270: # ifdef DEBUG ! 271: if (Debug) ! 272: printf("parse(\"%s\"): host \"%s\" user \"%s\" mailer %d\n", ! 273: addr, a->q_host, a->q_user, t->p_mailer); ! 274: # endif DEBUG ! 275: ! 276: return (a); ! 277: } ! 278: /* ! 279: ** MAKELOWER -- Translate a line into lower case ! 280: ** ! 281: ** Parameters: ! 282: ** p -- the string to translate. If NULL, return is ! 283: ** immediate. ! 284: ** ! 285: ** Returns: ! 286: ** none. ! 287: ** ! 288: ** Side Effects: ! 289: ** String pointed to by p is translated to lower case. ! 290: ** ! 291: ** Called By: ! 292: ** parse ! 293: */ ! 294: ! 295: makelower(p) ! 296: register char *p; ! 297: { ! 298: register char c; ! 299: ! 300: if (p == NULL) ! 301: return; ! 302: for (; (c = *p) != '\0'; p++) ! 303: if ((c & 0200) == 0 && isupper(c)) ! 304: *p = c - 'A' + 'a'; ! 305: } ! 306: /* ! 307: ** PRESCAN -- Prescan name and make it canonical ! 308: ** ! 309: ** Scans a name and turns it into canonical form. This involves ! 310: ** deleting blanks, comments (in parentheses), and turning the ! 311: ** word "at" into an at-sign ("@"). The name is copied as this ! 312: ** is done; it is legal to copy a name onto itself, since this ! 313: ** process can only make things smaller. ! 314: ** ! 315: ** This routine knows about quoted strings and angle brackets. ! 316: ** ! 317: ** There are certain subtleties to this routine. The one that ! 318: ** comes to mind now is that backslashes on the ends of names ! 319: ** are silently stripped off; this is intentional. The problem ! 320: ** is that some versions of sndmsg (like at LBL) set the kill ! 321: ** character to something other than @ when reading addresses; ! 322: ** so people type "csvax.eric\@berkeley" -- which screws up the ! 323: ** berknet mailer. ! 324: ** ! 325: ** Parameters: ! 326: ** addr -- the name to chomp. ! 327: ** buf -- the buffer to copy it into. ! 328: ** buflim -- the last usable address in the buffer ! 329: ** (which will old a null byte). Normally ! 330: ** &buf[sizeof buf - 1]. ! 331: ** delim -- the delimiter for the address, normally ! 332: ** '\0' or ','; \0 is accepted in any case. ! 333: ** are moving in place; set buflim to high core. ! 334: ** ! 335: ** Returns: ! 336: ** A pointer to the terminator of buf. ! 337: ** NULL on error. ! 338: ** ! 339: ** Side Effects: ! 340: ** buf gets clobbered. ! 341: ** ! 342: ** Called By: ! 343: ** parse ! 344: ** maketemp ! 345: */ ! 346: ! 347: char * ! 348: prescan(addr, buf, buflim, delim) ! 349: char *addr; ! 350: char *buf; ! 351: char *buflim; ! 352: char delim; ! 353: { ! 354: register char *p; ! 355: bool space; ! 356: bool quotemode; ! 357: bool bslashmode; ! 358: int cmntcnt; ! 359: int brccnt; ! 360: register char c; ! 361: register char *q; ! 362: extern bool any(); ! 363: ! 364: space = TRUE; ! 365: q = buf; ! 366: bslashmode = quotemode = FALSE; ! 367: cmntcnt = brccnt = 0; ! 368: for (p = addr; (c = *p++) != '\0'; ) ! 369: { ! 370: /* chew up special characters */ ! 371: *q = '\0'; ! 372: if (bslashmode) ! 373: { ! 374: c |= 0200; ! 375: bslashmode = FALSE; ! 376: } ! 377: else if (c == '"') ! 378: quotemode = !quotemode; ! 379: else if (c == '\\') ! 380: { ! 381: bslashmode++; ! 382: continue; ! 383: } ! 384: else if (quotemode) ! 385: c |= 0200; ! 386: else if (c == delim) ! 387: break; ! 388: else if (c == '(') ! 389: { ! 390: cmntcnt++; ! 391: continue; ! 392: } ! 393: else if (c == ')') ! 394: { ! 395: if (cmntcnt <= 0) ! 396: { ! 397: usrerr("Unbalanced ')'"); ! 398: return (NULL); ! 399: } ! 400: else ! 401: { ! 402: cmntcnt--; ! 403: continue; ! 404: } ! 405: } ! 406: else if (c == '<') ! 407: { ! 408: brccnt++; ! 409: if (brccnt == 1) ! 410: { ! 411: /* we prefer using machine readable name */ ! 412: q = buf; ! 413: *q = '\0'; ! 414: continue; ! 415: } ! 416: } ! 417: else if (c == '>') ! 418: { ! 419: if (brccnt <= 0) ! 420: { ! 421: usrerr("Unbalanced `>'"); ! 422: return (NULL); ! 423: } ! 424: else ! 425: brccnt--; ! 426: if (brccnt <= 0) ! 427: continue; ! 428: } ! 429: ! 430: /* ! 431: ** Turn "at" into "@", ! 432: ** but only if "at" is a word. ! 433: ** By the way, I violate the ARPANET RFC-733 ! 434: ** standard here, by assuming that 'space' delimits ! 435: ** atoms. I assume that is just a mistake, since ! 436: ** it violates the spirit of the semantics ! 437: ** of the document..... ! 438: */ ! 439: ! 440: if (space && (c == 'a' || c == 'A') && ! 441: (p[0] == 't' || p[0] == 'T') && ! 442: (any(p[1], "()<>@,;:\\\"") || p[1] <= 040)) ! 443: { ! 444: c = '@'; ! 445: p++; ! 446: } ! 447: ! 448: /* skip blanks */ ! 449: if (((c & 0200) != 0 || !isspace(c)) && cmntcnt <= 0) ! 450: { ! 451: if (q >= buflim) ! 452: { ! 453: usrerr("Address too long"); ! 454: return (NULL); ! 455: } ! 456: *q++ = c; ! 457: } ! 458: space = isspace(c); ! 459: } ! 460: *q = '\0'; ! 461: if (c == '\0') ! 462: p--; ! 463: if (cmntcnt > 0) ! 464: usrerr("Unbalanced '('"); ! 465: else if (quotemode) ! 466: usrerr("Unbalanced '\"'"); ! 467: else if (brccnt > 0) ! 468: usrerr("Unbalanced '<'"); ! 469: else if (buf[0] != '\0') ! 470: return (p); ! 471: return (NULL); ! 472: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.