# /* str_util.c * * This file contains the various string-handling utilities required * by the mail daemon. The following routines are included: * get_names get the user and host names from request file * scan_string parse a string into tokens and separators * min_ix_in_string find a substring in a string * local_host determine if a given host name is ours * tftp_host determine if a given host has tftp mail * smtp_host determine if a given host has smtp mail * gettmp get a temporary file name * ext get extension from a filename * lwccmp compare two strings ignoring case * itos convert an integer to a string */ #include "rqfile.h" #include "extern.h" #include get_names (from, hname, uname) /* Scan the string from from left, splitting it into * substrings separated by the separator strings in separators. * Scan until the current substring is our hostname, or * until end-of-string. Then the previous substring is the destination * host (in hname), and the concatenation of the substrings previous * to it are the destination user (in uname). * * Arguments: */ char *from; /* string containing names */ char *hname; /* destination host name */ register char *uname; /* destination user name */ { register char *nextp; /* ptr. to next substr. */ char *prevp; /* ptr. to previous substr */ char *curp; /* ptr. to current substr */ register char *hp; /* temp. ptr to start of hname */ char temp[NAMSIZ]; /* temp for local name test */ strcpy (hname, myhost[0]); prevp = 0; hp = nextp = scan_string (from, uname, separators); while (*nextp != '\0') { curp = scan_string (nextp, temp, separators); if (local_host (temp)) break; prevp = nextp; nextp = curp; strcpy (hname, temp); } if (prevp != 0) { while (*uname != '\0') uname++; /* find end of user name */ while (hp != prevp) *uname++ = *hp++; *uname = 0; } } char *scan_string (str, substr, separators) /* First, skip over any separator characters at the start of the string * pointed to by str. Then scan the string from str until you find * a separator or end-of-string, and copy the substring from the start * of the string up to the separator to substr. Return a pointer to the * start of the separator (or end-of-string if none). * * Arguments: */ register char *str; /* start of string to be scanned */ register char *substr; /* place to put substring */ char **separators; /* array of possible separators */ { register char *p; /* temp ptr. */ int sep_ix; /* index of sep. found in sep. array */ *substr = '\0'; /* return null substr. on failure */ if (*str == '\0') /* passed null string? */ return (str); if ((p = min_ix_in_str (str, separators, &sep_ix)) == str) { str += strlen (separators[sep_ix]); p = min_ix_in_str (str, separators, &sep_ix); } while (str != p) *substr++ = *str++; *substr = '\0'; return (p); } char *min_ix_in_str (str, seps, psepix) /* Find the minimum position in the string str occupied by one of * the separator strings in the array seps., and return a pointer * to that position. If none of the separator strings occur in * the string, return a pointer to the end of the string. * Also, set sepix to the index in the seps array of the separator * string found. * * Arguments: */ register char *str; /* string to be searched */ char *seps[]; /* array of separator strings */ int *psepix; /* ptr. to return ix. of sep. */ { register char *p; /* temp. ptr. */ register char *q; /* temp. ptr. */ register int i; /* index of next sep. string */ while (*str != '\0') { for (i = 0; seps[i] != 0; i++) { if (seps[i][0] != *str) /* nope; try next sep. */ continue; for (p = str + 1, q = seps[i] + 1; *q != '\0' && *p == *q; p++, q++) ; if (*q == '\0') { /* found one; return it */ *psepix = i; return (str); } } /* didn't; try next separator */ str++; /* try next position in string */ } return (str); /* didn' find a separator */ } local_host (hname) /* Determine whether the specified host name is ours, by looking it * up in the local host table. * * Arguments: */ char *hname; /* host name string */ { return (binsrch (&hname, myhost, myhsiz, sizeof (myhost[0]), &lwccmp) != -1); } tftp_host (hname) /* This routine determines whether the specified host has a TFTP * mailer handler (by looking it up in a host table). It returns * TRUE if so. * * Arguments: */ char *hname; /* name of destination host */ { return (binsrch (&hname, tftp_htab, tfhsiz, sizeof (tftp_htab[0]), &lwccmp) != -1); } smtp_host (hname) /* This routine determines whether the specified host has an SMTP * mailer handler (by looking it up in a host table). It returns * TRUE if so. * * Arguments: */ char *hname; /* name of destination host */ { return (binsrch (&hname, smtp_htab, smhsiz, sizeof (smtp_htab[0]), &lwccmp) != -1); } gettmp (tmpnam) /* This routine determines a unique file name for a request file * and returns it in tmpnam. The filename selected is of the * form "/maild/XXXX.req" where XXXX is a unique value. * The routine checks that the name is unique; if not, * the value is incremented and checked again. * * Arguments: */ char *tmpnam; /* place to put file name */ { char cpid[10]; /* char version of unique val */ struct inode buf; /* temp buf for stat call */ do { strcpy (tmpnam, maildir); strcat (tmpnam, "/"); itos (cpid, rewnam, 10); strcat (tmpnam, cpid); strcat (tmpnam, "."); strcat (tmpnam, rqext); rewnam++; } while (stat (tmpnam, &buf) != -1); } char *ext (fname) /* This program returns a string containing the "extension" of the * specified filename. The extension is defined as the string of * characters following the last '.' in the filename. * Caution: since this routine runs as the inner loop of the program, * it is coded for efficiency and may be hard to understand. * * Returns: * string containing the extension, or 0 if none * * Arguments: */ register char *fname; /* file name */ { register int extn; for (extn = 0; *fname != 0; ) if (*fname++ == '.') extn = fname; return (extn); } #define tolower(c) ((c) >= 'A' && (c) <= 'Z' ? (c) + 'a' - 'A' : (c)) lwccmp (s1, s2) /* Compare two strings ignoring case considerations. ARGUMENTS ARE POINTERS * TO THE STRINGS (IE char **) NOT THE STRINGS THEMSELVES. This is so * lwccmp can be used in quicksorts and binary searches. * Returns: * <0 if s1 < s2 * =0 if s1 = s2 * >0 if s1 > s2 * * Arguments: */ char **s1; /* ptr. to first string */ char **s2; /* ptr. to second string */ { register char *p1; /* first string */ register char *p2; /* second string */ p1 = *s1; p2 = *s2; while (*p1 == *p2 || (tolower (*p1) == tolower (*p2))) { if (*p1++ == '\0') return (0); else p2++; } return (tolower (*p1) - tolower (*p2)); } /* itos (ps, n, b) * * Converts its integer numeric argument n into an ASCII string in the * space pointed to by ps, according to the base b. */ char *itos (ps, n, b) register char *ps; int n, b; { register int a; if ((a = n / b) != 0) ps = itos (ps, a, b); a = n % b; *ps++ = a + (a > 9 ? 'A' - 10 : '0'); *ps = '\0'; return (ps); }