This is smartuser.c in view mode; [Download] [Up]
/* @(#)src/directors/smartuser.c 1.2 24 Oct 1990 05:22:35 */ /* * Copyright (C) 1987, 1988 Ronald S. Karr and Landon Curt Noll * * See the file COPYING, distributed with smail, for restriction * and warranty information. */ /* * smartuser.c: * direct mail to another address. This is useful for directing mail * that did not resolve to a user on the local machine to a user on * a remote machine. * * Specifications for the smartuser directing driver: * * private attribute data: * new_user: (a string) specifies a new address. expand_string() * is used to build the actual address, with the address' * remainder being substituted for $user. * * private attribute flags: * well_formed_only: if set, only match names which contain letters * numbers, `.', `-' and `_'. White spaces and dots are folded * into single occurances of the character `.'. * * NOTE: If no new_user attribute is specified, the smart_user * config file attribute will be used. If neither of these exist, * then the smart_user driver does not match anything. This makes * it possible to have a compiled-in configuration that does not * match anything, while making it possible to enable the smartuser * driver using only a config file. */ #include <stdio.h> #include <pwd.h> #include <grp.h> #include <sys/types.h> #include <sys/stat.h> #include <ctype.h> #include "defs.h" #include "../smail.h" #include "../smailconf.h" #include "../parse.h" #include "../addr.h" #include "../field.h" #include "../log.h" #include "../direct.h" #include "../dys.h" #include "../exitcodes.h" #include "smartuser.h" #ifndef DEPEND # include "../extern.h" # include "../debug.h" # include "../error.h" #endif /* functions local to this file */ static char *make_well_formed(); static char *make_passable(); /* * dtd_smartuser - direct to another address */ /*ARGSUSED*/ struct addr * dtd_smartuser(dp, in, out, new, defer, fail) struct director *dp; /* director entry */ struct addr *in; /* input local-form addrs */ struct addr **out; /* output resolved addrs */ struct addr **new; /* output new addrs to resolve */ struct addr **defer; /* addrs to defer to a later time */ struct addr **fail; /* unresolvable addrs */ { register struct addr *cur; /* temp for processing input */ struct addr *next; /* next value for cur */ struct addr *pass = NULL; /* addrs to pass to next director */ char *error; char *temp; struct smartuser_private *priv = (struct smartuser_private *)dp->private; DEBUG(DBG_DRIVER_HI, "dtd_smartuser called\n"); if (priv->new_user == NULL && smart_user == NULL) { /* there is no smart user information, don't match anything */ return in; } for (cur = in; cur; cur = next) { char *new_user; /* expanded new_user attribute */ char *remainder; /* remainder from addr structure */ struct addr *new_addr; /* new addr structure */ next = cur->succ; if (cur->flags & ADDR_SMARTUSER) { /* do not match addresses which smart_user already rerouted */ cur->succ = pass; pass = cur; continue; } if (dp->flags & SMARTUSER_WELLFORMED) { /* * if required, copy the remainder, making it "well-formed" * in the process */ remainder = make_well_formed(cur->remainder); if (remainder == NULL) { /* not a sufficiently well-formed, pass on the address */ cur->succ = pass; pass = cur; continue; } } else { remainder = make_passable(cur->remainder); } cur->director = dp; /* match anything, at this point */ new_user = expand_string(priv->new_user? priv->new_user: smart_user, (struct addr *)NULL, (char *)NULL, remainder); if (new_user == NULL) { /* * ERR_120 - smartuser expansion failed * * DESCRIPTION * expand_string() failed to expand the new_user attribute * for a smartuser director. * * ACTIONS * Defer the message with a configuration error. * * RESOLUTION * Check the entry in the director file and fix the * new_user attribute. */ cur->error = note_error(ERR_CONFERR|ERR_120, xprintf( "director %s: new_user expansion failed", dp->name)); cur->succ = *defer; *defer = cur; continue; } temp = preparse_address(new_user, &error); if (temp == NULL) { /* * ERR_121 - smartuser parse error * * DESCRIPTION * preparse_address() found an error while parsing the * expanded new_user attribute for a smartuser director. * The actual error was returned in `error'. * * ACTIONS * Defer the message with a configuration error. * * RESOLUTION * Check the entry in the director file and fix the * new_user attribute. */ cur->error = note_error(ERR_CONFERR|ERR_121, xprintf( "director %s: smartuser parse error: %s", dp->name, error)); cur->succ = *defer; *defer = cur; continue; } new_addr = alloc_addr(); new_addr->parent = cur; new_addr->work_addr = temp; new_addr->in_addr = COPY_STRING(new_user); new_addr->flags = ADDR_SMARTUSER; new_addr->succ = *new; *new = new_addr; DEBUG3(DBG_DRIVER_LO, "director %s: matched %s, aliased to %s\n", dp->name, cur->remainder, new_user); } return pass; /* return addrs for next director */ } /* * dtv_smartuser - match just about anything (unless well_formed is set). */ /*ARGSUSED*/ void dtv_smartuser(dp, in, retry, okay, defer, fail) struct director *dp; /* director entry */ struct addr *in; /* input local-form addrs */ struct addr **retry; /* output list of unmatched addrs */ struct addr **okay; /* output list of verified addrs */ struct addr **defer; /* temporariliy unverifiable addrs */ struct addr **fail; /* unverified addrs */ { register struct addr *cur; /* temp for processing input */ struct addr *next; /* next addr to process */ DEBUG(DBG_DRIVER_HI, "dtv_smartuser called\n"); /* loop through all of the input addrs */ for (cur = in; cur; cur = next) { char *remainder; /* remainder from addr structure */ next = cur->succ; if (cur->flags & ADDR_SMARTUSER) { /* do not match addresses which smart_user already rerouted */ cur->succ = *retry; *retry = cur; continue; } if (dp->flags & SMARTUSER_WELLFORMED) { /* * if a well-formed addr is required, make sure it IS * well formed. */ remainder = make_well_formed(cur->remainder); if (remainder == NULL) { /* not a sufficiently well-formed, pass on the address */ cur->succ = *retry; *retry = cur; continue; } } /* we match anything that passes the tests up to this point */ cur->succ = *okay; *okay = cur; } } /* * dtb_smartuser - read the configuration file attributes */ char * dtb_smartuser(dp, attrs) struct director *dp; /* director entry being defined */ struct attribute *attrs; /* list of per-driver attributes */ { char *error; static struct attr_table smartuser_attributes[] = { { "new_user", t_string, NULL, NULL, OFFSET(smartuser_private, new_user) }, { "well_formed_only", t_boolean, NULL, NULL, SMARTUSER_WELLFORMED }, }; static struct attr_table *end_smartuser_attributes = ENDTABLE(smartuser_attributes); static struct smartuser_private smartuser_template = { NULL, /* new_user */ }; struct smartuser_private *priv; /* new smartuser_private structure */ /* copy the template private data */ priv = (struct smartuser_private *)xmalloc(sizeof(*priv)); (void) memcpy((char *)priv, (char *)&smartuser_template, sizeof(*priv)); dp->private = (char *)priv; /* fill in the attributes of the private data */ error = fill_attributes((char *)priv, attrs, &dp->flags, smartuser_attributes, end_smartuser_attributes); if (error) { return error; } else { return NULL; } } /* * make_well_formed - check for well-formedness of a local address * * Check to make sure that characters in the input are in the set of * letters, numbers and the characters `.' and `-'. Also, any set * of 1 or more white space characters and `.' are transformed into * exactly one `.' character. * * returns NULL or a well-formed string. The value returned points * to storage which may be reused on subsequent calls. */ static char * make_well_formed(name) register char *name; /* input string */ { static char *result = NULL; /* region for forming result */ static int result_size; /* allocated region length */ register char *p; /* point to result */ register int c; /* char from name string */ /* get a region at least big enough to store result */ if (result == NULL) { result = xmalloc(result_size = strlen(name) + 1); } else { register int new_size = strlen(name) + 1; if (new_size > result_size) { result = xrealloc(result, new_size); } } /* * copy name to result, performing any necessary transformations. * Stop if any characters are found which would make the input * not well-formed. * * Don't allow it to begin with `-'. */ p = result; if (*name == '-') { return NULL; } while (c = *name++) { if (isalnum(c) || c == '-') { *p++ = c; } else if (isspace(c) || c == '.') { *p++ = '.'; while (isspace(c = *name) || c == '.') { name++; } } else { return NULL; } } *p++ = '\0'; return result; } /* * make_passable - build a legal local-part address string from an input * * given an input string, surround that string in quotes, if required * to make a valid local-part address, according to the RFC822 rules. * If the address is put in quotes, the text within quotes is guarranteed * to be properly \-escaped where required. * * return value may point to storage which can be reused in subsequent * calls. The value should be copied if it is to be retained. */ static char * make_passable(name) char *name; /* input local-part address */ { int need_quotes = FALSE; /* true if we should put in quotes */ int esc_ct = 0; /* count of \'s required */ static char *result = NULL; /* region for building result */ static int result_size; /* size of result region */ int new_size; /* minimum size required */ register char *p; /* temp for building result */ register char *q; /* temp for scanning name */ register int c; /* char from name */ for (q = name; c = *q; q++) { if (isalnum(c)) { continue; } else if (c == '.' || c == '-') { if (q == name || q[1] == '\0' || q[-1] == '.' || q[-1] == '-') { need_quotes = TRUE; } } else { need_quotes = TRUE; if (c == '"' || c == '\\' || !isprint(c)) { esc_ct++; } } } if (need_quotes) { new_size = strlen(name) + esc_ct + sizeof("\"\""); if (result == NULL) { result = xmalloc(result_size = new_size); } else if (result_size < new_size) { result = xrealloc(result, result_size = new_size); } /* copy name to result, inserting \ where appropriate */ p = result; *p++ = '"'; for (q = name; c = *q; q++) { if (c == '"' || c == '\\' || !isprint(c)) { *p++ = '\\'; *p++ = c; } else { *p++ = c; } } *p++ = '"'; *p = '\0'; return result; } return name; /* the original string was fine */ }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.