rsalz@uunet.UU.NET (Rich Salz) (09/21/87)
Submitted-by: island!argv@Sun.COM (Dan Heller) Posting-number: Volume 11, Issue 58 Archive-name: mush5.7/Part08 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 8 (of 12)." # Contents: hdrs.c tool_help PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'hdrs.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'hdrs.c'\" else echo shar: Extracting \"'hdrs.c'\" \(23014 characters\) sed "s/^X//" >'hdrs.c' <<'END_OF_FILE' X/* hdr_procs.c (c) copyright 1986 (Dan Heller) */ X X/* hdrs.h -- routines that look at message headers */ X#include "mush.h" X X/* X * get which message via the offset and search for the headers which X * match the string "str". there may be more than one of a field (like Cc:) X * so get them all and "cat" them together into the static buffer X * "buf" and return its address. X */ Xchar * Xheader_field(n, str) Xchar *str; X{ X static char buf[BUFSIZ]; X char tmp[BUFSIZ]; X register char *p, *p2, *b = buf; X int contd_hdr; /* true if next line is a continuation of the hdr we want */ X X if (fseek(tmpf, msg[n].m_offset, L_SET) != 0) { X error("fseek in %s (msg %d, folder=%s)", tempfile, n+1, mailfile); X turnon(glob_flags, READ_ONLY); X return NULL; X } X *b = 0; X while((p = fgets(tmp, BUFSIZ, tmpf)) && *p != '\n') { X if (*p != ' ' && *p != '\t') { X contd_hdr = 0; X /* strcmp ignoring case */ X for(p2 = str; *p && *p2 && *p2 == lower(*p); ++p, ++p2); X /* MATCH is true if p2 is at the end of str and *p is ':' */ X if (*p2 || *p++ != ':') X continue; X else X contd_hdr = 1; X } else if (!contd_hdr) X continue; X skipspaces(0); X p2 = no_newln(p); X *++p2 = ' ', *++p2 = 0; X b += Strcpy(b, p); X } X if (b > buf) /* now get rid of the trailing blank */ X *--b = 0; X return (*buf)? buf: NULL; X} X Xdo_hdrs(argc, argv, list) Xregister char **argv, list[]; X{ X register int pageful = 0, fnd; X int (*oldint)(), (*oldquit)(), show_deleted; X static int cnt; X register char *p; X char first_char = (argc) ? **argv: 'h'; X X if (!msg_cnt) { X if (isoff(glob_flags, DO_PIPE)) X return; X#ifdef CURSES X if (iscurses) X clear(); X#endif CURSES X#ifdef SUNTOOL X if (istool) X mail_status(0); X#endif SUNTOOL X return 0; X } X if (first_char == ':' || (argc > 1 && argv[1][0] == ':')) { X if (first_char != ':') X argv++; X return specl_hdrs(argv, list); X } X X if (argc > 1 && !strcmp(argv[1], "-?")) X return help(0, "headers", cmd_help); X X on_intr(); X X if (argc && (argv[0][1] == '+' || argc > 1 && !strcmp(argv[1], "+")) || X first_char == 'z' && !argv[1]) X if (msg_cnt > screen) X cnt = min(msg_cnt - screen, n_array[0] + screen); X else X cnt = 0; X else if (argc && (argv[0][1] == '-' || argc > 1 && !strcmp(argv[1], "-"))) X cnt = max((cnt - 2*screen), 0); X else if (argc && *++argv && X (isdigit(**argv) || **argv == '^' || **argv == '$') X || ison(glob_flags, IS_PIPE)) { X /* if we're coming from a pipe, start display at the first msg bit X * set in the msg_list X */ X if (ison(glob_flags, IS_PIPE)) { X if (isoff(glob_flags, DO_PIPE)) X for (fnd = 0; fnd < msg_cnt; fnd++) X if (msg_bit(list, fnd)) X wprint("%s\n", compose_hdr(fnd)); X off_intr(); X return 0; X } X /* if a number was given, use it */ X if (!(fnd = chk_msg(*argv))) { X off_intr(); X return -1; X } X for (cnt = fnd - 1; cnt > 0 && cnt + screen > msg_cnt; cnt--); X } else if (current_msg < n_array[0] || current_msg > n_array[screen-1]) X cnt = current_msg; /* adjust if user reads passed screen bounds */ X else if (cnt >= msg_cnt || !argc || !*argv) X cnt = max((cnt - screen), 0); /* adjust window to maintian position */ X X show_deleted = !!do_set(set_options, "show_deleted"); X X for (;pageful<screen && cnt<msg_cnt && isoff(glob_flags, WAS_INTR); cnt++) { X if (!iscurses && !show_deleted && first_char == 'h' X && ison(msg[cnt].m_flags, DELETE)) X continue; X n_array[pageful++] = cnt; X /* this message was displayed -- set the bit */ X if (list) X set_msg_bit(list, cnt); X /* if do_pipe, don't output anything */ X if (ison(glob_flags, DO_PIPE)) X continue; X p = compose_hdr(cnt); X if (!istool && (!iscurses || ison(glob_flags, IS_GETTING))) X puts(p); X#ifdef SUNTOOL X else if (istool) { X if (cnt == current_msg) /* embolden or reverse_video */ X highlight(hdr_win, 0,pageful*l_height(DEFAULT), DEFAULT,p); X else X pw_text(hdr_win, 0, pageful * l_height(DEFAULT), PIX_SRC, X fonts[DEFAULT], p); X Clrtoeol(hdr_win, strlen(p)*l_width(DEFAULT), X pageful*l_height(DEFAULT), DEFAULT); X } X#endif SUNTOOL X#ifdef CURSES X else if (iscurses) X mvprintw(pageful, 0, "%-*s", COLS-2, p); X#endif CURSES X } X /* just in case a signal stopped us */ X off_intr(); X pageful++; X#ifdef CURSES X if (iscurses && pageful < screen) X move(pageful, 0), clrtobot(); X#endif CURSES X if (cnt == msg_cnt) { X while (pageful <= screen) { X n_array[pageful-1] = msg_cnt+1; /* assign out-of-range values */ X#ifdef SUNTOOL X if (istool) X Clrtoeol(hdr_win, 0, pageful * l_height(DEFAULT), DEFAULT); X#endif SUNTOOL X ++pageful; X } X } X#ifdef SUNTOOL X if (istool) { X if (msg_cnt > screen) { X panel_set(next_scr, PANEL_SHOW_ITEM, TRUE, 0); X panel_set(prev_scr, PANEL_SHOW_ITEM, TRUE, 0); X } X mail_status(0); X } X#endif SUNTOOL X return 0; X} X X#define NEW 1 X#define ALL 2 X Xspecl_hdrs(argv, list) Xchar **argv, list[]; X{ X u_long special = 0; X int n = 0; X X while (argv[0][++n]) X switch(argv[0][n]) { X case 'a': special = ALL; X when 'n': special = NEW; X when 'u': special = UNREAD; X when 'o': special = OLD; X when 'd': special = DELETE; X otherwise: print("choose from n,u,o,d, or a"); return -1; X } X if (debug) X (void) check_flags(special); X X for (n = 0; n < msg_cnt; n++) { X /* X * First, see if we're looking for NEW messages. X * If so, then check to see if the msg is unread and not old. X * If special > ALL, then special has a mask of bits describing X * the state of the message. X */ X if (ison(glob_flags, IS_PIPE)&& !msg_bit(list, n)) X continue; X if (special == ALL || special == NEW && X (ison(msg[n].m_flags, UNREAD) && isoff(msg[n].m_flags, OLD))) { X if (isoff(glob_flags, DO_PIPE)) X print("%s\n", compose_hdr(n)); X if (list) X set_msg_bit(list, n); X#ifndef SYSV X /* X * XENIX compiler can't handle "special" in ison() macro. X * It only works if the second argument is a constant! X */ X } else if (special > ALL && ison(msg[n].m_flags, special)) { X if (isoff(glob_flags, DO_PIPE)) X print("%s\n", compose_hdr(n)); X if (list) X set_msg_bit(list, n); X#endif SYSV X } else { X if (list) X unset_msg_bit(list, n); X Debug("msg[%d].m_flags: %d", n, msg[n].m_flags), X (void) check_flags(msg[n].m_flags); X } X } X return 0; X} X Xchar * Xcompose_hdr(cnt) X{ X static char buf[256]; X register char *p, *b, *status; X char from[256], subject[256], date[17], lines[6], chars[6], line[256]; X char to[512], addr[256], name[256]; X X /* status of the message */ X if (ison(msg[cnt].m_flags, DELETE)) X status = "*"; X else if (ison(msg[cnt].m_flags, OLD) && ison(msg[cnt].m_flags, UNREAD)) X status = "U"; X else if (ison(msg[cnt].m_flags, PRESERVE)) X status = "P"; X else if (isoff(msg[cnt].m_flags, UNREAD)) X status = " "; X else X status = "N"; X X to[0] = from[0] = subject[0] = date[0] = lines[0] = chars[0] = X addr[0] = name[0] = line[0] = 0; X X /* who's the message to */ X if (p = header_field(cnt, "to")) X (void) strcpy(to, p); X X /* who the messages is from-- X %f From field X %a From address X %n From name X X where %a is anything in angle brackets, or if no angle brackets, X anything not in parenthesis, and %n is anything in parenthesis, or if X nothing in parenthesis, anything not in angle brackets. X */ X if (!(p = header_field(cnt, "from"))) { X /* if all else fails, then get the first token in "From" line */ X register char *p2; X p = ""; /* just in case */ X if (fseek(tmpf, msg[cnt].m_offset, L_SET) == -1 || X !(p2 = fgets(line, BUFSIZ, tmpf))) { X error("fseek in %s (msg %d, folder=%s)", tempfile, cnt+1, mailfile); X turnon(glob_flags, READ_ONLY); X } else if (!(p = index(p2, ' '))) X print("Fudged \"From\" line: %s", p2); X else if (p2 = any(++p, " \t")) X *p2 = 0; X } X skipspaces(0); X (void) no_newln(p); X /* if the "from" line produced the user's login name, then the message is X * from the user -- attempt to give more useful information by telling X * to whom the message was sent. This is not possible if the "to" header X * failed to get info (which is probably impossible). X */ X if (!strcmp(p, login) && *to) X (void) sprintf(from, "TO: %s", to); X else X (void) strcpy(from, p); X /* look for < or ( If <, then whatever is inside goes in addr, and X * whatever isn't inside goes in name. If it's a (, then whatever is X * inside goes in name and whatever isn't, goes in addr. It the same X * type of thing, but exclusive of each other. X */ X if (p = any(from, "<(")) { X register char *p2, *out, *in; X if (*p == '<') X out = name, in = addr; X else X out = addr, in = name; X X (void) strcpy(in, p+1); X if (p2 = index(in, (*p == '<')? '>' : ')')) X *p2 = 0; X /* whatever isn't in <'s gets put in "name". Put p at end of name */ X if (p - from > 1) X (void) strncpy(out, from, p - from), p = out+(p-from); X else X p = out; X if (p2) { X /* p2 will be at >, so there will be at least a blank following */ X while (isspace(*++p2)); X /* copy remainder of line onto p (end of name) */ X (void) strcpy(p, p2); X } X } X X (void) sprintf(lines, "%d", msg[cnt].m_lines); X (void) sprintf(chars, "%d", msg[cnt].m_size); X X /* the date */ X if (p = msg_date(cnt)) X (void) strcpy(date, date_to_string(p)); X X /* and the subject */ X if (p = header_field(cnt, "subject")) X (void) strcpy(subject, p); X X /* now, construct a header */ X if (!hdr_format) /* this should NEVER be true, but just in case */ X hdr_format = DEF_HDR_FMT; X X (void) sprintf(buf, "%3.d ", cnt+1); X b = buf+4; X *b++ = ((cnt == current_msg && !iscurses)? '>': ' '); X cnt = 5; X for (p = hdr_format; *p; p++) X if (*p == '\\') X switch (*++p) { X case 't': X while (cnt % 8) X cnt++, *b++ = ' '; X when 'n': X cnt = 1, *b++ = '\n'; X otherwise: cnt++, *b++ = *p; X } X else if (*p == '%') { X int buffer_space = 0; X register char *p2; X X if (isdigit(*++p)) X p = my_atoi(p, &buffer_space); X switch (*p) { X case 'f': p2 = from; X when 'a': X if (!*(p2 = addr)) X p2 = from; X when 'n': X if (!*(p2 = name)) X p2 = from; X when '%': p2 = "%"; X when 't': p2 = to; X when 'd': p2 = date; X when 's': p2 = subject; X when 'l': p2 = lines; X when 'c': p2 = chars; X when 'S': p2 = status; X otherwise: continue; /* unknown formatting char */ X } X if (!buffer_space) X buffer_space = strlen(p2); X (void) sprintf(b, "%-*.*s", buffer_space, buffer_space, p2); X cnt += buffer_space, b += buffer_space; X } else X cnt++, *b++ = *p; X for (*b-- = 0; isspace(*b); --b) X *b = 0; X return buf; X} X X/* X * Using message "n", build a list of recipients that you would mail to if X * you were to reply to this message. If "all" is true, then it will take X * everyone from the To line in addition to the original sender. X * fix_address() is caled from mail.c, not from here. There are too many X * other uses for reply_to to always require reconstruction of return paths. X * Note that we do NOT deal with Cc paths here either. X * Check to make sure that we in fact return a legit address (i.e. not blanks X * or null). If such a case occurs, return login name. Always pad blank at end. X */ Xchar * Xreply_to(n, all, buf) Xregister char *buf; X{ X register char *p = NULL, *p2, *b = buf, *field; X char line[256]; X X if (field = do_set(set_options, "reply_to_hdr")) { X if (!*field) X goto From; /* special case -- get the colon-less From line */ X field = lcase_strcpy(line, field); X while (*field) { X if (p2 = any(field, " \t,:")) X *p2 = 0; X if ((p = header_field(n, field)) || !p2) X break; X else { X field = p2+1; X while (isspace(*field) || *field == ':' || *field == ',') X field++; X } X } X if (!p) X print("Warning: message contains no `reply_to_hdr' headers.\n"); X } X if (p || (!p && ((p = header_field(n, "reply-to")) || X (p = header_field(n, "return-path")) || X (p = header_field(n, "from"))))) { X skipspaces(0); X /* correct reply address is in "<correct-address>" */ X if (p2 = index(p, '<')) { X if (p = index(p2, '>')) X *p = 0; X p = ++p2; X } X } else if (!p) { XFrom: X /* if all else fails, then get the first token in "From" line */ X if (fseek(tmpf, msg[n].m_offset, L_SET) == -1 || X !(p2 = fgets(line, BUFSIZ, tmpf))) { X error("fseek in %s (msg %d, folder=%s)", tempfile, n+1, mailfile); X turnon(glob_flags, READ_ONLY); X return ""; X } X p = index(p2, ' ') + 1; X } X /* find the first space and plug a null */ X if (p2 = any(p, " \t\n")) X *p2 = 0; X b += Strcpy(buf, p); X X /* X * if `all' is true, append everyone on the "To:" line. X * cc_to(), called separately, will catch the cc's X */ X if (all && (p = header_field(n, "to")) && *p) X (void) sprintf(b, " %s", p); X rm_cmts_in_addr(buf); X for (p = buf; isspace(*p); p++); X if (!*p) X (void) strcpy(buf, login); X return strcat(buf, " "); X} X Xchar * Xsubject_to(n, buf) Xregister char *buf; X{ X register char *p; X buf[0] = 0; /* make sure it's already null terminated */ X if (!(p = header_field(n, "subject"))) X return NULL; X if (strncmp(p, "Re:", 3)) X (void) strcpy(buf, "Re: "); X return strcat(buf, p); X} X Xchar * Xcc_to(n, buf) Xregister char *buf; X{ X register char *p; X buf[0] = 0; /* make sure it's already null terminated */ X if (!(p = header_field(n, "cc"))) X return NULL; X rm_cmts_in_addr(p); X return strcpy(buf, p); X} X X/* X * fix addresses according to the sender's address. 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 */ Xfix_addresses(to, cc) Xchar *to, *cc; X{ X int to_argc, cc_argc, cnt; X char **to_argv, **cc_argv, pre_path[128], *p, c; X char **new_to, **new_cc, **calloc(), buf[256]; X X pre_path[0] = 0; X if (!(to_argv = mk_argv(to, &to_argc, 0))) X return; /* what can we do? Just return unchanged To and Cc lists */ X cc_argv = mk_argv(cc, &cc_argc, 0); /* the cc list may be empty */ X if (cc_argc == 0 && to_argc == 1) X return; /* there's only one reciepient, nothing to alter */ X X if (p = any(to_argv[0], "!=")) { X char *p2; X while (p2 = any(++p, "!=")) X p = p2; X c = *p, *p = 0; X (void) strcpy(pre_path, to_argv[0]); X *p = c; X for (cnt = 0; cnt < MAX_HOST_NAMES && ourname[cnt]; cnt++) X if (!strcmp(pre_path, ourname[cnt])) { X *pre_path = 0; X break; X } X } X X if (!(new_to = calloc((unsigned)(to_argc+1), sizeof (char *))) || X !(new_cc = calloc((unsigned)(cc_argc+1), sizeof (char *)))) { X error("malloc in fix_headers"); X return; X } X /* this is the original sender */ X strdup(new_to[0], to_argv[0]); X X /* now modify the addresses to be routed thru the sender's adderess */ X for (cnt = 1; cnt < to_argc; cnt++) { X if (p = index(to_argv[cnt], ',')) X *p = 0; X Debug("Changing \"%s\" to ", to_argv[cnt]); X (void) sprintf(buf, "%s%s", pre_path, to_argv[cnt]); X strdup(new_to[cnt], buf); X Debug("\"%s\"\n", new_to[cnt]); X } X for (cnt = 0; cnt < cc_argc; cnt++) { X Debug("Changing \"%s\" to ", cc_argv[cnt]); X if (p = index(cc_argv[cnt], ',')) X *p = 0; X (void) sprintf(buf, "%s%s", pre_path, cc_argv[cnt]); X strdup(new_cc[cnt], buf); X Debug("\"%s\"\n", new_cc[cnt]); X } X (void) argv_to_string(to, new_to); X (void) argv_to_string(cc, new_cc); X free_vec(to_argv); X free_vec(cc_argv); X free_vec(new_to); X free_vec(new_cc); 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[BUFSIZ]; X int offset = 0; X register char *p = curstr; X X buf[0] = 0; X wprint(str); X fflush(stdout); /* force str curstr */ X if (do_prompt) { X if (curstr) X for (p = curstr; *p; p++) X#ifdef SUNTOOL X if (istool) X rite(*p); /* mimics typing for the tool */ X else X#endif /* SUNTOOL */ X if (isoff(glob_flags, ECHO_FLAG)) X fputc((buf[offset++] = *p), stdout); X else X#ifdef TIOCSTI X if (ioctl(0, TIOCSTI, p) == -1) { X error("ioctl: TIOCSTI"); X wprint("You must retype the entire line.\n%s", str); X break; X } X#else X { X wprint("WARNING: -e flag! Type the line over.\n%s", str); X break; X } X#endif TIOCSTI X X if (istool) X return NULL; X if (Getstr(buf, BUFSIZ, offset) == -1) X buf[0] = 0; 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 * 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. Comments are in parens. X * `take_me_off' takes occurences of login out of a list of recipients X * if the variable "metoo" is set. Some say that "metoo" is supposed to X * pass the -m flag along to sendmail, but not everyone runs sendmail :-) X * X * First expand a possible alias. Note that same string returns if not aliased. X * strip off host from login name (considers user@host, host!user and so on) X * if (user == ourlogin) X * match host with _this_ host, or X * match host with alternate hosts (alternate hostname, * matches all cases) X * if matched, then remove name from list. X * ignore parenthesized names (those are comments ignored by "correct" mailers) X */ Xrm_cmts_in_addr(p) Xregister char *p; X{ X char buf[BUFSIZ], *start = p, *cmnt; X register char **argv; X int cnt, argc, x = 0, take_me_off = !do_set(set_options, "metoo"); X int in_cmnt = FALSE, i; X X if (!(argv = mk_argv(p, &argc, 0))) X return; X for (cnt = 0; cnt < argc; cnt = x+1) { X /* comments are in parens, as in: "argv (Dan Heller)" */ X if ((cmnt = any(argv[cnt], "()")) || in_cmnt) { X x++; X if (cmnt && *cmnt != ')') X in_cmnt = TRUE; X else if (cmnt && *cmnt == ')') X in_cmnt = FALSE; /* else, unchange cmnt flag */ X /* if the previous argument was deleted, then delete this one X * example, we are "user" and our host is "host" take off: X * list ... user@host (firstname lastname) more users... X * "user@host" "(Firstname" "Last name)" X */ X xfree(argv[cnt]), argv[cnt] = ""; X continue; X } X (void) strcpy(buf, argv[x = cnt]); X /* example: "Dan Heller <argv>" -- real address is in angle brackets X * delete the angle brackets. Potential bug: the name is still in X * the address.. result might be: "Dan Heller argv" X */ X if (*buf == '<') { X while (!(p = index(argv[x], '>'))) X if (++x == argc) X break; X else X (void) strcat(buf, argv[x]); X if (!p) /* this one is in error, but parse the rest anyway */ X continue; X if (p = index(buf, '>')) X *p = 0; /* play with buf, not argv[]! */ X } X X /* if we're removing ourselves from the list, see if we're on it */ X if (!take_me_off || !chk_two_lists(login, buf, "!@%=")) X continue; X X /* we must be on the list -- see if the hostnames match alternates X * first match our current host if a host was even given. X * Bug: if a login name is a subset (or a complete) hostname, then X * incorrect results may occur. X */ X if (any(buf, "!@%=")) { X for (i = 0; i < MAX_HOST_NAMES && ourname[i]; i++) X if (chk_two_lists(buf, ourname[i], "!@%=")) X break; X /* If the hostname in the address is one of our hostnames, X * remove this address. Else, see if the alternates hostnames X * are in the address. X */ X if ((i == MAX_HOST_NAMES || !ourname[i]) && X (!(p = do_set(set_options, "alternates")) || *p != '*' && X !chk_two_lists(buf, p, "!@%= \t,"))) X continue; X } X /* all's well that ends well -- take us off the list */ X xfree(argv[cnt]), argv[cnt] = ""; X } X (void) argv_to_string(start, argv); X free_vec(argv); 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 X * rest of the line. 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 we get to a host we've already seen, then X * delete it and all the hosts since then until the first occurance of that X * hostname. When we get to the beginning, the address will be complete. X * X * return all results into the original buffer passed to us. Since we can X * at worst not touch the path (shorten it if anything), we know we're not X * going to overrun the buffer. X */ X X#define go_back_to_bang() for (--p; p > start && *p != '!'; p--) X Ximprove_uucp_paths(original) Xregister char *original; X{ X char hostnames[32][64], buf[BUFSIZ], *knowns, *end; X register char *p, *recipient, *start = original, *b = buf, c; X int saved_hosts, i; X X if (!original || !*original) X return; X X knowns = do_set(set_options, "known_hosts"); X X while ((end = any(start, " \t,")) || *start) { X saved_hosts = 0; X if (!end) X p = start + strlen(start); X else X p = end; /* set p to the "end" cuz p moves. start will equal end */ X c = *p, *p = 0; /* save the char we're nulling out (separating addrs) */ X go_back_to_bang(); X if (p == start) X b += Strcpy(b, start), recipient = NULL; X else { X recipient = p+1; X while (p > start) { X /* null remainder of string to save the hostname */ X *p = 0; X go_back_to_bang(); X /* if p is not at the start, move it forward past the '!' */ X if (p != start) X ++p; X#ifndef SYSV X /* next host on the list is ourselves, ignore preceding names */ X for (i = 0; i < MAX_HOST_NAMES && ourname[i]; i++) X if (!strcmp(p, ourname[i])) X saved_hosts = 0; X#endif SYSV X for (i = 0; i < saved_hosts; i++) X if (!strcmp(hostnames[i], p)) X saved_hosts = i; X (void) strcpy(hostnames[saved_hosts++], p); X if (saved_hosts == 32) { X print("Too many hosts in uucp path! Address not fixed.\n"); X return; /* original buffer is unchanged */ X } X /* If we know that we call this host, break */ X if (p == start || knowns && chk_two_lists(p, knowns, " ,\t")) X break; X --p; /* move p back onto the '!'; it != start */ X } X } X while (saved_hosts-- > 0) X b += strlen(sprintf(b, "%s!", hostnames[saved_hosts])); X if (recipient) { X /* if there were no saved_hosts, add a ! */ X if (*(b-1) != '!') X *b++ = '!'; X b += Strcpy(b, recipient); X } X *b++ = c; X if (!end) X break; X start = end + 1; X if (isspace(*start)) { X *b++ = ' '; X while (isspace(*start)) X start++; X } X } X *b = 0; X (void) strcpy(original, buf); X} END_OF_FILE if test 23014 -ne `wc -c <'hdrs.c'`; then echo shar: \"'hdrs.c'\" unpacked with wrong size! fi # end of 'hdrs.c' fi if test -f 'tool_help' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'tool_help'\" else echo shar: Extracting \"'tool_help'\" \(23232 characters\) sed "s/^X//" >'tool_help' <<'END_OF_FILE' X@(#)tool_help (c) copyright 10/18/86 (Dan Heller) X X%general% X X IF ALL ELSE FAILS, READ THE DIRECTIONS! X XThis famous quote applies here more than ever. If Xyou are unfamiliar with this mailtool, get yourself Xacquainted with it by choosing HELP options in all Xmenu items. If you get frustrated or confused about Xhow to use or run a command, or if you want to know Xhow something works or get to know quick shortcuts Xin achieving tasks, it is advisable to look at the XHelp option available with the item. X XSince there are many different options to some of Xthe commands in mailtool, explanation of options Xfor the commands can be found by choosing the RIGHT Xmouse button over an item. This will display a menu Xof options for the command. One of the menu options Xwill almost always be a Help option. X XGive yourself a head start, try selecting this same Xitem with the RIGHT mouse button. When you do, you Xwill given some more help topics to choose from. X%% X X%help% XHelp was designed for users to get help from anywhere on the mailtool Xwindow. The RIGHT mouse button may be selected on virtually every - X on any of the windows on the entire tool and a menu will appear. XThe last item in almost every menu is a "help" item. You will get an Xappropriate help message describing what you can do at the position you Xare in on the mailtool window. X XIf a help message isn't much help, it may be more helpful to reference Xa different help item which describes in more detail what you want to Xknow. For example, reading the help for "folder" will help you better Xunderstand the method in which mail messages are stored than it would Xif you had read the help message for "save" first. X%% X X%mouse% XThe mouse is an image (cursor) which moves across the screen. Its Xposition indicates which window is to receive input when you type Xor click a mouse button. X XThe mouse may take upon different images which indicate various Xthings. When the image looks like a "coffee cup", Mushtool is in Xthe process of doing something, like sending mail, or reading in Xnew mail. In this event, you should wait till the cursor returns Xto its normal state before attempting to do anything else. Go get Xsome coffee. X XWhen the mouse looks like a pair of glasses, you are reading mail Xand when it looks like a pencil, you are editing a letter. When Xin the Header Window, the cursor will look like the mouse device Xthat you hold with the buttons flashing on and off. This is to Xremind you that you can use each button to do different tasks. X XIn one window, the Main Panel Window, the cursor image looks like Xan envelope. Placing the cursor over "Panel Items" and selecting Xthe LEFT button will do that command. Selecting the RIGHT mouse Xbutton will give a menu of options to choose from. In most cases, XHelp is available and the end of each menu list to help you with Xthe proper use of Panel Items. X XWhen you are asked a yes or no question, choosing either the LEFT Xor RIGHT mouse buttons is the same as typing "y" or "n". X%% X X%respond% XThis item responds to mail in 4 ways. XIn all cases, at least one recipient of your message will be the Xsender of the message you are responding to. If a subject was in Xthe author's letter, then it will be used as your subject. X XThe first and most used method of response is to the author of the Xmessage only. Selecting this item with the LEFT mouse button will Xuse this method for responding to mail. X XIf you want to include a copy of the author's message, then choose Xthe menu item which says to include the message. If you wish for Xall the recipients of the message to receive a copy of your reply, Xthen choosing the third item will include them. X XThe fourth menu item will mail to the author and everyone listed on Xthe To and Cc lines of the message, and include the message you are Xresponding to in your text. X XIn such cases where you include the message you are responding to, Xthe included message will be indented by "> " to identify it from Xyour message. If you would like to have a string other than the Xdefault used, then set the appropriate option to whatever you would Xprefer by selecting the "Opts" item, moving the mouse on top of the Xstring, "indent-str", selecting the LEFT mouse button and typing the Xdesired string. X%% X X%menu_respond% XWhen you respond to a message using the menu item, you respond to the author Xof the message only. Since there are more ways to respond to a message, you Xmay want to choose the Main Panel Window's Reply item. This item also gives Xfar more extensive help than described here. X%% X X%menu_delete% XThis menu may delete or undelete Xwhichever message you happen to Xhave the cursor sitting on. For Xdeleting messages only, you can Xsimply select the MIDDLE mouse Xbutton over the message header Xyou would like deleted. X XFor extensive information on - X or undeletion of messages Xtry the the Main Panel Window's Xitem for Delete. X%% X X%delete% XYou may delete or undelete messages with this item. XWhen using the LEFT mouse button, you will delete the Xcurrent message (HIGHLIGHTED in the headers' window). XOtherwise, you may delete or undelete all messages by Xselecting the appropriate menu item. X XYou may delete or undelete a "range" of messages by Xtyping the range in the Header Window and selecting Xthe appropriate menu item (delete/undelete range). X XFor help on valid message ranges, select the menu in Xthe area marked "range" in the Header Panel Window. X%% X X%folder% XThis item changes your "folder" -- which is a place to keep all your Xindividual messages. Usually, if you are a heavy mail user, you would Xorganize your mail in such a way in which related mail would be saved Xtogether in one folder. You create folders simply by saving mail to Xa filename. Additional mail can be saved to those files in the same Xway. To manipulate messages in folders, you "change folders" to the Xfolder you wish to access using the folder item. Since it may occur Xthat you switch back and forth between two folders, you may use the Xprevious folder menu item which updates changes made to the current Xfolder and changes your folder to the one previous to the current. X XYou may also select the exact name of the folder you wish to access Xby selecting the left mouse button on the "folder" item and TYPING Xthe exact name of the folder you wish to access. The "pathname" to Xthe folder may start with a tilde (~) indicating your home directory. XOr, it may contain a plus sign before the name indicating your Mail Xdirectory (+reports, for example). Alternatively, you can type '%' Xto access your system Mailbox, the place where all your mail is first Xdelivered. And finally, you can type '#' to indicate the previously Xaccessed folder. See the help for "chdir" for more information. X%% X X%chdir% XThis is used to just change working directories. XYour working directory contains files and other Xdirectories. Files can be "mail folders" which Xcontain mail messages. You can change to other Xdirectories using some of the following methods: X XYou can select from the menu, HOME or Mail, which Xare your home and default mail directories. Or, Xselect the left mouse button and TYPE in the name Xof the directory you would like to change to. X XTyped names may have the following syntax: X X~[/subpath] will change to your home directory and X a path below that, if specified. Also, X you can specify other users: ~username X+[subpath] This is your default Mail directory. X%% X X%save% XYou may save messages in two ways. The most commonly used method is to Xsave messages to your mailbox folder ("mbox") in your home directory. XIf you use mail very frequently and save large amounts of mail, you can Xsave messages to other folders for better organization. X XUsually, when messages are saved, mailtool marks them for deletion for Xthe next update. If you don't want to have saved messages deleted, you Xmust undelete them. X XThere is a text item in the Main Panel Window which allows you to type Xthe name of the file to save a message. Select the LEFT mouse button Xover the "Save" item, and type the filename and hit return. If there is Xno filename specified, then messages are saved to your mbox file. X XYou can specify a range, or group of messages to save by typing a range Xin the Header Panel Window. X XFor additional information, see the help option for Folders. X%% X X%quit% XThere are various ways in which you may be finished with mailtool. XThe most commonly used method is to simply "close" the tool to an Xiconic form. This means that you haven't really quit, but you have Xmerely put it on "hold" till later. It will become an icon on the Xside or corner of the screen and appear to sit and do nothing. To Xclose the tool to icon form, there are two methods which have will Xhave two different effects. X XThe first method is to select this panel item with the left mouse Xbutton. This will update your current folder (deleting messages Xmarked for deletion) and close the tool. The second method is to Xuse the tool manager around the perimeter of the window and select X"close". This will close the tool without updating your mailfile. X XWhenever the mailtool is in the "closed" state, it periodically Xchecks your mail and updates your folder with the new mail. While Xmailtool is in iconic form, it will display the number of messages Xyou have in the current folder. X XThere are two equally similar methods of exiting mailtool, rather Xthan just closing to an icon: you may select the second menu item Xin the menu given by this panel item or you may use the tool mana- X "quit" item. X XUsing the tool manager's quit will exit the tool without updating Xyour folder whereas the panel item's menu selection will have the Xmailtool prompt you whether to update the current folder or not. X%% X X%help_menu_help_msg% XSelecting an item within this menu will Xgive you help on that item. If you want Xto execute the action, choose the other Xmenu by placing the mouse over the menu XBEHIND this menu, continue to keep your XRIGHT mouse button depressed and select Xthe LEFT mouse button over the menu on Xthe bottom and select that action. X%% X X%msg_menu% XWhen given menu in the Header Window, you will have a choice Xof actions to take. The message may not be the current one, Xit may be any message that appears in the Headers Window. XThe "title" of the menu will indicate which message you are Xreferring to. X XAt this point, you can select actions to take. You can Read, XDelete, Undelete, Save, Reply to, or Print messages. Most of Xthese are self explanatory, but if you need help with one of Xthese, place the mouse over the menu BEHIND the given menu, Xcontinue to have the RIGHT mouse button depressed and select Xthe LEFT mouse button over the Help Menu. X XThis action toggles the menus such that you can change back Xand forth between these menus. The menu you are on will tell Xwhich action to take on that message. In either case, you Xplace the mouse over the action to take, and, if you are on Xthe help menu, help will be given regarding that particular Xaction. If not in the help menu, then that specific action Xwill actually be taken. X%% X X%edit% XChoosing this item with the LEFT mouse button in Xthe Main Panel Window or in the Menu item will Xallow you to access a full-screen editor. The Xeditor which you will use is indicated when you Xselect the "opts" item in the Main Panel Window. X XWhile you are typing a letter, you can specify Xexplicitly which editor to use by typing (on a Xline by itself) "~v editor". Type "~?" on a line Xby itself while typing to see a list of valid X"~commands". X XUpon exiting the editor, you can continue typing Xand even reenter the editor if you like in the Xsame manner. X%% X X%update% XThis item will update the current folder you are using. XChanges are updated to the folder; that is, deleted mail Xis removed and all other mail is copied back to the folder Xunless otherwise specified. See the help in "folder" for Xmore information on folders. X XIf new mail has arrived, it will incorporate it. Otherwise, Xnew mail is incorporated every two minutes or so, if some Xcomes in. X%% X X%headers% XThe message headers are displayed in their own separate window. XThe "current" message is usually displayed in either BOLD or XREVERSE text. This "highlighted" message is the one which is Xdisplayed at the bottom, larger window. In the message window, Xeach message is displayed in the following format: Xthe message number is displayed first; if it is the "current" Xmessage, then there is a '>' sign. XThe next character is the 'status' character: X 'N' -- New (and unread) X 'U' -- not new, but still Unread X '*' -- delete messages (set show_deleted) X 'P' -- preserve in spoolfile. X 'O' -- Old message which has also been Read. XIf there is just a space (no character), the message is new, but Xyou've already read it. You should explicitly save or delete these. X XFollowing that is the Author of the message and/or all or part of Xhis network address and login name. Following that is the number Xof lines the message is. In quotes is all or part of the "Subject" X(if one was specified). X XTo read a message, select either the READ item in the main panel Xsubwindow or move the mouse over the message header you want to read Xand press the LEFT mouse button. Or, the MIDDLE mouse button will Xdelete that message. Choosing the RIGHT mouse button will give you Xa menu of things to do then. Included in the menu, is a help item Xwhich describes the selections in the menu. X%% X X%preserve% XUsually, after you read mail and you "update" or quit mailtool, unread Xmessages are copied back into your system mailbox, deleted messages are Xremoved, and messages which have been read but not deleted are saved in Xyour "mbox" file. Specifying "hold" prevents this from ever happening, Xbut you can mark specific messages to be held in your system mailbox by Xpreserving them. X%% X X%compose% XWhen you start to compose a letter for mailing, Xyou will be prompted for the login name(s), of Xwhom you want to mail, the (optional) subject Xof the message, and an optional list of carbon Xcopy recipients. This is an additional list of Xlogin names who will be mailed copies of your Xmessage. X XAfter that, anything you type will be added to Xyour message. If you select the RIGHT mouse Xbutton in the window in which you are type to Xget a menu of things to do. You may enter an Xeditor if your message needs to be modified in Xmore detail. X XWhen you're through with your message, you can Xsend it by typing (on a line by itself) "." or X^D. Or, you can select the Send item in the XMain Panel Window and your mail will be sent. XYou cannot send mail while still in an editor; Xyou must exit the editor first. X XIf you have the option "autoedit" set, you are Xautomatically put into an editor when you want Xto compose or whenever you reply to a letter. XIn this case, whenever you're through editing Xthe letter, you will be put back into the main Xediting mode where you terminate and send the Xletter using any of the above methods. X%% X X%next% XYou can page through all your messages by selecting "Next" after reading Xeach message. The same effect is gotten when you select the "Delete" item Xwhen the option, "autoprint" is set to be true (see "opts") except that Xthe current message is deleted before the next one is displayed. Deleting Xmail which is not important helps the efficiency of mailtool and reduces Xunnecessary use of system resources. X XIn the Header Window, you will notice the cursor looks like the mouse you Xuse. The blinking buttons on the mouse image remind you that you can use Xany of the three buttons at any time. When you move the mouse over a Xmessage and choose a button, the message under the mouse is going to be Xthe one affected. Choosing left button will read the message, the middle Xbutton will delete it, and the right button will give you a menu. X%% X X%aliases% XAliases are used as a method of mailing to users with long addresses using Xshort names. For example, if you wanted to mail to X argv@spam.istc.sri.com Xbut didn't want to type that all the time, then you could make an alias by Xselecting the alias menu item that specifies "adding alias" and then TYPE: X Dan argv@spam.istc.sri.com XIf you want to mail to a list of people and do so frequently enough to want Xan alias name for the whole list, then you would type something like this: X project-group fred mary bob@foo-bar herb sly@baz.bitnet X XTo mail to an "alias" you would compose a letter and address the letter: X XTo: Dan XSubject: Alias example XCc: project-group X(rest of letter) X%% X X%alts% X"Alternates" are alternate names for YOU. In messages you Xreceive, your account will appear on the "To" or "Cc" list. XWhen you REPLY to those messages, mailtool will construct Xa message header for your letter which will contain the To Xand Cc lists of recipients from the original message. You Xwould probably want your name taken off the list so you do Xnot mail yourself a copy of your own message. If you have Xother account names or accounts on other machines, you can Xlet mailtool know what those mail addresses are so they can Xbe removed from the lists as well. X XNote, that if YOU add your name MANUALLY (type it yourself) Xto either of the lists, it will not be removed. X XYou can set such a list in your .mailrc file in your home Xdirectory by adding the line: X Xalts hostname1 hostname2 ... X XIf you prefer to not have your name removed from lists when Xresponding to mail, set the option "metoo" and this prevents Xthe need for alternates and your name will never be removed. X%% X X%opts% XTo set or unset options and their values, move the mouse over Xthe option of your choice and select the LEFT button to toggle Xtrue/false values. If an option requires a string value, you Xmust type the value, so select the LEFT button to reference Xthe option, and then type away. Use a Carriage Return to enter Xthe final value for the option. X XYou may select the RIGHT mouse button anywhere in the window Xto give a menu which consists of saving options permanently, Xreading in previous settings (from ~/.mailrc), and other things. X%% X X%ignore% XWhen reading mail, the message "headers" may clutter up the Xwindow with information you are not interested in. For Xexample, you may not be interested in the "Received" or X"Message-Id" field of the mail message. You would find that Xin time, it will become annoying to see these uninteresting Xmessage headers. X XYou can specify which message headers should not be shown, Xthus shortening the appearance of the length of the message. X XTypical settings: X Received X Message-Id X Status X%% X X%printer% XThis item will send the current message, or the message specified on the Xmenu header, to the printer. The printer used is given by the "printer" Xoption (see opts in Main Panel Window). To specify a different printer, Xchange the printer option by selecting the item "Opts" in the Main Panel XWindow, moving the mouse over the Printer option, selecting the LEFT Xmouse button and typing the name of the printer which you'd like to use. X XBe sure to set this option before printing because the DEFAULT option may Xnot be what you want. X XYou can print messages that are NOT the current message by moving the Xmouse into the Header Window and selecting the RIGHT mouse button on top Xof the message you want to print and selecting the PRINT menu option. X%% X X%windows% X"Windows" are the boxes which contain items, text, or graphic Ximages. There are two "panel" windows. A panel window is one Xwhich contains items, which are the little boxes with words Xthat you can place the mouse over and click the left or mouse Xbutton. X XEach window has a separate function for different purposes. XStarting at the top of the main "tool" (contains all windows) Xwe have the "header panel." Everything in this panel pertains Xto the message headers, only. The panel in the middle of the Xtool is the "mail panel" which is more general and applies to Xjust about everything. For a description of each of the items Xwithin any panel, select the "Help" option from the menu Xyou get by selecting the RIGHT mouse button. X%% X X%options% XMove the cursor over the option you wish to change. XThe LEFT mouse button turns toggles values off and on. XThe MIDDLE mouse button displays the meaning of a Xvariable. If the option needs typed input, use the LEFT Xmouse button. Sometimes value can be both toggle and Xstring values so you may have to click the left button Xmore than once to type. When entering text values, you Xmust use RETURN, so the value you typed will be associated Xwith the option specified. Unsetting the option will - Xassociate the a string value with that option. X XOnce values are disassociated with options, they can Xonly be retrieved by either reentering their values or Xby selecting the "restore options" item in the menu. XDoing so will read in the last copy of the saved options Xfrom your .mailrc file. X XSelecting the Save option in the menu will save the Xcurrent settings in ~/.mailrc. Selecting the quit Xoption in the menu does NOT imply that values are Xsaved permanently; changed values will remain through- Xout the rest of the mail session. To save options more Xpermanently, select the save menu item. X%% X X%function keys% XSelecting the panel item "Opts" with the MENU button will give you Xa choice of the type of options you can set. If you choose the one Xthat says "function keys", then you can edit the commands that the Xfunction keys on the keyboard may execute. Once in this mode, you Xwill find more extensive help. X%% X X%fkeys% XUsually the LAST function key in each set (top, left, Xand right set of keys) will display the current settings Xof all they keys. The command which does this is X`key_settings X' where X is L, R, or T (left right top) Xreferencing the associated function keys. To set a function Xkey to a specific command or set of commands, place the mouse Xover the icon image of the key on the screen and click the Xleft mouse button. Type a command from the list of commands Xat the bottom of the window and enter RETURN. X XMany commands take arguments or flags, so be sure to enter Xthem here if you want those options. Clicking the middle button Xwill display the current value for that key. If you want to Xset a key for multiple commands, separate the commands with Xsemicolons: X XL9: update ; close X XThis example would update your mailbox (committing changes) Xand close the tool to an icon. X%% X X%message range% XYou can specify a large group of messages using a combination of special Xsymbols in addition to numbers. For example, if you wish to save all of Xthe messages, then you can use `*' to represent them all. If you were to Xtype the "star" and select the Save menu option for "save range", then Xyou would save ALL the messages you have (including deleted ones). X XIf you would like to save messages 4 through 9, then you would specify: X4-9 XIf you want to specify the messages between 2 and 32 except for messages X6, 8 and message 12-14, you would type: X2-32 {6,8,12-14} XCommas or spaces can be used to separate numbers. X XNote that you cannot specify negated messages without first specifying Xnormal messages; e.g. {2-5} 1-11 doesn't make sense. X%% END_OF_FILE if test 23232 -ne `wc -c <'tool_help'`; then echo shar: \"'tool_help'\" unpacked with wrong size! fi # end of 'tool_help' fi echo shar: End of archive 8 \(of 12\). cp /dev/null ark8isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 12 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 12 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