home *** CD-ROM | disk | FTP | other *** search
- /* hdrs.c (c) copyright 1986 (Dan Heller) */
-
- /* Routines that deal with message headers inside messages */
- #include "mush.h"
-
- /*
- * get which message via the offset and search for the headers which
- * match the string "str". there may be more than one of a field (like Cc:)
- * so get them all and "cat" them together into the static buffer
- * "buf" and return its address.
- */
- char *
- header_field(n, str)
- char *str;
- {
- static char buf[BUFSIZ];
- char tmp[BUFSIZ];
- register char *p, *p2, *b = buf;
- int contd_hdr; /* true if next line is a continuation of the hdr we want */
-
- if (fseek(tmpf, msg[n].m_offset, L_SET) == -1) {
- error("fseek in %s (msg %d, folder=%s)", tempfile, n+1, mailfile);
- turnon(glob_flags, READ_ONLY);
- return NULL;
- }
- *b = 0;
- while((p = fgets(tmp, sizeof(buf), tmpf)) && *p != '\n') {
- if (*p != ' ' && *p != '\t') {
- contd_hdr = 0;
- /* strcmp ignoring case */
- for(p2 = str; *p && *p2 && *p2 == lower(*p); ++p, ++p2);
- /* MATCH is true if p2 is at the end of str and *p is ':' */
- if (*p2 || *p++ != ':')
- continue;
- else
- contd_hdr = 1;
- } else if (!contd_hdr)
- continue;
- skipspaces(0);
- p2 = no_newln(p);
- *++p2 = ' ', *++p2 = 0;
- if (strlen(p) + (b-buf) < sizeof (buf))
- b += Strcpy(b, p);
- }
- if (b > buf) /* now get rid of the trailing blank */
- *--b = 0;
- return (*buf)? buf: NULL;
- }
-
- do_hdrs(argc, argv, list)
- register char **argv, list[];
- {
- register int pageful = 0, fnd;
- int (*oldint)(), (*oldquit)(), show_deleted;
- static int cnt;
- register char *p;
- char first_char = (argc) ? **argv: 'h';
-
- if (argc > 1 && !strcmp(argv[1], "-?"))
- return help(0, "headers", cmd_help);
-
- if (!msg_cnt) {
- if (ison(glob_flags, DO_PIPE))
- return 0;
- #ifdef CURSES
- if (iscurses)
- clear();
- #endif /* CURSES */
- #ifdef SUNTOOL
- if (istool)
- mail_status(0);
- #endif /* SUNTOOL */
- return 0;
- }
- if (first_char == ':' || (argc > 1 && argv[1][0] == ':')) {
- if (first_char != ':')
- argv++;
- return specl_hdrs(argv, list);
- }
-
- on_intr();
-
- if (argc && (argv[0][1] == '+' || argc > 1 && !strcmp(argv[1], "+")) ||
- first_char == 'z' && !argv[1])
- if (msg_cnt > screen)
- cnt = min(msg_cnt - screen, n_array[0] + screen);
- else
- cnt = 0;
- else if (argc && (argv[0][1] == '-' || argc > 1 && !strcmp(argv[1], "-")))
- cnt = max((cnt - 2*screen), 0);
- else if (argc && *++argv &&
- (isdigit(**argv) || **argv == '^' || **argv == '$' || **argv == '.')
- || ison(glob_flags, IS_PIPE)) {
- /* if we're coming from a pipe, start display at the first msg bit
- * set in the msg_list
- */
- if (ison(glob_flags, IS_PIPE)) {
- if (isoff(glob_flags, DO_PIPE))
- for (fnd = 0; fnd < msg_cnt; fnd++)
- if (msg_bit(list, fnd))
- wprint("%s\n", compose_hdr(fnd));
- off_intr();
- return 0;
- }
- /* if a number was given, use it */
- if (!(fnd = chk_msg(*argv))) {
- off_intr();
- return -1;
- }
- for (cnt = fnd - 1; cnt > 0 && cnt + screen > msg_cnt; cnt--);
- } else if (current_msg < n_array[0] || current_msg > n_array[screen-1])
- cnt = current_msg; /* adjust if user reads passed screen bounds */
- else if (cnt >= msg_cnt || !argc || !*argv)
- cnt = max((cnt - screen), 0); /* adjust window to maintian position */
-
- show_deleted = !!do_set(set_options, "show_deleted");
-
- for (;pageful<screen && cnt<msg_cnt && isoff(glob_flags, WAS_INTR); cnt++) {
- if (!iscurses && !show_deleted && first_char == 'h'
- && ison(msg[cnt].m_flags, DELETE))
- continue;
- n_array[pageful++] = cnt;
- /* this message was displayed -- set the bit */
- if (list)
- set_msg_bit(list, cnt);
- /* if do_pipe, don't output anything */
- if (ison(glob_flags, DO_PIPE))
- continue;
- p = compose_hdr(cnt);
- if (!istool && (!iscurses || ison(glob_flags, IS_GETTING)))
- puts(p);
- #ifdef SUNTOOL
- else if (istool) {
- if (cnt == current_msg) /* embolden or reverse_video */
- highlight(hdr_win, 0,pageful*l_height(DEFAULT), DEFAULT,p);
- else
- pw_text(hdr_win, 0, pageful * l_height(DEFAULT), PIX_SRC,
- fonts[DEFAULT], p);
- Clrtoeol(hdr_win, strlen(p)*l_width(DEFAULT),
- pageful*l_height(DEFAULT), DEFAULT);
- }
- #endif /* SUNTOOL */
- #ifdef CURSES
- else if (iscurses)
- mvprintw(pageful, 0, "%-.*s", COLS-2, p), clrtoeol();
- #endif /* CURSES */
- }
- /* just in case a signal stopped us */
- off_intr();
- pageful++;
- #ifdef CURSES
- if (iscurses && pageful < screen)
- move(pageful, 0), clrtobot();
- #endif /* CURSES */
- if (cnt == msg_cnt) {
- while (pageful <= screen) {
- n_array[pageful-1] = msg_cnt+1; /* assign out-of-range values */
- #ifdef SUNTOOL
- if (istool)
- Clrtoeol(hdr_win, 0, pageful * l_height(DEFAULT), DEFAULT);
- #endif /* SUNTOOL */
- ++pageful;
- }
- }
- #ifdef SUNTOOL
- if (istool) {
- if (msg_cnt > screen) {
- panel_set(next_scr, PANEL_SHOW_ITEM, TRUE, 0);
- panel_set(prev_scr, PANEL_SHOW_ITEM, TRUE, 0);
- }
- mail_status(0);
- }
- #endif /* SUNTOOL */
- return 0;
- }
-
- #define NEW 1
- #define ALL 2
-
- specl_hdrs(argv, list)
- char **argv, list[];
- {
- u_long special = 0;
- int n = 0;
-
- while (argv[0][++n])
- switch(argv[0][n]) {
- case 'a': special = ALL;
- when 'n': special = NEW;
- when 'u': special = UNREAD;
- when 'o': special = OLD;
- when 'd': special = DELETE;
- when 'r': special = REPLIED;
- otherwise: print("choose from n,u,o,d,r, or a"); return -1;
- }
- if (debug)
- (void) check_flags(special);
-
- for (n = 0; n < msg_cnt; n++) {
- /*
- * First, see if we're looking for NEW messages.
- * If so, then check to see if the msg is unread and not old.
- * If special > ALL, then special has a mask of bits describing
- * the state of the message.
- */
- if (ison(glob_flags, IS_PIPE)&& !msg_bit(list, n))
- continue;
- if (special == ALL || special == NEW &&
- (ison(msg[n].m_flags, UNREAD) && isoff(msg[n].m_flags, OLD))) {
- if (isoff(glob_flags, DO_PIPE))
- print("%s\n", compose_hdr(n));
- if (list)
- set_msg_bit(list, n);
- #ifndef SYSV
- /*
- * XENIX compiler can't handle "special" in ison() macro.
- * It only works if the second argument is a constant!
- */
- } else if (special > ALL && ison(msg[n].m_flags, special)) {
- if (isoff(glob_flags, DO_PIPE))
- print("%s\n", compose_hdr(n));
- if (list)
- set_msg_bit(list, n);
- #endif /* SYSV */
- } else {
- if (list)
- unset_msg_bit(list, n);
- if (debug) {
- printf("msg[%d].m_flags: %d", n, msg[n].m_flags);
- (void) check_flags(msg[n].m_flags);
- }
- }
- }
- return 0;
- }
-
- #define Strncpy(buf,p) (void) strncpy(buf,p, sizeof(buf)),buf[sizeof(buf)-1]=0
-
- /*
- * compose a header from the information about a message (from, to, date,
- * subject, etc..). The header for message number "cnt" is built and is
- * returned in the static buffer "buf". There will be *at least* 9 chars
- * in the buffer which will be something like: " 123 >N " The breakdown
- * is as follows: 4 chars for the message number, 1 space, 1 char for '>'
- * (if current message) and two spaces for message status (new, unread, etc)
- * followed by 1 terminating space.
- * Read other comments in the routine for more info.
- */
- char *
- compose_hdr(cnt)
- {
- static char buf[256];
- register char *p, *b;
- char from[256], subject[256], date[17], lines[16], chars[16], line[256];
- char to[256], addr[256], name[256], status[2];
- char Day[3], Mon[4], Tm[8], Yr[5], Wkday[4];
-
- /* status of the message */
- if (ison(msg[cnt].m_flags, DELETE))
- status[0] = '*';
- else if (ison(msg[cnt].m_flags, OLD) && ison(msg[cnt].m_flags, UNREAD))
- status[0] = 'U';
- else if (ison(msg[cnt].m_flags, PRESERVE))
- status[0] = 'P';
- else if (isoff(msg[cnt].m_flags, UNREAD))
- status[0] = ' ';
- else
- status[0] = 'N';
-
- if (ison(msg[cnt].m_flags, REPLIED))
- status[1] = 'r';
- else
- status[1] = ' ';
-
- to[0] = from[0] = subject[0] = date[0] = lines[0] = chars[0] = addr[0] =
- name[0] = line[0] = Day[0] = Mon[0] = Tm[0] = Yr[0] = Wkday[0] = 0;
-
- /* who's the message to */
- if ((p = header_field(cnt, "to")) ||
- (p = header_field(cnt, "resent-to")) ||
- (p = header_field(cnt, "apparently-to")))
- Strncpy(to, p);
-
- /* who the messages is from--
- * %f From field
- * %a From address
- * %n From name
- */
- if (!(p = header_field(cnt, "from"))) {
- /* if all else fails, then get the first token in "From" line */
- register char *p2;
- p = ""; /* just in case */
- if (fseek(tmpf, msg[cnt].m_offset, L_SET) == -1 ||
- !(p2 = fgets(line, sizeof(line), tmpf))) {
- error("fseek in %s (msg %d, folder=%s)", tempfile, cnt+1, mailfile);
- turnon(glob_flags, READ_ONLY);
- } else if (!(p = index(p2, ' ')))
- print("Fudged \"From\" line: %s", p2);
- else if (p2 = any(++p, " \t"))
- *p2 = 0;
- }
- skipspaces(0);
- (void) no_newln(p);
- /* if the "from" line produced the user's login name, then the message is
- * from the user -- attempt to give more useful information by telling
- * to whom the message was sent. This is not possible if the "to" header
- * failed to get info (which is probably impossible).
- */
- if (!strcmp(p, login) && *to) {
- (void) strcpy(from, "TO: ");
- (void) strncpy(from+4, to, sizeof(from)-4), from[sizeof(from)-4] = 0;
- (void) get_name_n_addr(from+4, name+4, addr+4);
- if (name[4])
- (void) strncpy(name,"TO: ",4); /* strncpy doesn't null terminate */
- if (addr[4])
- (void) strncpy(addr,"TO: ",4); /* don't overwrite name there */
- } else {
- Strncpy(from, p);
- (void) get_name_n_addr(from, name, addr);
- }
-
- if (p = msg_date(cnt))
- date_to_string(p, Yr, Mon, Day, Wkday, Tm, date);
-
- (void) sprintf(lines, "%d", msg[cnt].m_lines);
- (void) sprintf(chars, "%ld", msg[cnt].m_size);
-
- /* and the subject */
- if (p = header_field(cnt, "subject"))
- Strncpy(subject, p);
-
- /* now, construct a header out of a format string */
- if (!hdr_format)
- hdr_format = DEF_HDR_FMT;
-
- (void) sprintf(buf, "%4.d ", cnt+1);
- b = buf+5;
- *b++ = ((cnt == current_msg && !iscurses)? '>': ' ');
- *b++ = status[0], *b++ = status[1];
- *b++ = ' ';
- /* use the cnt variable to count chars since beginning of buf
- * initialize to 9 (strlen(buf) so far). This magic number is
- * used in other places in msgs.c and mail.c
- */
- cnt = 9;
- for (p = hdr_format; *p; p++)
- if (*p == '\\')
- switch (*++p) {
- case 't':
- while (cnt % 8)
- cnt++, *b++ = ' ';
- when 'n':
- cnt = 1, *b++ = '\n';
- otherwise: cnt++, *b++ = *p;
- }
- else if (*p == '%') {
- char fmt[64];
- register char *p2 = fmt;
- int len, got_dot = FALSE;
-
- *p2++ = '%';
- if (p[1] != '-')
- *p2++ = '-';
- else
- *++p;
- while (isdigit(*++p) || !got_dot && *p == '.') {
- if (*p == '.')
- got_dot = TRUE;
- *p2++ = *p;
- }
- if (!got_dot && isdigit(p[-1])) {
- int val;
- *p2 = 0; /* assure null termination */
- val = atoi(fmt+1);
- p2 += strlen(sprintf(p2, ".%d", (val >= 0 ? val : -val)));
- }
- *p2++ = 's', *p2 = 0;
- switch (*p) {
- case 'f': p2 = from;
- when 'a':
- if (!*(p2 = addr))
- p2 = from;
- when 'n':
- if (!*(p2 = name))
- p2 = from;
- when '%': p2 = "%";
- when 't': p2 = to;
- when 's': p2 = subject;
- when 'l': p2 = lines;
- when 'c': p2 = chars;
- /* date formatting chars */
- when 'd': p2 = date; /* the full date */
- when 'T': p2 = Tm;
- when 'M': p2 = Mon;
- when 'Y': p2 = Yr;
- when 'N': p2 = Day;
- when 'D': p2 = Wkday;
- otherwise: continue; /* unknown formatting char */
- }
- len = strlen(sprintf(b, fmt, p2));
- cnt += len, b += len;
- /* Get around a bug in 5.5 IBM RT which pads with NULL's not ' ' */
- while (cnt && !*(b-1))
- b--, cnt--;
- } else
- cnt++, *b++ = *p;
- for (*b-- = 0; isspace(*b); --b)
- *b = 0;
- return buf;
- }
-
- /*
- * Using message "n", build a list of recipients that you would mail to if
- * you were to reply to this message. If "all" is true, then it will take
- * everyone from the To line in addition to the original sender.
- * fix_address() is caled from mail.c, not from here. There are too many
- * other uses for reply_to to always require reconstruction of return paths.
- * Note that we do NOT deal with Cc paths here either.
- * Check to make sure that we in fact return a legit address (i.e. not blanks
- * or null). If such a case occurs, return login name. Always pad end w/blank.
- */
- char *
- reply_to(n, all, buf)
- register char *buf;
- {
- register char *p = NULL, *p2, *b = buf, *field;
- char line[256];
-
- if (field = do_set(set_options, "reply_to_hdr")) {
- #ifndef MSG_SEPARATOR
- if (!*field)
- goto From; /* special case -- get the colon-less From line */
- #endif /* MSG_SEPARATOR */
- field = lcase_strcpy(line, field);
- while (*field) {
- if (p2 = any(field, " \t,:"))
- *p2 = 0;
- if ((p = header_field(n, field)) || !p2)
- break;
- else {
- field = p2+1;
- while (isspace(*field) || *field == ':' || *field == ',')
- field++;
- }
- }
- if (!p)
- print("Warning: message contains no `reply_to_hdr' headers.\n");
- }
- if (p || (!p && ((p = header_field(n, "from")) ||
- (p = header_field(n, "reply-to")) ||
- (p = header_field(n, "return-path")))))
- skipspaces(0);
- else if (!p) {
- #ifndef MSG_SEPARATOR
- From:
- /* if all else fails, then get the first token in "From" line */
- if (fseek(tmpf, msg[n].m_offset, L_SET) == -1 ||
- !(p2 = fgets(line, sizeof(line), tmpf))) {
- error("fseek in %s (msg %d, folder=%s)", tempfile, n+1, mailfile);
- turnon(glob_flags, READ_ONLY);
- return "";
- }
- p = index(p2, ' ');
- skipspaces(1);
- if (p2 = index(p, ' '))
- *p2 = 0;
- #else /* MSG_SEPARATOR */
- wprint("Warning: unable to find who msg %d is from!\n", n+1);
- #endif /* MSG_SEPARATOR */
- }
- b += Strcpy(buf, p);
-
- /*
- * if `all' is true, append everyone on the "To:" line.
- * cc_to(), called separately, will catch the cc's
- */
- if (all && (p = header_field(n, "to")) && *p) {
- b += Strcpy(b, ", ");
- /* The assumption that BUFSIZ is correct is unwise, but I know it
- * to be true for Mush. Be forewarned if you call this routine.
- */
- (void) strncpy(b, p, BUFSIZ - (b - buf) - 2);
- buf[BUFSIZ-3] = 0;
- }
- fix_up_addr(buf);
- take_me_off(buf);
- for (p = buf; *p == ',' || isspace(*p); p++);
- if (!*p)
- (void) strcpy(buf, login);
- return strcat(buf, " ");
- }
-
- char *
- subject_to(n, buf)
- register char *buf;
- {
- register char *p;
- buf[0] = 0; /* make sure it's already null terminated */
- if (!(p = header_field(n, "subject")))
- return NULL;
- if (strncmp(p, "Re:", 3))
- (void) strcpy(buf, "Re: ");
- return strcat(buf, p);
- }
-
- char *
- cc_to(n, buf)
- register char *buf;
- {
- register char *p;
- buf[0] = 0; /* make sure it's already null terminated */
- if (!(p = header_field(n, "cc")))
- return NULL;
- fix_up_addr(buf);
- take_me_off(p);
- return strcpy(buf, p);
- }
-
- /*
- * fix addresses according to the sender's address. If he's on a remote
- * machine, chances are that the addresses of everyone else he mailed to
- * are addresses from his machine. Reconstruct those addresses to route
- * thru the senders machine first.
- */
- fix_addresses(to, cc)
- char *to, *cc;
- {
- char pre_path[256], addr[256], name[256], buf[BUFSIZ], c, *p2;
- register char *next, *p, *b = buf, *str;
- int pre_len = 0;
-
- pre_path[0] = 0;
- /* Get the address of the sender (which is always listed first) */
- if (!(next = get_name_n_addr(to, name, addr)))
- return;
-
- /* fix up the sender's address; improve_uucp_path to optimize pre_path */
- improve_uucp_paths(addr);
-
- /* if user didn't route via uucp, pre_path will be blank */
- if (p = rindex(addr, '!')) {
- c = *++p, *p = 0;
- (void) strcpy(pre_path, addr); /* the uucp route he used */
- pre_len = strlen(pre_path);
- *p = c;
- Debug("Routing thru \"%s\"\n", pre_path);
- }
-
- b += Strcpy(b, addr);
- if (*name)
- b += strlen(sprintf(b, " (%s)", name));
- while (*next == ',' || isspace(*next)) /* move next to the next address */
- next++;
- if (*next) /* there's more to come on the To line */
- b += Strcpy(b, ", ");
- else {
- (void) strcpy(to, buf);
- if (!cc || !*cc)
- return;
- }
- for (str = next, c = 0; c < 2; str = cc, c++) {
- if (str == cc)
- b = buf;
- *b = 0; /* null terminate beginning in case there's nothing to do */
- if (!str || !*str)
- continue;
- do {
- /* get_name returns a pointer to the next address */
- if (!(p = get_name_n_addr(str, name, addr)))
- break;
- /* check to see if there's enough buffer space to add this addr */
- if ((b - buf) + pre_len + strlen(addr) + strlen(name) + 5 >= BUFSIZ)
- break;
- while (p2 = index(addr, '@'))
- *p2++ = '%'; /* '@' has too high precedence for uucp paths */
- /* don't prepend the sender's path unless required */
- if (pre_len && strncmp(addr, pre_path, pre_len))
- b += Strcpy(b, pre_path);
- b += Strcpy(b, addr);
- if (*name)
- b += strlen(sprintf(b, " (%s)", name));
- while (*p == ',' || isspace(*p))
- p++;
- if (*p)
- b += Strcpy(b, ", ");
- } while (*(str = p));
- for (b--; b > buf && (*b == ',' || isspace(*b)); b--)
- *b = 0;
- improve_uucp_paths(buf);
- if (c == 0)
- (void) strcpy(to, buf);
- else
- (void) strcpy(cc, buf);
- }
- }
-
- /*
- * pass a string describing header like, "Subject: ", current value, and
- * whether or not to prompt for it or to just post the information.
- * If do_prompt is true, "type in" the current value so user can either
- * modify it, erase it, or add to it.
- */
- char *
- set_header(str, curstr, do_prompt)
- register char *str, *curstr;
- {
- static char buf[BUFSIZ];
- int offset = 0;
- register char *p = curstr;
-
- buf[0] = 0;
- wprint(str);
- fflush(stdout); /* force str curstr */
- if (do_prompt) {
- if (curstr)
- for (p = curstr; *p; p++)
- #ifdef SUNTOOL
- if (istool)
- rite(*p); /* mimics typing for the tool */
- else
- #endif /* SUNTOOL */
- if (isoff(glob_flags, ECHO_FLAG))
- fputc((buf[offset++] = *p), stdout);
- else
- #ifdef TIOCSTI
- if (ioctl(0, TIOCSTI, p) == -1) {
- error("ioctl: TIOCSTI");
- wprint("You must retype the entire line.\n%s", str);
- break;
- }
- #else
- {
- wprint("WARNING: -e flag! Type the line over.\n%s", str);
- break;
- }
- #endif /* TIOCSTI */
-
- if (istool)
- return NULL;
- /* simulate the fact that we're getting input for the letter even tho
- * we may not be. set_header is called before IS_GETTING is true,
- * but if we set it to true temporarily, then signals will return to
- * the right place (stop/continue).
- */
- {
- u_long getting = ison(glob_flags, IS_GETTING);
- if (!getting)
- turnon(glob_flags, IS_GETTING);
- if (Getstr(buf, sizeof(buf), offset) == -1)
- buf[0] = 0;
- if (!getting)
- turnoff(glob_flags, IS_GETTING);
- }
- } else
- puts(strcpy(buf, curstr));
- if (debug > 1)
- print("returning (%s) from set_header\n", buf);
- return buf;
- }
-
- /*
- * improve uucp paths by looking at the name of each host listed in the
- * path given.
- * sun!island!pixar!island!argv
- * It's a legal address, but redundant. Also, if we know we talk to particular
- * hosts via uucp, then we can just start with that host and disregard the path
- * preceding it. So, first get the known hosts and save them. Then start
- * at the end of the original path (at the last ! found), and move backwards
- * saving each hostname. If we get to a host that we know about, stop there
- * and use that address. If we get to a host we've already seen, then
- * delete it and all the hosts since then until the first occurance of that
- * hostname. When we get to the beginning, the address will be complete.
- *
- * Return all results into the original buffer passed to us. Since we can
- * at worst not touch the path (shorten it if anything), we know we're not
- * going to overrun the buffer.
- */
- improve_uucp_paths(original)
- register char *original;
- {
- char *hostnames[128];
- char name[BUFSIZ], addr[BUFSIZ], buf[BUFSIZ], *knowns, *end;
- register char *p, *recipient, *start = original, *b = buf;
- int saved_hosts, i;
-
- if (!original || !*original)
- return;
-
- knowns = do_set(set_options, "known_hosts");
-
- while (end = get_name_n_addr(start, name, addr)) {
- saved_hosts = 0;
- /* no uucp path, just user name [@host] with optional name attached */
- if (!(p = rindex(addr, '!'))) {
- char c = *end;
- *end = 0;
- b += Strcpy(b, start); /* copy the entire address with comments */
- *end = c;
- recipient = NULL;
- } else {
- recipient = p+1;
- while (p > addr) {
- /* null the '!' separating the rest of the path from the part
- * of the path preceding it and move p back to the previous
- * '!' (or beginning to addr) for hostname to point to.
- */
- for (*p-- = 0; p > addr && *p != '!'; p--)
- ;
- /* if p is not at the addr, move it forward past the '!' */
- if (p != addr)
- ++p; /* now points to a null terminated hostname */
- #ifndef SYSV
- /* if host is ourselves, ignore this and preceding hosts */
- for (i = 0; i < MAX_HOST_NAMES && ourname[i]; i++)
- if (!lcase_strcmp(p, ourname[i]))
- break;
- if (i < MAX_HOST_NAMES && ourname[i])
- break; /* our own host is not included in the path */
- #endif /* SYSV */
- /* check already saved hostnames. If host is one of them,
- * delete remaining hostnames since there is a redundant path.
- */
- for (i = 0; i < saved_hosts; i++)
- if (!lcase_strcmp(hostnames[i], p))
- saved_hosts = i;
-
- hostnames[saved_hosts++] = p;
- /* If we know that we call this host, break */
- if (p == addr || knowns && chk_two_lists(p, knowns, " ,\t"))
- break;
- --p; /* move p back onto the '!'; it will not equal addr */
- }
- while (saved_hosts-- > 0) {
- b += Strcpy(b, hostnames[saved_hosts]);
- *b++ = '!';
- }
- if (recipient)
- b += Strcpy(b, recipient);
- if (*name)
- b += strlen(sprintf(b, " (%s)", name));
- }
- for (start = end; *start == ',' || isspace(*start); start++)
- ;
- if (!*start)
- break;
- b += Strcpy(b, ", ");
- }
- (void) strcpy(original, buf);
- }
-
- /*
- * rm_cmts_in_addr() removes the comment lines in addresses that result from
- * sendmail or other mailers which append the user's "real name" on the
- * from lines. See get_name_n_addr().
- */
- rm_cmts_in_addr(str)
- register char *str;
- {
- char addr[BUFSIZ], buf[BUFSIZ], *start = str;
- register char *b = buf;
-
- *b = 0;
- do {
- if (!(str = get_name_n_addr(str, NULL, addr)))
- break;
- b += Strcpy(b, addr);
- while (*str == ',' || isspace(*str))
- str++;
- if (*str)
- b += Strcpy(b, ", ");
- } while (*str);
- for (b--; b > start && (*b == ',' || isspace(*b)); b--)
- *b = 0;
- (void) strcpy(start, buf);
- }
-
- /*
- * take_me_off() is intended to search for the user's login name in an
- * address string and remove it. Note that string should be legal addresses
- * only -- no (comments) allowed here. See rm_cmts_in_addr().
- * If "metoo" is set, don't touch addr. This implementation is very bug prone
- * because the user's name may be a hostname or the path specified may
- * be incomplete.
- */
- take_me_off(str)
- char *str;
- {
- int i = 0, rm_me;
- char addr[BUFSIZ], buf[BUFSIZ], *start = str;
- char *Alts;
- register char *p, *b = buf;
-
- if (!str || !*str || do_set(set_options, "metoo"))
- return;
-
- Alts = do_set(set_options, "alternates");
-
- *b = 0;
- do {
- if (!(p = get_name_n_addr(str, NULL, addr)))
- break;
- rm_me = FALSE;
- /* see if user's login is in the address */
- if (!strcmp(login, addr))
- rm_me = TRUE;
- /* if Alts is not set and the above strcmp failed, don't remove him */
- else if (*addr && Alts && *Alts && chk_two_lists(login,addr, "!@%=")) {
- /* To be in this block, there must be a remote address */
- i = 0; /* initialize 'i' in case while loop is skipped */
- #ifndef SYSV
- /* see if the hostnames match our hostname. */
- while (i < MAX_HOST_NAMES && ourname[i])
- if (chk_two_lists(addr, ourname[i++], "!@%="))
- break;
- #endif /* SYSV */
- /* If one of the hostnames in the address is one of user's
- * hostnames, remove this address. If the alternates
- * hostnames listed contains a hostname in the address, remove
- * from the list.
- */
- if (
- #ifndef SYSV
- i < MAX_HOST_NAMES && ourname[i] ||
- #endif /* SYSV */
- *Alts == '*' || !chk_two_lists(addr, Alts, "!@%= \t,"))
- rm_me = TRUE;
- }
- if (!rm_me) {
- char c = *p;
- *p = 0;
- b += Strcpy(b, str);
- *p = c;
- }
- while (*p == ',' || isspace(*p))
- p++;
- if (*p && !rm_me)
- b += Strcpy(b, ", ");
- } while (*(str = p));
- for (b--; b > start && (*b == ',' || isspace(*b)); b--)
- *b = 0;
- (void) strcpy(start, buf);
- }
-
- /*
- * Place commas in between all addresses that don't already have
- * them. Addresses which use comments which are in parens or _not_
- * within angle brackets *must* already have commas around them or
- * you can't determine what is a comment and what is an address.
- */
- fix_up_addr(str)
- register char *str;
- {
- char buf[BUFSIZ], *start = str, c;
- register char *p, *b = buf;
-
- *b = 0;
- do {
- /* get_name returns a pointer to the next address */
- if (!(p = get_name_n_addr(str, NULL, NULL)))
- break;
- c = *p, *p = 0;
- if (strlen(str) + (b - buf) >= BUFSIZ - 2) {
- /* print("Address too long! Lost address: \"%s\"\n", str); */
- *p = c;
- break;
- }
- for (b += Strcpy(b, str); b > buf && isspace(*(b-1)); b--)
- *b = 0;
- for (*p = c; *p == ',' || isspace(*p); p++)
- ;
- if (*p)
- b += Strcpy(b, ", ");
- } while (*(str = p));
- for (b--; b > buf && (*b == ',' || isspace(*b)); b--)
- *b = 0;
- (void) strcpy(start, buf);
- }
-
- /*
- * Get address and name from a string (str) which came from an address header
- * in a message or typed by the user. The string may contain one or more
- * well-formed addresses. Each must be separated by a comma.
- *
- * address, address, address
- * address (comment or name here)
- * comment or name <address>
- * "Comment, even those with comma's!" <address>
- * address (comma, (more parens), etc...)
- *
- * This does *not* handle cases like:
- * comment <address (comment)>
- *
- * find the *first* address here and return a pointer to the end of the
- * address (usually a comma). Return NULL on error: non-matching parens,
- * brackets, quotes...
- */
- char *
- get_name_n_addr(str, name, addr)
- register char *str, *name, *addr;
- {
- register char *p, *p2, *beg_addr = addr, *beg_name = name, c;
-
- if (addr)
- *addr = 0;
- if (name)
- *name = 0;
- if (!str || !*str)
- return NULL;
-
- /* first check to see if there's something to look for */
- if (!(p = any(str, ",(<\""))) {
- /* no comma or indication of a quote character. Find a space and
- * return that. If nothing, the entire string is a complete address
- */
- if (p = any(str, " \t"))
- c = *p, *p = 0;
- if (addr)
- (void) strcpy(addr, str);
- if (p)
- *p = c;
- return p? p : str + strlen(str);
- }
-
- /* comma terminated before any comment stuff. If so, check for whitespace
- * before-hand cuz it's possible that strings aren't comma separated yet
- * and they need to be.
- *
- * address address address, address
- * ^p <- p points here.
- * ^p2 <- should point here.
- */
- if (*p == ',') {
- c = *p, *p = 0;
- if (p2 = any(str, " \t"))
- *p = ',', c = *p2, p = p2;
- if (addr)
- (void) strcpy(addr, str);
- *p = c;
- return p;
- }
-
- /* starting to get hairy -- we found an angle bracket. This means that
- * everything outside of those brackets are comments until we find that
- * all important comma. A comment AFTER the <addr> :
- * <address> John Doe
- * can't call this function recursively or it'll think that "John Doe"
- * is a string with two legal address on it (each name being an address).
- */
- if (*p == '<') { /* note that "str" stil points to comment stuff! */
- if (name && *str) {
- *p = 0;
- name += Strcpy(name, str);
- *p = '<';
- }
- if (!(p2 = index(p+1, '>'))) {
- wprint("Warning! Malformed address: \"%s\"\n", str);
- return NULL;
- }
- if (addr) {
- /* to support <addr (comment)> style addresses, add code here */
- *p2 = 0;
- skipspaces(1);
- addr += Strcpy(addr, p);
- while (addr > beg_addr && isspace(*(addr-1)))
- *--addr = 0;
- *p2 = '>';
- }
- /* take care of the case "... <addr> com (ment)" */
- {
- int p_cnt = 0; /* parenthesis counter */
- p = p2;
- /* don't recurse yet -- scan till null, comma or '<'(add to name) */
- for (p = p2; p[1] && (p_cnt || p[1] != ',' && p[1] != '<'); p++) {
- if (p[1] == '(')
- p_cnt++;
- else if (p[1] == ')')
- p_cnt--;
- if (name)
- *name++ = p[1];
- }
- if (p_cnt) {
- wprint("Warning! Malformed name: \"%s\"\n", name);
- return NULL;
- }
- }
- if (name && name > beg_name) {
- while (isspace(*(name-1)))
- --name;
- *name = 0;
- }
- }
-
- /* this is the worst -- now we have parentheses/quotes. These guys can
- * recurse pretty badly and contain commas within them.
- */
- if (*p == '(' || *p == '"') {
- char *start = p;
- int comment = 1;
- c = *p;
- /* "str" points to address while p points to comments */
- if (addr && *str) {
- *p = 0;
- while (isspace(*str))
- str++;
- addr += Strcpy(addr, str);
- while (addr > beg_addr && isspace(*(addr-1)))
- *--addr = 0;
- *p = c;
- }
- while (comment) {
- if (c == '"' && !(p = index(p+1, '"')) ||
- c == '(' && !(p = any(p+1, "()"))) {
- wprint("Warning! Malformed address: \"%s\"\n", str);
- return NULL;
- }
- if (*p == '(') /* loop again on parenthesis. quote ends loop */
- comment++;
- else
- comment--;
- }
- /* Something like ``Comment (Comment) <addr>''. In this case
- * the name should include both comment parts with the
- * parenthesis. We have to redo addr.
- */
- if ((p2 = any(p+1, "<,")) && *p2 == '<') {
- if (!(p = index(p2, '>'))) {
- wprint("Warning! Malformed address: \"%s\"\n", str);
- return NULL;
- }
- if (addr = beg_addr) { /* reassign addr and compare to null */
- c = *p; *p = 0;
- addr += Strcpy(addr, p2+1);
- while (addr > beg_addr && isspace(*(addr-1)))
- *--addr = 0;
- *p = c;
- }
- if (name) {
- c = *p2; *p2 = 0;
- name += Strcpy(name, str);
- while (name > beg_name && isspace(*(name-1)))
- *--name = 0;
- *p2 = c;
- }
- } else if (name && start[1]) {
- c = *p, *p = 0; /* c may be ')' instead of '(' now */
- name += Strcpy(name, start+1);
- while (name > beg_name && isspace(*(name-1)))
- *--name = 0;
- *p = c;
- }
- }
- skipspaces(1);
- /* this is so common, save time by returning now */
- if (!*p || *p == ',')
- return p;
- return get_name_n_addr(p, name, addr);
- }
-