home *** CD-ROM | disk | FTP | other *** search
/ Beijing Paradise BBS Backup / PARADISE.ISO / software / BBSDOORW / SMAILSRC.ZIP / SMAIL.ZIP / ALIAS.C next >
Encoding:
C/C++ Source or Header  |  1990-05-05  |  11.5 KB  |  603 lines

  1. /*
  2. **  Patched for MS-DOS compatibility by Stephen Trier, March-May, 1990
  3. */
  4.  
  5. #ifndef lint
  6. static char *sccsid = "@(#)alias.c    2.5 (smail) 9/15/87";
  7. #endif
  8.  
  9. #include <stdio.h>
  10. #include <sys/types.h>
  11. #include <sys/stat.h>
  12. #include <pwd.h>
  13. #include "defs.h"
  14. #include <ctype.h>
  15.  
  16. extern enum edebug debug;    /* verbose and debug modes        */
  17. extern char hostdomain[];
  18. extern char hostname[];
  19. extern char *aliasfile;
  20.  
  21. /*
  22. **
  23. ** Picture of the alias graph structure
  24. **
  25. **    head
  26. **       |
  27. **       v
  28. **    maps -> mark -> gjm -> mel -> NNULL
  29. **       |
  30. **       v
  31. **    sys ->  root -> ron -> NNULL
  32. **       |
  33. **       v
  34. **    root -> mark -> chris -> lda -> NNULL
  35. **       |
  36. **       v
  37. **      NNULL
  38. */
  39.  
  40. typedef struct alias_node node;
  41.  
  42. static struct alias_node {
  43.     char *string;
  44.     node *horz;
  45.     node *vert;
  46. };
  47.  
  48. #ifndef SENDMAIL
  49. static node aliases = {"", 0, 0}; /* this is the 'dummy header' */
  50. #endif /* not SENDMAIL */
  51.  
  52. /*
  53. ** lint free forms of NULL
  54. */
  55.  
  56. #define NNULL    ((node   *) 0)
  57. #define CNULL    ('\0')
  58.  
  59. /*
  60. ** string parsing macros
  61. */
  62. #define SKIPWORD(Z)  while(*Z!=' ' && *Z!='\t' && *Z!='\n' && *Z!=',') Z++;
  63. #define SKIPSPACE(Z) while(*Z==' ' || *Z=='\t' || *Z=='\n' || *Z==',') Z++;
  64.  
  65. static int nargc = 0;
  66. static char *nargv[MAXARGS];
  67.  
  68. void    add_horz();
  69. void    load_alias(), strip_comments();
  70. int    recipients();
  71. node    *pop();
  72. #ifndef SENDMAIL
  73. node    *v_search(), *h_search();
  74. char    *tilde();
  75. #endif    /* not SENDMAIL */
  76.  
  77. /* our horizontal linked list looks like a stack */
  78. #define push        add_horz
  79.  
  80. #define escape(s)    ((*s != '\\') ? (s) : (s+1))
  81.  
  82. char **
  83. alias(pargc, argv)
  84. int *pargc;
  85. char **argv;
  86. {
  87. /*
  88. **  alias the addresses
  89. */
  90.     int    i;
  91.     char    domain[SMLBUF], ubuf[SMLBUF], *user;
  92.     node    *addr, addrstk;
  93.     node    *flist,  fliststk, *u;
  94.  
  95. #ifndef SENDMAIL
  96.     FILE    *fp;
  97.     node    *a;
  98.     char    *home, buf[SMLBUF];
  99.     int    aliased;
  100.     struct    stat st;
  101. #endif /* not SENDMAIL */
  102.  
  103. #ifdef FULLNAME
  104.     char *res_fname();    /* Does fullname processing */
  105. #endif
  106.  
  107.     addr  = &addrstk;
  108.     flist = &fliststk;
  109.     user  = ubuf;
  110.  
  111.     addr->horz = NNULL;
  112.     flist->horz  = NNULL;
  113.  
  114.     /*
  115.     ** push all of the addresses onto a stack
  116.     */
  117.     for(i=0; i < *pargc; i++) {
  118.         push(addr, argv[i]);
  119.     }
  120.  
  121.     /*
  122.     ** for each adress, check for included files, aliases,
  123.     ** full name mapping, and .forward files
  124.     */
  125.  
  126.     while((nargc < MAXARGS) && ((u = pop(addr)) != NNULL)) {
  127. #ifndef SENDMAIL
  128.         if(strncmpic(u->string, ":include:", 9) == 0) {
  129.             /*
  130.             ** make sure it's a full path name
  131.             ** don't allow multiple sourcing
  132.             ** of a given include file
  133.             */
  134.             char *p = u->string + 9;
  135.  
  136.             if((*p == '/')
  137.             && (h_search(flist, p) == NULL)) {
  138.                 push(flist, p);
  139.                 if((stat(p, &st) >= 0)
  140.                 &&((st.st_mode & S_IFMT) == S_IFREG)
  141.                 &&((fp = fopen(p, "r")) != NULL)) {
  142.                     while(fgets(buf, sizeof buf, fp)) {
  143.                         (void) recipients(addr, buf);
  144.                     }
  145.                     (void) fclose(fp);
  146.                 }
  147.             }
  148.             continue;
  149.         }
  150. #endif /* not SENDMAIL */
  151.         /*
  152.         ** parse the arg to see if it's to be aliased
  153.         */
  154.  
  155.         if(islocal(u->string, domain, ubuf) == 0) {
  156.             goto aliasing_complete;
  157.         }
  158.  
  159.         /*
  160.         ** local form - try to alias user
  161.         ** aliases file takes precedence over ~user/.forward
  162.         ** since that's the way that sendmail does it.
  163.         */
  164.  
  165. #ifdef LOWERLOGNAME
  166.         /* squish 'user' into lower case */
  167.         for(user = ubuf; *user ; user++) {
  168.             *user = lower(*user);
  169.         }
  170. #endif
  171.         user = escape(ubuf);
  172.  
  173.         (void) strcpy(u->string, user);    /* local => elide domain */
  174. #ifndef SENDMAIL
  175.         /*
  176.         ** check for alias - all this complication is necessary
  177.         ** to handle perverted aliases like these:
  178.         ** # mail to 's' resolves to 't' 'm' and 'rmt!j'
  179.         ** s    t,g,j,m
  180.         ** g    j,m
  181.         ** j    rmt!j
  182.         ** # mail to 'a' resolves to 'rmt!d'
  183.         ** a    b c
  184.         ** b    c
  185.         ** c    rmt!d
  186.         ** # mail to x resolves to 'x'
  187.         ** x    local!x
  188.         ** # mail to 'y' resolves to 'y' and 'z'
  189.         ** y    \y z
  190.         */
  191.         if(((a = v_search(user)) != NNULL)) {
  192.             char dtmpb[SMLBUF], utmpb[SMLBUF], *ut;
  193.             int user_inalias = 0;
  194.             node *t = a;
  195.  
  196.             for(a = a->horz; a != NNULL; a=a->horz) {
  197.                 if(islocal(a->string, dtmpb, utmpb)) {
  198. #ifdef LOWERLOGNAME
  199.                     /* squish 'utmpb' into lower case */
  200.                     for(ut = utmpb; *ut ; ut++) {
  201.                         *ut = lower(*ut);
  202.                     }
  203. #endif
  204.  
  205.                     ut = escape(utmpb);
  206. #ifdef CASEALIAS
  207.                     if(strcmp(ut, user) == 0)
  208. #else
  209.                     if(strcmpic(ut, user) == 0)
  210. #endif
  211.                     {
  212.                         user_inalias = 1;
  213.                     } else {
  214.                         push(addr, a->string);
  215.                     }
  216.                 } else {
  217.                     push(addr, a->string);
  218.                 }
  219.             }
  220.             t->horz = NNULL; /* truncate horz list of aliases */
  221.             if(user_inalias == 0) {
  222.                 continue;
  223.             }
  224.         }
  225.  
  226.         if((home = tilde(user)) != NULL) {
  227.             /* don't allow multiple sourcing
  228.             ** of a given .forward file
  229.             */
  230.  
  231.             if((h_search(flist, home) != NULL)) {
  232.                 continue;
  233.             }
  234.             push(flist, home);
  235.  
  236.             /*
  237.             ** check for ~user/.forward file
  238.             ** must be a regular, readable file
  239.             */
  240.  
  241. #ifndef MSDOS   /* Change by SCT */
  242.             (void) sprintf(buf, "%s/%s", home, ".forward");
  243. #else
  244.             (void) sprintf(buf, "%s/%s", home, "forward");
  245. #endif /* MSDOS */
  246.             if((stat(buf, &st) >= 0)
  247.             &&((st.st_mode & S_IFMT) == S_IFREG)
  248. #ifndef MSDOS
  249.             &&((st.st_mode & 0444)   == 0444)
  250. #endif
  251.             &&((fp = fopen(buf, "r")) != NULL)) {
  252.                 aliased = 0;
  253.                 while(fgets(buf, sizeof buf, fp)) {
  254.                     aliased |= recipients(addr, buf);
  255.                 }
  256.                 (void) fclose(fp);
  257.                 if(aliased) {
  258.                     continue;
  259.                 }
  260.             }
  261.         }
  262. #endif /* not SENDMAIL */
  263.  
  264. #ifdef FULLNAME
  265.         /*
  266.         ** Do possible fullname substitution.
  267.         */
  268. #ifdef DOT_REQD
  269.         if (index(user, '.') != NULL)
  270. #endif
  271.         {
  272.             static char t_dom[SMLBUF], t_unam[SMLBUF];
  273.             char *t_user = res_fname(user);
  274.             if (t_user != NULL) {
  275.                 if(islocal(t_user, t_dom, t_unam) == 0) {
  276.                     /* aliased to non-local address */
  277.                     push(addr, t_user);
  278.                     continue;
  279.                 }
  280.                 if(strcmp(t_unam, user) != 0) {
  281.                     /* aliased to different local address */
  282.                     push(addr, t_unam);
  283.                     continue;
  284.                 }
  285.             }
  286.         }
  287. #endif
  288.  
  289. aliasing_complete:
  290.         user = escape(u->string);
  291.         for(i=0; i < nargc; i++) {
  292.             if(strcmpic(nargv[i], user) == 0) {
  293.                 break;
  294.             }
  295.         }
  296.  
  297.         if(i == nargc) {
  298.             nargv[nargc++] = user;
  299.         }
  300.     }
  301.     *pargc     = nargc;
  302.     return(nargv);
  303. }
  304.  
  305. #ifndef SENDMAIL
  306. /*
  307. ** v_search
  308. **    given an string, look for its alias in
  309. **    the 'vertical' linked list of aliases.
  310. */
  311. node *
  312. v_search(user)
  313. char *user;
  314. {
  315.     node *head;
  316.     node *a;
  317.     static int loaded = 0;
  318.  
  319.     head = &aliases;
  320.     if(loaded == 0) {
  321.         load_alias(head, aliasfile);
  322.         loaded = 1;
  323.     }
  324.  
  325.     for(a = head->vert; a != NNULL; a = a->vert) {
  326. #ifdef CASEALIAS
  327.         if(strcmp(a->string, user) == 0)
  328. #else
  329.         if(strcmpic(a->string, user) == 0)
  330. #endif
  331.         {
  332.             break;
  333.         }
  334.     }
  335.     if(a == NNULL) {        /* not in graph */
  336.         return(NNULL);
  337.     }
  338.     return(a);
  339. }
  340.  
  341. /*
  342. ** h_search
  343. **    given an string, look for it in
  344. **    a 'horizontal' linked list of strings.
  345. */
  346. node *
  347. h_search(head, str)
  348. node *head;
  349. char *str;
  350. {
  351.     node *a;
  352.     for(a = head->horz; a != NNULL; a = a->horz) {
  353. #ifdef CASEALIAS
  354.         if(strcmp(a->string, str) == 0)
  355. #else
  356.         if(strcmpic(a->string, str) == 0)
  357. #endif
  358.         {
  359.             break;
  360.         }
  361.     }
  362.     return(a);
  363. }
  364. #endif /* not SENDMAIL */
  365.  
  366. /*
  367. ** load_alias
  368. **    parse an 'aliases' file and add the aliases to the alias graph.
  369. **    Handle inclusion of other 'aliases' files.
  370. */
  371.  
  372. void
  373. load_alias(head, filename)
  374. node *head;
  375. char *filename;
  376. {
  377.     FILE *fp;
  378.     node *v, *h, *add_vert();
  379.     char domain[SMLBUF], user[SMLBUF];
  380.     char *p, *b, buf[SMLBUF];
  381.  
  382.     if((fp = fopen(filename,"r")) == NULL) {
  383. DEBUG("load_alias open('%s') failed\n", filename);
  384.         return;
  385.     }
  386.  
  387.     while(fgets(buf, sizeof buf, fp) != NULL) {
  388.         p = buf;
  389.         if((*p == '#') || (*p == '\n')) {
  390.             continue;
  391.         }
  392.  
  393.         /*
  394.         ** include another file of aliases
  395.         */
  396.  
  397.         if(strncmp(p, ":include:", 9) == 0) {
  398.             char *nl;
  399.             p += 9;
  400.             if((nl = index(p, '\n')) != NULL) {
  401.                 *nl = CNULL;
  402.             }
  403. DEBUG("load_alias '%s' includes file '%s'\n", filename, p);
  404.             load_alias(head, p);
  405.             continue;
  406.         }
  407.  
  408.         /*
  409.         **  if the first char on the line is a space or tab
  410.         **  then it's a continuation line.  Otherwise,
  411.         **  we start a new alias.
  412.         */
  413.         if(*p != ' ' && *p != '\t') {
  414.             b = p;
  415.             SKIPWORD(p);
  416.             *p++ = CNULL;
  417.             /*
  418.             ** be sure that the alias is in local form
  419.             */
  420.             if(islocal(b, domain, user) == 0) {
  421.                 /*
  422.                 ** non-local alias format - skip it
  423.                 */
  424.                 continue;
  425.             }
  426.             /*
  427.             ** add the alias to the (vertical) list of aliases
  428.             */
  429.             if((h = add_vert(head, user)) == NNULL) {
  430. DEBUG("load_alias for '%s' failed\n", b);
  431.                 return;
  432.             }
  433.         }
  434.         /*
  435.         **  Next on the line is the list of recipents.
  436.         **  Strip out each word and add it to the
  437.         **  horizontal linked list.
  438.         */
  439.         (void) recipients(h, p);
  440.     }
  441.     (void) fclose(fp);
  442.     /*
  443.     ** strip out aliases which have no members
  444.     */
  445.     for(v = head; v->vert != NNULL; ) {
  446.         if(v->vert->horz == NNULL) {
  447.             v->vert = v->vert->vert;
  448.         } else {
  449.             v = v->vert;
  450.         }
  451.     }
  452. }
  453.  
  454. /*
  455. ** add each word in a string (*p) of recipients
  456. ** to the (horizontal) linked list associated with 'h'
  457. */
  458.  
  459. recipients(h, p)
  460. node *h;
  461. char *p;
  462. {
  463.  
  464.     char *b, d[SMLBUF], u[SMLBUF];
  465.     int ret = 0;
  466.  
  467.     strip_comments(p);    /* strip out stuff in ()'s */
  468.  
  469.     SKIPSPACE(p);        /* skip leading whitespace on line */
  470.  
  471.     while((*p != NULL) && (*p != '#')) {
  472.         b = p;
  473.         if(*b == '"') {
  474.             if((p = index(++b, '"')) == NULL) {
  475.                 /* syntax error - no matching quote */
  476.                 /* skip the rest of the line */
  477.                 return(ret);
  478.             }
  479.         } else {
  480.             SKIPWORD(p);
  481.         }
  482.  
  483.         if(*p != CNULL) {
  484.             *p++ = CNULL;
  485.         }
  486.  
  487.         /* don't allow aliases of the form
  488.         ** a    a
  489.         */
  490.         if((islocal(b, d, u) == 0)
  491.         || (strcmpic(h->string, u) != 0)) {
  492.             add_horz(h, b);
  493.             ret = 1;
  494.         }
  495.         SKIPSPACE(p);
  496.     }
  497.     return(ret);
  498. }
  499.  
  500. /*
  501. ** some aliases may have comments on the line like:
  502. **
  503. ** moderators    moderator@somehost.domain    (Moderator's Name)
  504. **        moderator@anotherhost.domain    (Another Moderator's Name)
  505. **
  506. ** strip out the stuff in ()'s
  507. **
  508. */
  509.  
  510. void
  511. strip_comments(p)
  512. char *p;
  513. {
  514.     char *b;
  515.     while((p = index(p, '(')) != NULL) {
  516.         b = p++;    /*
  517.                 ** save pointer to open parenthesis
  518.                 */
  519.         if((p = index(p, ')')) != NULL) {/* look for close paren */
  520.             (void) strcpy(b, ++p);     /* slide string left    */
  521.         } else {
  522.             *b = CNULL;    /* no paren, skip rest of line  */
  523.             break;
  524.         }
  525.     }
  526. }
  527.  
  528. /*
  529. ** add_vert - add a (vertical) link to the chain of aliases.
  530. */
  531.  
  532. node *
  533. add_vert(head, str)
  534. node *head;
  535. char *str;
  536. {
  537.     char *p, *malloc();
  538.     void free();
  539.     node *new;
  540.  
  541.     /*
  542.     ** strip colons off the end of alias names
  543.     */
  544.     if((p = index(str, ':')) != NULL) {
  545.         *p = CNULL;
  546.     }
  547.     if((new = (node *) malloc(sizeof(node))) != NNULL) {
  548.         if((new->string = malloc((unsigned) strlen(str)+1)) == NULL) {
  549.             free(new);
  550.             new = NNULL;
  551.         } else {
  552.             (void) strcpy(new->string, str);
  553.             new->vert   = head->vert;
  554.             new->horz   = NNULL;
  555.             head->vert  = new;
  556. /*DEBUG("add_vert %s->%s\n", head->string, new->string);/* */
  557.         }
  558.     }
  559.     return(new);
  560. }
  561.  
  562. /*
  563. ** add_horz - add a (horizontal) link to the chain of recipients.
  564. */
  565.  
  566. void
  567. add_horz(head, str)
  568. node *head;
  569. char *str;
  570. {
  571.     char *malloc();
  572.     node *new;
  573.  
  574.     if((new = (node *) malloc(sizeof(node))) != NNULL) {
  575.         if((new->string = malloc((unsigned) strlen(str)+1)) == NULL) {
  576.             free(new);
  577.             new = NNULL;
  578.         } else {
  579.             (void) strcpy(new->string, str);
  580.             new->horz  = head->horz;
  581.             new->vert  = NNULL;
  582.             head->horz = new;
  583.         }
  584. /*DEBUG("add_horz %s->%s\n", head->string, new->string);/* */
  585.     }
  586. }
  587.  
  588. node *
  589. pop(head)
  590. node *head;
  591. {
  592.     node *ret = NNULL;
  593.  
  594.  
  595.     if(head != NNULL) {
  596.         ret = head->horz;
  597.         if(ret != NNULL) {
  598.             head->horz = ret->horz;
  599.         }
  600.     }
  601.     return(ret);
  602. }
  603.