home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-05-06 | 53.9 KB | 1,763 lines |
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then feed it
- # into a shell via "sh file" or similar. To overwrite existing files,
- # type "sh file -c".
- # The tool that generated this appeared in the comp.sources.unix newsgroup;
- # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
- # If this archive is complete, you will see the following message at the end:
- # "End of archive 7 (of 19)."
- # Contents: mush/addrs.c mush/viewopts.c
- # Wrapped by argv@turnpike on Wed May 2 13:59:26 1990
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'mush/addrs.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'mush/addrs.c'\"
- else
- echo shar: Extracting \"'mush/addrs.c'\" \(33359 characters\)
- sed "s/^X//" >'mush/addrs.c' <<'END_OF_FILE'
- X/* addrs.c -- copyright (c) Dan Heller 1/25/1989 */
- X
- X#include "mush.h"
- X
- X/*
- X * Check to see if all addressees in list1 is in list2.
- X * The lists must be as clean as the driven snow (no comments, aliases
- X * must have been expanded, all are separated by whitespace (for mk_argv).
- X *
- X * "user" matches "user" and "user@localhost"
- X * "*user" matches "user" at any address whatsoever."
- X * !host matches any user destined for the specified host.
- X * !some!path is the same, but can be more specifiec in the path.
- X * @dom.ain can match any user destined for any host within the domain.
- X * @berkeley.edu would match: dheller@cory.berkeley.edu
- X */
- Xcompare_addrs(list1, list2, ret_buf)
- Xchar *list1, *list2, ret_buf[];
- X{
- X register char *p;
- X char **addrv, **listv, buf[256]; /* addrs aren't long */
- X int addrc, listc, a, l, h, ret_val;
- X
- X /* autosign2 list contains non-comment addresses */
- X listv = mk_argv(list1, &listc, FALSE);
- X addrv = mk_argv(list2, &addrc, FALSE);
- X
- X /* loop thru both lists and convert addresses to !-format
- X * then remove ourhost names so "user" matches "user!local"
- X * also remove possible trailing commas (from list).
- X */
- X for (a = 0; a < addrc; a++) {
- X if (a != addrc-1 && (p = index(addrv[a], ',')) && !p[1])
- X *p = 0;
- X if (addrv[a][0] == '!' || addrv[a][0] == '@')
- X continue;
- X (void) bang_form(buf, addrv[a]);
- X if (strcmp(addrv[a], buf)) /* if they differ... */
- X (void) strcpy(addrv[a], buf); /* save new version */
- X }
- X for (l = 0; l < listc; l++) {
- X if (l != listc-1 && (p = index(listv[l], ',')) && !p[1])
- X *p = 0;
- X if (listv[l][0] == '!' || listv[l][0] == '@')
- X continue;
- X (void) bang_form(buf, listv[l]);
- X if (strcmp(listv[l], buf)) /* if they differ... */
- X (void) strdup(listv[l], buf); /* save new version */
- X }
- X
- X Debug("\nlist1 = "), print_argv(listv);
- X Debug("list2 = "), print_argv(addrv), putchar('\n');
- X
- X /* loop thru each list comparing each element with the
- X * other, if necessary.
- X */
- X for (l = 0; l < listc; l++) {
- X ret_val = 0;
- X /* check if local recipient with was specified. */
- X if (!(p = rindex(listv[l], '!')))
- X for (a = 0; a < addrc; a++) {
- X /* we have a local user so far. If addrv[] is
- X * not remote, then strcmp() immediately.
- X * Note that "!" with no host indicates *all*
- X * local users!!!
- X */
- X if (addrv[a][0] == '*') {
- X /* "*user" == "user" or "*" == login */
- X if (!addrv[a][1] && !lcase_strncmp(listv[l], login, -1) ||
- X !lcase_strncmp(listv[l], addrv[a]+1, -1))
- X ret_val = 1;
- X } else if (addrv[a][0] != '!') {
- X if (!lcase_strncmp(addrv[a], listv[l], -1) || !addrv[a][1])
- X ret_val = 1;
- X } else for (h = 0; ourname && ourname[h]; h++)
- X if (!lcase_strncmp(addrv[a]+1, ourname[h], -1)) {
- X ret_val = 1;
- X break;
- X }
- X if (ret_val)
- X break;
- X }
- X /* else this is a remote user */
- X else {
- X /* check all the addresses for @dom.ain stuff or
- X * !path!name type stuff only.
- X */
- X /* first back up p to the previous '!' */
- X char *start, *user = p + 1;
- X while (p > listv[l] && *--p != '!')
- X ;
- X start = p; /* Where to start for _domain_ addrs */
- X for (a = 0; a < addrc; a++) {
- X int len;
- X char *path;
- X
- X /* first check the cases of address unmodified by @ and !
- X * or check to see if *user is specified.
- X */
- X if (addrv[a][0] != '@' && addrv[a][0] != '!') {
- X if (addrv[a][0] == '*') {
- X /* we saved the username at "user" declaration. */
- X /* if "*" is by itself, check against user's login */
- X if (!addrv[a][1] && !lcase_strncmp(user, login, -1) ||
- X addrv[a][1] && !lcase_strncmp(user,addrv[a]+1,-1)){
- X ret_val = 1;
- X break;
- X }
- X } else if (!lcase_strncmp(addrv[a], listv[l], -1)) {
- X ret_val = 1;
- X break;
- X }
- X continue;
- X }
- X path = addrv[a]+1;
- X while (addrv[a][0] == '@' && *path == '.')
- X path++;
- X if ((len = strlen(path)) == 0)
- X continue; /* localhost stuff only -- can't match */
- X /* first check against specified domains */
- X if (addrv[a][0] == '@') {
- X for (p = start; p; (p = index(p, '.')) && ++p)
- X if (!lcase_strncmp(p, path, len) &&
- X (p[len] == '.' || p[len] == 0 || p[len] == '!')) {
- X ret_val = 1;
- X break;
- X }
- X } else if (addrv[a][0] == '!') {
- X /* for !path style, start at head of addr */
- X for (p = listv[l]; p; (p = index(p, '!')) && ++p)
- X if (!lcase_strncmp(p, path, len) &&
- X (p[len] == '!' || p[len] == 0)) {
- X ret_val = 1;
- X break;
- X }
- X }
- X /* If address is in autosign2, goto next addr */
- X if (ret_val)
- X break;
- X }
- X }
- X if (!ret_val) {
- X /* this address isn't in autosign2 list */
- X if (ret_buf)
- X (void) strcpy(ret_buf, listv[l]);
- X break;
- X }
- X }
- X free_vec(listv);
- X free_vec(addrv);
- X
- X return ret_val;
- X}
- X
- X/*
- X * Parser for stupidly-formed RFC822 addresses. It has been tested on
- X * several bizzare cases as well as the normal stuff and uucp paths. It
- X * takes a string which is a bunch of addresses and unscrambles the first
- X * one in the string. It returns a pointer to the first char past what it
- X * unscrambled and copies the unscrambled address to its second argument.
- X *
- X * It does NOT deal with trailing (comment) strings --
- X * <whoever@somewhere> (This is a comment)
- X * ^unscramble_addr return points here
- X *
- X * It also does not deal well with malformed <addresses> --
- X * <whoever@somewhere,nowhere>
- X * ^unscramble_addr return points here
- X *
- X * In each of the above cases, the string "whoever@somewhere" is copied
- X * to the second argument.
- X *
- X * Nothing is done to un-<>ed route-less RFC822/976 addresses, nor to
- X * uucp paths, nor to mixed-mode addresses not containing a route.
- X * Hopelessly scrambled addresses are not handled brilliantly --
- X * @some.dumb.place,@any.other.place:sys2!user%sys3@sys1
- X * parses to
- X * sys2!user%sys3@sys1
- X * i.e., the route is simply dropped.
- X *
- X * If UUCP is defined, a little more work is done with @: routes. The
- X * mangled address given above will unwind to
- X * some.dumb.place!any.other.place!sys1!sys2!sys3!user
- X * thanks to intelligence in bang_form().
- X */
- Xchar *
- Xunscramble_addr(addr, naddr)
- Xchar *addr;
- Xchar *naddr;
- X{
- X char *i, *r, *at;
- X char s[BUFSIZ], t[BUFSIZ];
- X int anglebrace = 0;
- X
- X /* Make a copy of the address so we can mangle it freely. */
- X if (addr && *addr) {
- X /* Skip any leading whitespace. */
- X for (i = addr; *i && (r = any(i, " \t")) == i;)
- X if (r)
- X i = r + 1;
- X if (*i == '\0')
- X return NULL;
- X /* Skip any leading double-quoted comment. */
- X if (*i == '"') {
- X if ((i = index(i + 1, '"')) && (*i == '\0' || *(++i) == '\0'))
- X return NULL;
- X }
- X /* Skip any more whitespace. */
- X for (; *i && (r = any(i, " \t")) == i;)
- X if (r)
- X i = r + 1;
- X if (*i == '\0')
- X return NULL;
- X /* Check for angle braces around the address. */
- X if (*i == '<') {
- X if (*(++i) == '\0')
- X return NULL;
- X ++anglebrace;
- X }
- X /*
- X * Look for a route. A route is a comma-separated set of @-tagged
- X * domains terminated by a colon. Later versions might try to use
- X * the route, but for now it confuses too many mailers.
- X */
- X if ((*i == '@') && (r = any(i, " \t:"))) {
- X if (*r != ':')
- X return NULL;
- X if (*(r + 1) == '\0')
- X return NULL;
- X#ifndef UUCP
- X /*
- X * Back up to the rightmost @-tagged domain
- X * (see note below about unwinding)
- X */
- X *r = '\0';
- X i = rindex(i, '@');
- X *r = ':';
- X#endif /* !UUCP */
- X }
- X /* Remember how much we've skipped, and copy the rest. */
- X at = i;
- X (void) strncpy(t, i, sizeof t);
- X t[sizeof t - 1] = 0;
- X /* Strip from a trailing angle brace, if present. */
- X if (anglebrace) {
- X if (r = any(t, "> \t")) {
- X if (r == t || *r != '>')
- X return NULL;
- X else
- X *r = '\0';
- X --anglebrace;
- X } else
- X return NULL;
- X }
- X if (t[0] == '@') {
- X /* Chop off any invalid stuff after the address. */
- X if (r = any(index(t, ':'), " \t,(<"))
- X *r = '\0';
- X }
- X } else
- X return NULL;
- X /* Remember where we are so we can return it. */
- X at += strlen(t) + 1;
- X /*
- X * Unscramble the route, if present.
- X * NOTE: We assume that a route is present in only two cases:
- X * 1) addr was taken from the "From " line of a stupid mailer
- X * 2) addr was a well-formed, <> enclosed RFC822 address
- X */
- X if (t[0] == '@') {
- X#ifdef UUCP
- X if (!bang_form(s, t))
- X return NULL;
- X#else /* UUCP */
- X if (r = index(t, ':'))
- X r++;
- X else
- X return NULL;
- X /* Delete the route if extraneous, otherwise unwind it. */
- X if (i = index(r, '@'))
- X (void) strcpy(s, r);
- X else {
- X /*
- X * NOTE: Unwinding currently uses only the rightmost domain
- X * in the route. This will break for mailers that need the
- X * entire route. Complete unwinding would require the use
- X * of % characters, which are avoided for other reasons.
- X */
- X (void) strcpy(s, r);
- X *(--r) = '\0';
- X (void) strcat(s, t);
- X }
- X#endif /* UUCP */
- X } else
- X (void) strcpy(s, t);
- X /*
- X * Ok, now the address should be in the form user@domain and
- X * is held in buffer s (t[] is not copied directly to naddr
- X * to allow future additional processing to be added here).
- X */
- X if (debug > 1) /* Don't dump this on trivial debugging */
- X wprint("Converting \"%s\" to \"%s\"\n", addr, s);
- X (void) strcpy(naddr, s);
- X return at;
- X}
- X
- X/*
- X * Convert RFC822 or mixed addresses to RFC976 `!' form,
- X * copying the new address to d. The source address is
- X * translated according to RFC822 rules.
- X * Return a pointer to the end (nul terminus) of d.
- X */
- Xchar *
- Xbang_form (d, s)
- Xchar *d, *s;
- X{
- X char *r, *t, *ab = NULL;
- X
- X *d = '\0';
- X /* If nothing to do, quit now */
- X if (!s || !*s) {
- X return d;
- X }
- X /* Avoid any angle braces */
- X if (*s == '<') {
- X if (ab = index(s + 1, '>'))
- X s++, *ab = '\0';
- X else
- X return NULL;
- X }
- X /*
- X * Look backwards for the first `@'; this gives us the
- X * primary domain of the RFC822 address
- X */
- X if (*s == '@') {
- X /* An RFC-822 "@domain1,@domain2:" routing */
- X if (t = any(++s, ",:")) {
- X char c = *t;
- X *t = '\0';
- X d += Strcpy(d, s);
- X *d++ = '!';
- X *t++ = c;
- X r = bang_form(d, t);
- X } else
- X r = NULL;
- X } else if ((t = rindex(s, '@')) && t != s) {
- X /* Copy the RFC822 domain as the UUCP head */
- X d += Strcpy(d, t + 1);
- X *d++ = '!';
- X *t = '\0';
- X r = bang_form(d, s);
- X *t = '@';
- X } else if (t = index(s, '!')) {
- X /* A normal UUCP path */
- X *t = '\0';
- X d += Strcpy(d, s);
- X *t++ = *d++ = '!';
- X r = bang_form(d, t);
- X } else if (t = rindex(s, '%')) {
- X /* An imbedded `%' -- treat as low-priority `@' */
- X *t = '@';
- X r = bang_form(d, s);
- X *t = '%';
- X } else
- X r = d + Strcpy(d, s); /* No `@', `!', or `%' */
- X if (ab)
- X *ab = '>';
- X return r;
- X}
- X
- X/*
- X * Route addresses according to certain criteria. This function is really
- X * just a front end for improve_uucp_paths() which does routing (differently).
- X * If "route" is null, this routine is being called incorrectly.
- X * If route is an address, just call improve_uucp_paths() and return.
- X * If route is the null string, then route all addresses via the sender's
- X * which is the first name/address on the To: list. If he's on a remote
- X * machine, chances are that the addresses of everyone else he mailed to
- X * are addresses from his machine. Reconstruct those addresses to route
- X * thru the senders machine first.
- X */
- Xroute_addresses(to, cc, route_path)
- Xchar *to, *cc, *route_path;
- X{
- X char pre_path[256], sender[HDRSIZ], tmp[256];
- X register char *next, *p;
- X int c;
- X
- X Debug("route_addresses()\n");
- X if (!route_path)
- X return;
- X if (*route_path) {
- X improve_uucp_paths(to, HDRSIZ, route_path);
- X improve_uucp_paths(cc, HDRSIZ, route_path);
- X return;
- X }
- X
- X pre_path[0] = 0;
- X /* Get the address of the sender (which is always listed first) */
- X if (!(next = get_name_n_addr(to, NULL, NULL)))
- X return;
- X c = *next, *next = 0;
- X (void) strcpy(sender, to);
- X *next = c;
- X /* fix up the sender's address; improve_uucp_paths to optimize pre_path */
- X improve_uucp_paths(sender, sizeof sender, NULL);
- X
- X /* check to see if there is only one addr on To: line and no Cc: header */
- X if (!*next && (!cc || !*cc)) {
- X (void) strcpy(to, sender);
- X return;
- X }
- X /* otherwise, get the pre_path */
- X if (p = get_name_n_addr(sender, NULL, tmp))
- X c = p - sender; /* save the original length */
- X if (*tmp) {
- X (void) bang_form(pre_path, tmp);
- X if (p = rindex(pre_path, '!')) {
- X *p = 0;
- X Debug("Routing thru \"%s\"\n", pre_path);
- X } else
- X pre_path[0] = 0;
- X } else
- X pre_path[0] = 0;
- X
- X while (*next == ',' || isspace(*next))
- X next++;
- X improve_uucp_paths(next, HDRSIZ - (int)(next - to), pre_path);
- X improve_uucp_paths(cc, HDRSIZ, pre_path);
- X p = sender + c;
- X *p++ = ',', *p++ = ' ';
- X (void) strcpy(p, next);
- X (void) strcpy(to, sender);
- X}
- X
- X/*
- X * pass a string describing header like, "Subject: ", current value, and
- X * whether or not to prompt for it or to just post the information.
- X * If do_prompt is true, "type in" the current value so user can either
- X * modify it, erase it, or add to it.
- X */
- Xchar *
- Xset_header(str, curstr, do_prompt)
- Xregister char *str, *curstr;
- X{
- X static char buf[HDRSIZ];
- X int offset = 0;
- X register char *p = curstr;
- X
- X if (!str)
- X str = "";
- X
- X buf[0] = 0;
- X print(str);
- X (void) fflush(stdout); /* force str curstr */
- X if (do_prompt) {
- X if (curstr)
- X if (isoff(glob_flags, ECHO_FLAG)) {
- X Ungetstr(curstr);
- X } else
- X#ifdef TIOCSTI
- X for (p = curstr; *p; p++)
- X if (ioctl(0, TIOCSTI, p) == -1) {
- X error("ioctl: TIOCSTI");
- X print("You must retype the entire line.\n%s", str);
- X break;
- X }
- X#else /* !TIOCSTI */
- X print("WARNING: -e flag! Type the line over.\n%s", str);
- X#endif /* TIOCSTI */
- X
- X if (istool)
- X return NULL;
- X /* simulate the fact that we're getting input for the letter even tho
- X * we may not be. set_header is called before IS_GETTING is true,
- X * but if we set it to true temporarily, then signals will return to
- X * the right place (stop/continue).
- X */
- X {
- X u_long getting = ison(glob_flags, IS_GETTING);
- X int wrapping = wrapcolumn;
- X /* Funky trick here. If the prompt string is empty,
- X * assume that we are allowed to do line wrap;
- X * otherwise, temporarily disable line wrap
- X */
- X if (*str)
- X wrapcolumn = 0;
- X if (!getting)
- X turnon(glob_flags, IS_GETTING);
- X if (Getstr(buf, sizeof(buf), offset) == -1) {
- X putchar('\n');
- X buf[0] = 0;
- X }
- X if (!getting)
- X turnoff(glob_flags, IS_GETTING);
- X wrapcolumn = wrapping;
- X }
- X } else
- X puts(strcpy(buf, curstr));
- X if (debug > 1)
- X print("returning (%s) from set_header\n", buf);
- X return buf;
- X}
- X
- X/*
- X * improve uucp paths by looking at the name of each host listed in the
- X * path given.
- X * sun!island!pixar!island!argv
- X * It's a legal address, but redundant. Also, if we know we talk to particular
- X * hosts via uucp, then we can just start with that host and disregard the path
- X * preceding it. So, first get the known hosts and save them. Then start
- X * at the end of the original path (at the last ! found), and move backwards
- X * saving each hostname. If we get to a host that we know about, stop there
- X * and use that address. If the system knows about domains, skip all paths
- X * that precede a domain hostname. If we get to a host we've already seen,
- X * then delete it and all the hosts since then until the first occurrence of
- X * that hostname. When we get to the beginning, the address will be complete.
- X * The route_path is prepended to each address to check make sure this path
- X * is used if no known_hosts precede it in that address.
- X *
- X * Return all results into the original buffer passed to us. If route_path
- X * adds to the length of all the paths, then the original buffer could be
- X * overwritten. someone should check for this!
- X */
- Ximprove_uucp_paths(original, size, route_path)
- Xchar *original, *route_path;
- X{
- X char name[256], addr[256], buf[2 * HDRSIZ], *end;
- X char *hostnames[32], tmp[sizeof addr], *domain_path;
- X register char *p, *p2, *recipient, *start = original, *b = buf;
- X int saved_hosts, i, is_domain;
- X
- X if (!original || !*original)
- X return;
- X
- X /* use domain_path to point to the path for pathnames that have
- X * a fully qualified domain host in them.
- X */
- X domain_path = do_set(set_options, "domain_route");
- X while (end = get_name_n_addr(start, name, tmp)) {
- X /* first copy the route path, then the rest of the address. */
- X p = addr;
- X if (route_path && *route_path) {
- X p += Strcpy(addr, route_path);
- X *p++ = '!';
- X }
- X (void) bang_form(p, tmp);
- X saved_hosts = 0;
- X if (p2 = rindex(p, '!')) {
- X recipient = p2+1;
- X /* save the uucp-style address *without* route_path in tmp */
- X (void) strcpy(tmp, p);
- X for (p = p2; p > addr; p--) {
- X is_domain = 0;
- X /* null the '!' separating the rest of the path from the part
- X * of the path preceding it and move p back to the previous
- X * '!' (or beginning to addr) for hostname to point to.
- X */
- X for (*p-- = 0; p > addr && *p != '!'; p--)
- X if (!is_domain && domain_path && *p == '.' &&
- X lcase_strncmp(p, ".uucp", 5))
- X is_domain++;
- X /* if p is not at the addr, move it forward past the '!' */
- X if (p != addr)
- X ++p; /* now points to a null terminated hostname */
- X /* if host is ourselves, ignore this and preceding hosts */
- X for (i = 0; ourname && ourname[i]; i++)
- X if (!lcase_strncmp(p, ourname[i], -1))
- X break;
- X if (ourname && ourname[i]) {
- X is_domain = 0; /* we've eliminated all domains */
- X break;
- X }
- X /* check already saved hostnames. If host is one of them,
- X * delete remaining hostnames since there is a redundant path.
- X */
- X for (i = 0; i < saved_hosts; i++)
- X if (!lcase_strncmp(hostnames[i], p, -1))
- X saved_hosts = i;
- X
- X /* Add the hostname to the path being constructed */
- X hostnames[saved_hosts++] = p;
- X
- X /* If the original path or the address is a fully qualified
- X * hostname (domain info is included), then break here
- X */
- X if (p == addr || is_domain && domain_path)
- X break;
- X /* If we know that we call this host, break */
- X for (i = 0; known_hosts && known_hosts[i]; i++)
- X if (!lcase_strncmp(p, known_hosts[i], -1))
- X break;
- X if (known_hosts && known_hosts[i])
- X break;
- X }
- X /* temporary holder for where we are in buffer (save address) */
- X p2 = b;
- X if (is_domain && domain_path && *domain_path)
- X b += Strcpy(b, domain_path), *b++ = '!';
- X while (saved_hosts-- > 0) {
- X b += Strcpy(b, hostnames[saved_hosts]);
- X *b++ = '!';
- X }
- X b += Strcpy(b, recipient);
- X if (!strcmp(p2, tmp)) { /* if the same, address was unmodified */
- X b = p2; /* reset offset in buf (b) to where we were (p2) */
- X goto unmodified;
- X }
- X if (*name)
- X b += strlen(sprintf(b, " (%s)", name));
- X } else {
- X char c;
- Xunmodified:
- X c = *end;
- X *end = 0;
- X b += Strcpy(b, start); /* copy the entire address with comments */
- X *end = c;
- X }
- X if (b - buf > size) {
- X wprint("Warning: address list truncated!\n");
- X /* Use a very poor heuristic to find the last complete address */
- X for (b = buf+size - 1; *b != ','; b--)
- X ;
- X wprint("Lost addresses: %s%s\n", b, end); /* end = not yet parsed */
- X while (isspace(*b) || *b == ',')
- X b--;
- X break;
- X }
- X for (start = end; *start == ',' || isspace(*start); start++)
- X ;
- X if (!*start)
- X break;
- X *b++ = ',', *b++ = ' ', *b = '\0';
- X }
- X (void) strcpy(original, buf);
- X}
- X
- X/*
- X * rm_cmts_in_addr() removes the comment lines in addresses that result from
- X * sendmail or other mailers which append the user's "real name" on the
- X * from lines. See get_name_n_addr().
- X */
- Xrm_cmts_in_addr(str)
- Xregister char *str;
- X{
- X char addr[BUFSIZ], buf[HDRSIZ], *start = str;
- X register char *b = buf;
- X
- X *b = 0;
- X do {
- X if (!(str = get_name_n_addr(str, NULL, addr)))
- X break;
- X b += Strcpy(b, addr);
- X while (*str == ',' || isspace(*str))
- X str++;
- X if (*str)
- X *b++ = ',', *b++ = ' ', *b = '\0';
- X } while (*str);
- X for (b--; b > start && (*b == ',' || isspace(*b)); b--)
- X *b = 0;
- X (void) strcpy(start, buf);
- X}
- X
- X/*
- X * take_me_off() is intended to search for the user's login name in an
- X * address string and remove it. If "metoo" is set, return without change.
- X * determine which addresses are the "user'"'s addresses by comparing them
- X * against the host/path names in alternates. If the "*" is used, then
- X * this matches the address against the user's current login and -any- path.
- X *
- X * Note that the alternates list is an array of addresses stored *reversed*!
- X */
- Xtake_me_off(str)
- Xchar *str;
- X{
- X int i = 0, rm_me;
- X char tmp[256], addr[256], buf[HDRSIZ], *start = str;
- X register char *p, *p2, *b = buf;
- X
- X if (!str || !*str)
- X return;
- X
- X Debug("take_me_off()\n");
- X *b = 0;
- X do {
- X rm_me = FALSE;
- X /* get the first "address" and advance p to next addr (ignore name) */
- X if (!(p = get_name_n_addr(str, NULL, tmp)))
- X break; /* we've reached the end of the address list */
- X /* see if user's login is in the address */
- X if (!strcmp(login, tmp))
- X rm_me = TRUE;
- X else {
- X int len;
- X /* put address in !-format and store in "addr" */
- X (void) bang_form(addr, tmp);
- X (void) reverse(addr);
- X for (i = 0; alternates && alternates[i] && !rm_me; i++) {
- X if (alternates[i][0] == '*') {
- X if (alternates[i][1] == '\0')
- X p2 = reverse(strcpy(tmp, login));
- X else
- X p2 = reverse(strcpy(tmp, &alternates[i][1]));
- X } else
- X p2 = alternates[i];
- X if (!lcase_strncmp(p2, addr, (len = strlen(p2))) &&
- X (!addr[len] || addr[len] == '!')) {
- X Debug("\t%s\n", reverse(addr));
- X rm_me = TRUE;
- X }
- X }
- X for (i = 0; !rm_me && ourname && ourname[i]; i++) {
- X p2 = tmp + Strcpy(tmp, ourname[i]);
- X *p2++ = '!';
- X (void) strcpy(p2, login);
- X (void) reverse(tmp);
- X if (!lcase_strncmp(tmp, addr, (len = strlen(tmp))) &&
- X (!addr[len] || addr[len] == '!')) {
- X Debug("\t%s\n", reverse(addr));
- X rm_me = TRUE;
- X }
- X }
- X }
- X /* The address is not the user's -- put it into the returned list */
- X if (!rm_me) {
- X char c = *p;
- X *p = 0;
- X b += Strcpy(b, str);
- X *p = c;
- X }
- X while (*p == ',' || isspace(*p))
- X p++;
- X if (*p && !rm_me)
- X *b++ = ',', *b++ = ' ', *b = '\0';
- X } while (*(str = p));
- X for (b--; b > buf && (*b == ',' || isspace(*b)); b--)
- X *b = 0;
- X (void) strcpy(start, buf);
- X}
- X
- X/*
- X * Place commas in between all addresses that don't already have
- X * them. Addresses which use comments which are in parens or _not_
- X * within angle brackets *must* already have commas around them or
- X * you can't determine what is a comment and what is an address.
- X */
- Xfix_up_addr(str)
- Xchar *str;
- X{
- X char buf[HDRSIZ], *start = str;
- X register char c, *p, *b = buf;
- X
- X *b = 0;
- X do {
- X /* get_name returns a pointer to the next address */
- X if (!(p = get_name_n_addr(str, NULL, NULL)))
- X break;
- X c = *p, *p = 0;
- X if (strlen(str) + (b - buf) >= sizeof(buf) - 2) {
- X /* wprint("Address too long! Lost address: \"%s\"\n", str); */
- X *p = c;
- X break;
- X }
- X for (b += Strcpy(b, str); b > buf && isspace(*(b-1)); b--)
- X *b = 0;
- X for (*p = c; *p == ',' || isspace(*p); p++)
- X ;
- X if (*p)
- X *b++ = ',', *b++ = ' ', *b = '\0';
- X } while (*(str = p));
- X for (b--; b > buf && (*b == ',' || isspace(*b)); b--)
- X *b = 0;
- X (void) strcpy(start, buf);
- X}
- X
- X/*
- X * Remove redundant addresses.
- X * Assume improve_uucp_paths, fix_up_addr or whatever have already been called.
- X */
- Xrm_redundant_addrs(to, cc)
- Xchar *to, *cc;
- X{
- X char tmp[256], addr[256], buf[HDRSIZ];
- X char **list; /* a list of addresses for comparison */
- X int list_cnt = 0, l;
- X register char c, *p, *b, *start;
- X
- X Debug("rm_redundant_addrs()\n");
- X list = (char **) calloc(256, sizeof(char *));
- X if (!list) {
- X error("out of memory in rm_redundant_addrs");
- X return;
- X }
- X start = to;
- X b = buf, *b = 0;
- X /* first do the To header */
- X do {
- X /* get_name returns a pointer to the next address */
- X if (!(p = get_name_n_addr(to, NULL, tmp)))
- X break;
- X c = *p, *p = 0;
- X (void) bang_form(addr, tmp);
- X for (l = 0; l < list_cnt; l++)
- X if (!lcase_strncmp(addr, list[l], -1))
- X break;
- X /* if l == list_cnt, we got a new address, store it and add to buf */
- X if (l == list_cnt) {
- X /* Don't overwrite buffer. */
- X if (list_cnt < 256)
- X list[list_cnt++] = savestr(addr);
- X if (b > buf)
- X *b++ = ',', *b++ = ' ', *b = '\0';
- X for (b += Strcpy(b, to); b > buf && isspace(*(b-1)); b--)
- X *b = 0;
- X } else
- X Debug("\t%s\n", tmp); /* already specified (removed from list) */
- X for (*p = c; *p == ',' || isspace(*p); p++)
- X ;
- X } while (*(to = p));
- X for (b--; b > buf && (*b == ',' || isspace(*b)); b--)
- X *b = 0;
- X (void) strcpy(start, buf);
- X b = buf, *b = 0;
- X /* Now do the Cc header. If addr is listed in the To field, rm it in cc */
- X start = cc;
- X do {
- X /* get_name returns a pointer to the next address */
- X if (!(p = get_name_n_addr(cc, NULL, tmp)))
- X break;
- X c = *p, *p = 0;
- X (void) bang_form(addr, tmp);
- X for (l = 0; l < list_cnt; l++)
- X if (!lcase_strncmp(addr, list[l], -1))
- X break;
- X if (l == list_cnt) {
- X /* Don't overwrite buffer. */
- X if (list_cnt < sizeof(list)/sizeof(char *))
- X list[list_cnt++] = savestr(addr);
- X if (b > buf)
- X *b++ = ',', *b++ = ' ', *b = '\0';
- X for (b += Strcpy(b, cc); b > buf && isspace(*(b-1)); b--)
- X *b = 0;
- X } else
- X Debug("\t%s\n", tmp); /* already specified (removed from list) */
- X for (*p = c; *p == ',' || isspace(*p); p++)
- X ;
- X } while (*(cc = p));
- X list[list_cnt] = NULL; /* for free_vec */
- X free_vec(list);
- X for (b--; b > buf && (*b == ',' || isspace(*b)); b--)
- X *b = 0;
- X (void) strcpy(start, buf);
- X}
- X
- X/*
- X * Get address and name from a string (str) which came from an address header
- X * in a message or typed by the user. The string may contain one or more
- X * well-formed addresses. Each must be separated by a comma.
- X *
- X * address, address, address
- X * address (comment or name here)
- X * comment or name <address>
- X * "Comment, even those with comma's!" <address>
- X * address (comma, (more parens), etc...)
- X *
- X * This does *not* handle cases like:
- X * comment <address (comment)>
- X *
- X * find the *first* address here and return a pointer to the end of the
- X * address (usually a comma). Return NULL on error: non-matching parens,
- X * brackets, quotes...
- X */
- Xchar *
- Xget_name_n_addr(str, name, addr)
- Xregister char *str, *name, *addr;
- X{
- X register char *p, *p2, *beg_addr = addr, *beg_name = name, c;
- X
- X if (addr)
- X *addr = 0;
- X if (name)
- X *name = 0;
- X if (!str || !*str)
- X return NULL;
- X
- X while (isspace(*str))
- X str++;
- X
- X /* first check to see if there's something to look for */
- X if (!(p = any(str, ",(<\""))) {
- X /* no comma or indication of a quote character. Find a space and
- X * return that. If nothing, the entire string is a complete address
- X */
- X if (p = any(str, " \t"))
- X c = *p, *p = 0;
- X if (addr)
- X (void) strcpy(addr, str);
- X if (p)
- X *p = c;
- X return p? p : str + strlen(str);
- X }
- X
- X /* comma terminated before any comment stuff. If so, check for whitespace
- X * before-hand cuz it's possible that strings aren't comma separated yet
- X * and they need to be.
- X *
- X * address address address, address
- X * ^p <- p points here.
- X * ^p2 <- should point here.
- X */
- X if (*p == ',') {
- X c = *p, *p = 0;
- X if (p2 = any(str, " \t"))
- X *p = ',', c = *p2, p = p2, *p = 0;
- X if (addr)
- X (void) strcpy(addr, str);
- X *p = c;
- X return p;
- X }
- X
- X /* starting to get hairy -- we found an angle bracket. This means that
- X * everything outside of those brackets are comments until we find that
- X * all important comma. A comment AFTER the <addr> :
- X * <address> John Doe
- X * can't call this function recursively or it'll think that "John Doe"
- X * is a string with two legal address on it (each name being an address).
- X */
- X if (*p == '<') { /* note that "str" still points to comment stuff! */
- X if (name && *str) {
- X *p = 0;
- X name += Strcpy(name, str);
- X *p = '<';
- X }
- X if (!(p2 = index(p+1, '>'))) {
- X wprint("Warning! Malformed address: \"%s\"\n", str);
- X return NULL;
- X }
- X if (addr) {
- X /* to support <addr (comment)> style addresses, add code here */
- X *p2 = 0;
- X skipspaces(1);
- X addr += Strcpy(addr, p);
- X while (addr > beg_addr && isspace(*(addr-1)))
- X *--addr = 0;
- X *p2 = '>';
- X }
- X /* take care of the case "... <addr> com (ment)" */
- X {
- X int p_cnt = 0; /* parenthesis counter */
- X p = p2;
- X /* don't recurse yet -- scan till null, comma or '<'(add to name) */
- X for (p = p2; p[1] && (p_cnt || p[1] != ',' && p[1] != '<'); p++) {
- X if (p[1] == '(')
- X p_cnt++;
- X else if (p[1] == ')')
- X p_cnt--;
- X if (name)
- X *name++ = p[1];
- X }
- X if (p_cnt) {
- X wprint("Warning! Malformed name: \"%s\"\n", name);
- X return NULL;
- X }
- X }
- X if (name && name > beg_name) {
- X while (isspace(*(name-1)))
- X --name;
- X *name = 0;
- X }
- X }
- X
- X /* this is the worst -- now we have parentheses/quotes. These guys can
- X * recurse pretty badly and contain commas within them.
- X */
- X if (*p == '(' || *p == '"') {
- X char *start = p;
- X int comment = 1;
- X c = *p;
- X /* "str" points to address while p points to comments */
- X if (addr && *str) {
- X *p = 0;
- X while (isspace(*str))
- X str++;
- X addr += Strcpy(addr, str);
- X while (addr > beg_addr && isspace(*(addr-1)))
- X *--addr = 0;
- X *p = c;
- X }
- X while (comment) {
- X if (c == '"' && !(p = index(p+1, '"')) ||
- X c == '(' && !(p = any(p+1, "()"))) {
- X wprint("Warning! Malformed address: \"%s\"\n", str);
- X return NULL;
- X }
- X if (*p == '(') /* loop again on parenthesis. quote ends loop */
- X comment++;
- X else
- X comment--;
- X }
- X /* Something like ``Comment (Comment) <addr>''. In this case
- X * the name should include both comment parts with the
- X * parenthesis. We have to redo addr.
- X */
- X if ((p2 = any(p+1, "<,")) && *p2 == '<') {
- X if (!(p = index(p2, '>'))) {
- X wprint("Warning! Malformed address: \"%s\"\n", str);
- X return NULL;
- X }
- X if (addr = beg_addr) { /* reassign addr and compare to null */
- X c = *p; *p = 0;
- X addr += Strcpy(addr, p2+1);
- X while (addr > beg_addr && isspace(*(addr-1)))
- X *--addr = 0;
- X *p = c;
- X }
- X if (name) {
- X c = *p2; *p2 = 0;
- X name += Strcpy(name, str);
- X while (name > beg_name && isspace(*(name-1)))
- X *--name = 0;
- X *p2 = c;
- X }
- X } else if (name && start[1]) {
- X c = *p, *p = 0; /* c may be ')' instead of '(' now */
- X name += Strcpy(name, start+1);
- X while (name > beg_name && isspace(*(name-1)))
- X *--name = 0;
- X *p = c;
- X }
- X }
- X skipspaces(1);
- X /* this is so common, save time by returning now */
- X if (!*p || *p == ',')
- X return p;
- X return get_name_n_addr(p, name, addr);
- X}
- X
- X/* takes string 's' which can be a name or list of names separated by
- X * commas and checks to see if each is aliased to something else.
- X * return address of the static buf.
- X */
- Xchar *
- Xalias_to_address(s)
- Xregister char *s;
- X{
- X static char buf[HDRSIZ];
- X register char *p, *p2, *tmp;
- X char newbuf[HDRSIZ], c;
- X static int recursive;
- X
- X if (!aliases)
- X return strcpy(buf, s);
- X if (!s || !*s)
- X return NULL;
- X if (!recursive) {
- X bzero(buf, sizeof buf);
- X p2 = buf; /* if we're starting all this, p2 starts at &buf[0] */
- X } else
- X p2 = buf+strlen(buf); /* else, pick up where we left off */
- X
- X if (++recursive == 30) {
- X wprint("alias references too many addresses!\n");
- X recursive = 0;
- X return NULL;
- X }
- X do {
- X char addr[256];
- X if (!(p = get_name_n_addr(s, NULL, addr)))
- X break;
- X c = *p, *p = 0;
- X
- X /* On recursive calls, compare against the entire
- X * previous expansion, not just the address part.
- X */
- X if (recursive > 1)
- X (void) strcpy(addr, s);
- X
- X /* if this is an alias, recurse this routine to expand it out */
- X if ((tmp = do_set(aliases, addr)) && *tmp) {
- X if (!alias_to_address(strcpy(newbuf, tmp))) {
- X *p = c;
- X return NULL;
- X } else
- X p2 = buf+strlen(buf);
- X /* Now, make sure the buffer doesn't overflow */
- X } else if (strlen(s) + (p2-buf) + 2 > sizeof buf) { /* add ", " */
- X wprint("address length too long.\n");
- X recursive = 0;
- X *p = c;
- X return NULL;
- X } else {
- X /* append the new alias (or unchanged address) onto the buffer */
- X p2 += Strcpy(p2, s);
- X *p2++ = ',', *p2++ = ' ', *p2 = '\0';
- X }
- X for (*p = c; *p == ',' || isspace(*p); p++)
- X ;
- X } while (*(s = p));
- X if (recursive)
- X recursive--;
- X if (!recursive)
- X *(p2-2) = 0; /* get rid of last ", " if end of recursion */
- X return buf;
- X}
- X
- X/*
- X * Wrap addresses so that the headers don't exceed n chars (typically 80).
- X */
- Xchar *
- Xwrap_addrs(str, n)
- Xchar *str;
- X{
- X char buf[HDRSIZ * 2], *start = str;
- X register char *b = buf, *p, c, *line_start = buf;
- X
- X *b = 0;
- X do {
- X /* get_name returns a pointer to the next address */
- X if (!(p = get_name_n_addr(str, NULL, NULL)))
- X break;
- X c = *p, *p = 0;
- X if (b > buf) {
- X *b++ = ',', *b++ = ' ', *b = '\0';
- X if (b - line_start + strlen(str) + 8 /* \t = 8 */ >= n)
- X *b++ = '\n', *b++ = '\t', line_start = b;
- X }
- X for (b += Strcpy(b, str); b > buf && isspace(*(b-1)); b--)
- X *b = 0;
- X for (*p = c; *p == ',' || isspace(*p); p++)
- X ;
- X } while (*(str = p));
- X for (b--; b > buf && (*b == ',' || isspace(*b)); b--)
- X *b = 0;
- X return strcpy(start, buf);
- X}
- END_OF_FILE
- if test 33359 -ne `wc -c <'mush/addrs.c'`; then
- echo shar: \"'mush/addrs.c'\" unpacked with wrong size!
- fi
- # end of 'mush/addrs.c'
- fi
- if test -f 'mush/viewopts.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'mush/viewopts.c'\"
- else
- echo shar: Extracting \"'mush/viewopts.c'\" \(18292 characters\)
- sed "s/^X//" >'mush/viewopts.c' <<'END_OF_FILE'
- X/* @(#)viewopts.c (c) copyright 10/18/86 (Dan Heller) */
- X
- X#include "mush.h"
- X
- Xstruct viewopts {
- X char *v_opt;
- X char *v_prompt;
- X char *v_description;
- X#ifdef SUNTOOL
- X Panel_item v_choice;
- X Panel_item v_text;
- X#endif /* SUNTOOL */
- X};
- X
- X#ifdef SUNTOOL
- Xshort dat_cycle_cursor[] = {
- X 0x07C0, 0x0FE0, 0x1834, 0x301C, 0x601C, 0x203C, 0x0000, 0x0000,
- X 0x7808, 0x700C, 0x7018, 0x5830, 0x0FE0, 0x07C0, 0x0000, 0x0000
- X
- X};
- Xmpr_static(cycle, 16, 16, 1, dat_cycle_cursor);
- X#endif /* SUNTOOL */
- X
- X/*
- X * struct contains the option, a prompt if it has a string value, whether
- X * or not it applies to non suntools, line mode, or both, and a
- X * string describing what the option does. If the prompt string starts
- X * with a minus sign, then the value can be set without a value. This
- X * is there to indicate to option_line to print a toggle (cycle) pixrect
- X * and to print TRUE/FALSE telling whether the value is on or off regardless
- X * of it's "string" value.
- X */
- Xstruct viewopts viewopts[] = {
- X { "alwaysignore", NULL,
- X "Always ignore the message headers on the 'ignored' list." },
- X { "ask", NULL,
- X "Prompts for a subject on outgoing mail." },
- X { "askcc", NULL,
- X "Ask for list of Carbon Copy recipients whenever sending mail." },
- X { "autodelete", NULL,
- X "Automatically delete ALL READ messages whenever you update mail." },
- X { "autoedit", NULL,
- X "Automatically enter editor for REPLIES only (not toolmode)." },
- X { "autoinclude", NULL,
- X "Include a copy of author's message each time you reply to mail." },
- X { "autoprint", NULL,
- X "Display the next message on the list when you delete a message." },
- X { "auto_route", "-Host/Path:",
- X "Remove redundant uucp addresses when replying to messages." },
- X { "autosign", "-Filename:",
- X "Add file (~/.signature if set but no value) at end of all letters." },
- X { "autosign2", "Addr:File:",
- X "Signature to use for specific addresses. \"addr, ... : <signature>\""},
- X { "cdpath", "Path:",
- X "Path to search for directories when the \"cd\" command is issued." },
- X { "cmd_help", "Path:",
- X "Location of the general help file for line and curses modes." },
- X { "complete", "Character:",
- X "The character typed to cause a word completion to occur." },
- X { "crt", "Lines:",
- X "The number of lines a message must have for 'pager' to be invoked." },
- X { "crt_win", "Lines:",
- X "Lines in the tool mode text subwindow for paging messages." },
- X { "curses_help", "-Commands:",
- X "List of curses commands whose bindings appear in the help display." },
- X { "date_received", NULL,
- X "Time displayed for message headers shows date received (or sent)." },
- X { "dead", "Filename:",
- X "The name of the file to store dead mail (default = ~/dead.letter)." },
- X { "domain_route", "-Host/Path:",
- X "Cause short-circuiting of domain addresses when auto-routing." },
- X { "dot", NULL,
- X "Allow \".\" on a line by itself to send letter." },
- X { "edit_hdrs", NULL,
- X "Allow headers of messages to be edited using your editor." },
- X { "editor", "Editor:",
- X "Editor for message editing (default = env EDITOR or \"vi\")." },
- X { "escape", "Character:",
- X "Escape character for extended editing commands (default = ~)." },
- X { "fignore", "Patterns:",
- X "Filename extensions or patterns ignored in completions." },
- X { "folder", "Pathname:",
- X "Full pathname to the directory where personal folders are kept." },
- X { "fortune", "-Flag:",
- X "Add fortune to end of letters. Flag to \"fortune\" is optional." },
- X { "fortunates", "Users:",
- X "Those who will receive fortunes if fortune is set (default: All)." },
- X { "hdr_format", "Format:",
- X "Formatting string for headers. \"headers -?\" or help hdr_format." },
- X { "history", "Number:",
- X "How many commands to remember (like csh)." },
- X { "hold", NULL,
- X "Read but not deleted messages are saved in spool -- not mbox." },
- X { "home", "Directory:",
- X "The user's home directory." },
- X { "hostname", "Hostname:",
- X "User-definable name for the name of your machine." },
- X { "ignore_bang", NULL,
- X "Ignore '!' as a history reference. Otherwise, escape by: \\!" },
- X { "ignoreeof", "-Command:",
- X "Ignores ^D as exit, or (if set), execute \"command\"." },
- X { "indent_str", "String:",
- X "String to offset included messages within your letters." },
- X { "in_reply_to", "-String:",
- X "When responding to mail, add In-Reply-To: to message headers." },
- X { "keepsave", NULL,
- X "Prevents messages from being marked as `deleted' when you `save'." },
- X { "known_hosts", "Host list:",
- X "List of hosts that your site is known to uucp mail to." },
- X { "logfile", "Filename:",
- X "Log outgoing mail headers only. Message text not logged." },
- X { "mail_icon", "Filename:",
- X "Alternate pixmap to use when tool is closed to an icon." },
- X { "mbox", "Filename:",
- X "Filename to use instead of ~/mbox for default mailbox." },
- X { "metoo", NULL,
- X "When replying to mail, metoo preserves your name on mailing list." },
- X { "mil_time", NULL,
- X "24-hour military time format is used whenever a time is printed." },
- X { "msg_win", "Lines:",
- X "Number of lines in the message composition window for tool mode." },
- X { "newline", "-Command:",
- X "Ignore RETURN. If set to a command, execute that command." },
- X { "newmail_icon", "Filename:",
- X "Alternate icon shown when new mail is available." },
- X { "no_expand", NULL,
- X "Prevents expansion of Mush aliases in outgoing mail headers." },
- X { "no_hdrs", NULL,
- X "If set, personalized headers are NOT inserted to outgoing mail." },
- X { "no_reverse", NULL,
- X "Disables reverse video in curses mode -- uses \"bold\" in tool mode."},
- X { "nonobang", NULL,
- X "Suppresses errors from unsuccessful history references." },
- X { "nosave", NULL,
- X "Prevents aborted mail from being saved in $dead." },
- X { "output", NULL,
- X "The message list produced as output of the last command." },
- X { "pager", "Program:",
- X "Program name to be used as a pager for messages longer than crt." },
- X { "pre_indent_str", "String:",
- X "String to precede message text interpolated into message body." },
- X { "post_indent_str", "String:",
- X "String to succeed message text interpolated into message body." },
- X { "print_cmd", "Program:",
- X "Alternate program to use to send messages to the printer." },
- X { "printer", "Printer:",
- X "Printer to send messages to (default = environment PRINTER)." },
- X { "prompt", "String:",
- X "Your prompt. \"help prompt\" for more information." },
- X { "quiet", "-Conditions:",
- X "Turn off verbose messages and error bells in various conditions." },
- X { "realname", "Name:",
- X "Your real name." },
- X { "record", "Filename:",
- X "Save all outgoing mail in specified filename." },
- X { "reply_to_hdr", "Headers:",
- X "List of headers use to construct reply addresses from a message." },
- X { "save_empty", NULL,
- X "Folders which have all messages deleted are NOT removed on updates." },
- X { "screen", "# of Headers:",
- X "Number of headers to print in non-suntools (text) mode." },
- X { "screen_win", "# of Headers:",
- X "Set the size of the header window for the tool mode only." },
- X { "show_deleted", NULL,
- X "Show deleted messages in headers listings (unused in curses mode)." },
- X { "show_hdrs", "Headers:",
- X "When displaying a message, show list of \"headers\" only." },
- X { "sendmail", "Program:",
- X "Program to use to deliver mail instead of using the default."},
- X { "sort", "-Option:",
- X "Pre-sorting of messages on mush startup (set to valid sort option)." },
- X { "squeeze", NULL,
- X "When reading messages, squeeze all blank lines into one." },
- X { "status", NULL,
- X "The success or failure status of the most recent command." },
- X { "thisfolder", "Folder:",
- X "This read-only variable gives the current folder name." },
- X { "tool_help", "Path:",
- X "Location of the help file for tool mode." },
- X { "toplines", "Lines:",
- X "Number of lines to print of a message for the 'top' command." },
- X { "tmpdir", "Directory:",
- X "Directory to use for temporary files used by Mush." },
- X { "unix", NULL,
- X "Non-mush commands are considered to be UNIX commands." },
- X { "verify", NULL,
- X "Verify to send, re-edit, or abort letter after editing." },
- X { "visual", "Visual editor:",
- X "Visual editor for messages (default = $editor or env VISUAL)."},
- X { "warning", NULL,
- X "Print warning messages for non-fatal errors." },
- X { "wrap", NULL,
- X "After referencing last message, message pointer wraps to start." },
- X { "wrapcolumn", "-Column to wrap [78]:",
- X "Column at which to wrap lines when composing messages." },
- X};
- X
- X#ifdef SUNTOOL
- X
- X#define OPTIONS_PANEL_WIDTH 550
- X
- Xint set_value(), toggle_value(), help_opt();
- X
- XFrame opts_frame;
- XPanel opts_panel;
- XPanel_item desc_msg;
- XPanel_item file_text_item;
- X
- Xstatic void
- Xframe_done()
- X{
- X#ifdef SUN_4_0 /* SunOS 4.0+ */
- X window_set(opts_frame, WIN_SHOW, FALSE, NULL);
- X#else /* SUN_4_0 */
- X /* not enough fd's to keep it lying around for SunOS 3.X */
- X window_destroy(opts_frame);
- X opts_frame = (Frame) 0;
- X#endif /* SUN_4_0 */
- X}
- X
- Xstatic void
- Xopts_help()
- X{
- X help(0, "options", tool_help);
- X}
- X
- Xstatic void
- Xopts_save_load(item)
- XPanel_item item;
- X{
- X int (*func)() = (int (*)())panel_get(item, PANEL_CLIENT_DATA);
- X int result;
- X char buf[MAXPATHLEN];
- X char *argv[3], *file = panel_get_value(file_text_item);
- X
- X if (!*file) {
- X result = (*func)(0, DUBL_NULL);
- X file = ".mushrc";
- X } else {
- X argv[1] = file;
- X argv[2] = NULL;
- X result = (*func)(2, argv);
- X }
- X switch (result) {
- X case 0:
- X sprintf(buf, "%s %s",
- X (func == source)? "Loaded options from" : "Saved options to",
- X file);
- X when -1:
- X sprintf(buf, "%s: %s", file, sys_errlist[errno]);
- X when -2:
- X sprintf(buf, "%s is a directory.", file);
- X when -3:
- X /* save_opts() returns -3 if user doesn't confirm overwrite */
- X strcpy(buf, "Save operation aborted.");
- X }
- X panel_set(desc_msg, PANEL_LABEL_STRING, buf, NULL);
- X}
- X
- Xstatic void
- Xunset_opts()
- X{
- X cmd_line("unset *", NULL);
- X}
- X
- Xstatic void
- Xreset_opts()
- X{
- X source(0, DUBL_NULL);
- X}
- X
- X/*
- X * Public routine which creates a subframe which contains two panels.
- X * The first contains options for loading and saving options from a
- X * file (text item) and so on... the second panel contains all the items
- X * which correspond to each mush variable that exists.
- X */
- Xvoid
- Xview_options()
- X{
- X extern Notify_value fkey_interposer();
- X register char *p;
- X int count;
- X
- X if (opts_frame) {
- X window_set(opts_frame, WIN_SHOW, TRUE, NULL);
- X opts_panel_item(NULL);
- X return;
- X }
- X#ifdef SUN_3_5
- X if (nopenfiles(0) < 3) {
- X ok_box("Too many frames; close one first!\n");
- X return;
- X }
- X#endif /* SUN_3_5 */
- X
- X opts_frame = window_create(tool, FRAME,
- X FRAME_DONE_PROC, frame_done,
- X FRAME_LABEL, "Mush Options",
- X FRAME_NO_CONFIRM, TRUE,
- X FRAME_SHOW_LABEL, TRUE,
- X WIN_WIDTH, OPTIONS_PANEL_WIDTH,
- X NULL);
- X
- X opts_panel = window_create(opts_frame, PANEL,
- X WIN_WIDTH, OPTIONS_PANEL_WIDTH,
- X NULL);
- X (void) notify_interpose_event_func(opts_panel,
- X fkey_interposer, NOTIFY_SAFE);
- X panel_create_item(opts_panel, PANEL_BUTTON,
- X PANEL_LABEL_IMAGE,
- X panel_button_image(opts_panel, "Done", 4, mush_font),
- X PANEL_NOTIFY_PROC, frame_done,
- X NULL);
- X panel_create_item(opts_panel, PANEL_BUTTON,
- X PANEL_LABEL_IMAGE,
- X panel_button_image(opts_panel, "Help", 4, mush_font),
- X PANEL_NOTIFY_PROC, opts_help,
- X NULL);
- X panel_create_item(opts_panel, PANEL_BUTTON,
- X PANEL_LABEL_IMAGE,
- X panel_button_image(opts_panel, "Save", 4, mush_font),
- X PANEL_NOTIFY_PROC, opts_save_load,
- X PANEL_CLIENT_DATA, save_opts,
- X NULL);
- X panel_create_item(opts_panel, PANEL_BUTTON,
- X PANEL_LABEL_IMAGE,
- X panel_button_image(opts_panel, "Load", 4, mush_font),
- X PANEL_NOTIFY_PROC, opts_save_load,
- X PANEL_CLIENT_DATA, source,
- X NULL);
- X panel_create_item(opts_panel, PANEL_BUTTON,
- X PANEL_LABEL_IMAGE,
- X panel_button_image(opts_panel, "Clear", 5, mush_font),
- X PANEL_NOTIFY_PROC, unset_opts,
- X NULL);
- X panel_create_item(opts_panel, PANEL_BUTTON,
- X PANEL_LABEL_IMAGE,
- X panel_button_image(opts_panel, "Restart", 7, mush_font),
- X PANEL_NOTIFY_PROC, reset_opts,
- X NULL);
- X file_text_item = panel_create_item(opts_panel, PANEL_TEXT,
- X PANEL_LABEL_STRING, "Save/Load File:",
- X PANEL_VALUE_DISPLAY_LENGTH, 30,
- X NULL);
- X desc_msg = panel_create_item(opts_panel, PANEL_MESSAGE,
- X PANEL_LABEL_STRING, "Help Descriptions -- Click on Variable Name",
- X NULL);
- X window_fit_height(opts_panel);
- X
- X /* reuse opts_panel -- we don't need the other one */
- X opts_panel = window_create(opts_frame, PANEL,
- X WIN_BELOW, opts_panel,
- X WIN_X, 0,
- X WIN_COLUMN_GAP, 120,
- X WIN_TOP_MARGIN, 10,
- X WIN_LEFT_MARGIN, 10,
- X WIN_WIDTH, OPTIONS_PANEL_WIDTH,
- X PANEL_VERTICAL_SCROLLBAR, scrollbar_create(NULL),
- X NULL);
- X (void) notify_interpose_event_func(opts_panel,
- X fkey_interposer, NOTIFY_SAFE);
- X
- X for (count = 0; count < ArraySize(viewopts); count++) {
- X panel_create_item(opts_panel, PANEL_MESSAGE,
- X PANEL_ITEM_X, ATTR_COL(0),
- X PANEL_ITEM_Y, ATTR_ROW(count),
- X PANEL_LABEL_STRING, viewopts[count].v_opt,
- X PANEL_NOTIFY_PROC, help_opt,
- X PANEL_CLIENT_DATA, count,
- X NULL);
- X
- X if (!(p = viewopts[count].v_prompt) || *p == '-') {
- X if (p && *p)
- X p++;
- X viewopts[count].v_choice = panel_create_item(opts_panel,
- X PANEL_CHOICE,
- X PANEL_LABEL_IMAGE, &cycle,
- X PANEL_LAYOUT, PANEL_HORIZONTAL,
- X PANEL_CHOICE_STRINGS, "False", "True", NULL,
- X PANEL_DISPLAY_LEVEL, PANEL_CURRENT,
- X PANEL_ITEM_X, ATTR_COL(1),
- X PANEL_ITEM_Y, ATTR_ROW(count),
- X PANEL_NOTIFY_PROC, toggle_value,
- X PANEL_CLIENT_DATA, count,
- X NULL);
- X }
- X if (p) {
- X viewopts[count].v_text = panel_create_item(opts_panel, PANEL_TEXT,
- X PANEL_VALUE_DISPLAY_LENGTH, 10,
- X PANEL_VALUE_UNDERLINED, TRUE,
- X PANEL_LABEL_STRING, p,
- X PANEL_ITEM_X, ATTR_COL(2),
- X PANEL_ITEM_Y, ATTR_ROW(count),
- X PANEL_NOTIFY_PROC, set_value,
- X PANEL_CLIENT_DATA, count,
- X NULL);
- X }
- X }
- X /* set the panel items' values */
- X opts_panel_item(NULL);
- X
- X window_set(opts_panel,
- X WIN_HEIGHT, 400,
- X WIN_FIT_HEIGHT, 0,
- X NULL);
- X window_set(opts_frame, WIN_SHOW, TRUE, NULL);
- X}
- X
- X/*
- X * Sets the items in the panels to reflect that variable's value.
- X * If "var" is NULL, do it for all the items.
- X */
- Xvoid
- Xopts_panel_item(var)
- Xchar *var;
- X{
- X int count;
- X char *value;
- X
- X if (!opts_frame)
- X return;
- X
- X for (count = 0; count < ArraySize(viewopts); count++) {
- X if (var && strcmp(var, viewopts[count].v_opt))
- X continue;
- X value = do_set(set_options, viewopts[count].v_opt);
- X
- X if (!viewopts[count].v_prompt || *viewopts[count].v_prompt == '-')
- X panel_set_value(viewopts[count].v_choice, value != NULL);
- X if (viewopts[count].v_prompt)
- X panel_set_value(viewopts[count].v_text, value? value : "");
- X if (var)
- X break;
- X }
- X}
- X
- X/*
- X * Callback for choice items -- for variables that have boolean settings.
- X * CLIENT_DATA is the index in the viewopts array.
- X */
- Xstatic
- Xtoggle_value(item, value)
- XPanel_item item;
- Xint value;
- X{
- X int count = (int) panel_get(item, PANEL_CLIENT_DATA);
- X char *p, *argv[4];
- X char *text_value = NULL;
- X
- X if (check_internal(viewopts[count].v_opt)) {
- X panel_set(desc_msg, PANEL_LABEL_STRING,
- X "This is an internal variable which cannot be changed.",
- X NULL);
- X return -1;
- X }
- X
- X if (p = viewopts[count].v_prompt) /* set equal */
- X text_value = panel_get_value(viewopts[count].v_text);
- X
- X if (!value)
- X (void) un_set(&set_options, viewopts[count].v_opt);
- X else {
- X /* Turn it on if it's entirely boolean or bool/str, but no str value */
- X if (!p || text_value && !*text_value) {
- X argv[0] = viewopts[count].v_opt; /* it's a boolean */
- X argv[1] = NULL;
- X } else {
- X /* string value -- determine the text from the typed in value */
- X argv[0] = viewopts[count].v_opt;
- X argv[1] = "=";
- X argv[2] = text_value;
- X argv[3] = NULL;
- X }
- X (void) add_option(&set_options, argv);
- X }
- X
- X if (!strcmp(viewopts[count].v_opt, "no_reverse") ||
- X !strcmp(viewopts[count].v_opt, "show_deleted"))
- X do_hdrs(0, DUBL_NULL, NULL);
- X
- X return 0;
- X}
- X
- X/* callback for text items -- set vars to the string typed. */
- Xstatic
- Xset_value(item, event)
- XPanel_item item;
- XEvent *event;
- X{
- X int count = (int)panel_get(item, PANEL_CLIENT_DATA);
- X char *p, *argv[4], *value;
- X
- X if (event_id(event) == '\t')
- X return (int) PANEL_NEXT;
- X
- X p = viewopts[count].v_prompt;
- X value = panel_get_value(item);
- X
- X if (check_internal(viewopts[count].v_opt)) {
- X panel_set(desc_msg, PANEL_LABEL_STRING,
- X "This is an internal variable which cannot be changed.",
- X NULL);
- X return (int) PANEL_NONE;
- X }
- X
- X /*
- X * You can "unset" string-only values by entering a blank string.
- X * If the "prompt" starts with a -, then you can only "unset" the
- X * variable by setting the associated choice item to false.
- X */
- X if (*p != '-' && !*value) {
- X (void) un_set(&set_options, viewopts[count].v_opt);
- X return (int) PANEL_NONE; /* do not advance caret */
- X }
- X /* Turn it on, but not to a value */
- X if (!*value) {
- X argv[0] = viewopts[count].v_opt; /* it's a boolean */
- X argv[1] = NULL;
- X } else {
- X /* string value -- determine the text from the typed in value */
- X argv[0] = viewopts[count].v_opt;
- X argv[1] = "=";
- X argv[2] = value;
- X argv[3] = NULL;
- X }
- X
- X (void) add_option(&set_options, argv);
- X if (p && *p == '-')
- X panel_set_value(viewopts[count].v_choice, TRUE);
- X
- X return (int) PANEL_NONE;
- X}
- X
- X/* when user clicks on variable label itself */
- Xstatic
- Xhelp_opt(item, event)
- XPanel_item item;
- XEvent *event;
- X{
- X int count = (int)panel_get(item, PANEL_CLIENT_DATA);
- X
- X panel_set(desc_msg,
- X PANEL_LABEL_STRING, viewopts[count].v_description,
- X NULL);
- X return 0;
- X}
- X
- X#endif /* SUNTOOL */
- X
- X/*
- X * return a string describing a variable.
- X * parameters: count, str, buf.
- X * If str != NULL, check str against ALL variables
- X * in viewopts array. The one that matches, set count to it and
- X * print up all the stuff from the viewopts[count] into the buffer
- X * space in "buf" and return it.
- X */
- Xchar *
- Xvariable_stuff(count, str, buf)
- Xregister char *str, *buf;
- X{
- X if (str)
- X for (count = 0; count < ArraySize(viewopts); count++)
- X if (!strcmp(str, viewopts[count].v_opt))
- X break;
- X if (count >= ArraySize(viewopts)) {
- X (void) sprintf(buf, "%s: Not a default %s variable.",
- X str? str : itoa(count), prog_name);
- X return NULL;
- X }
- X return sprintf(buf, "%s: %s",
- X viewopts[count].v_opt, viewopts[count].v_description);
- X}
- END_OF_FILE
- if test 18292 -ne `wc -c <'mush/viewopts.c'`; then
- echo shar: \"'mush/viewopts.c'\" unpacked with wrong size!
- fi
- # end of 'mush/viewopts.c'
- fi
- echo shar: End of archive 7 \(of 19\).
- cp /dev/null ark7isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 19 archives.
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-
-
-