home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume18
/
mush6.4
/
part09
/
hdrs.c
< prev
Wrap
C/C++ Source or Header
|
1989-03-12
|
19KB
|
632 lines
/* hdrs.c (c) copyright 1986 (Dan Heller) */
/*
* Routines that deal with message headers inside messages
* msg_get(n, from, count) -- get the From_ line in msg n into "from".
* header_field(n, str) -- get the header named "str" from msg n.
* do_hdrs(argc, argv, list) -- diplay message headers.
* specl_hdrs(argv, list) -- display msgs that share common attributes.
* compose_hdr(cnt) -- compose a message header from msg n.
* reply_to(n, all, buf) -- construct a header based on the To: header of n.
* subject_to(n, buf) -- get the subject for replying to msg n.
* cc_to(n, buf) -- construct a Cc header based on the Cc of message n.
*/
#include "mush.h"
/*
* Get a message from the current folder by its offset.
* Copy the From_ line to the second argument if the third arg > 0,
* and return the second argument, or NULL on an error.
*/
char *
msg_get(n, from, count)
int n, count;
char *from;
{
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;
}
if (count)
#ifndef MSG_SEPARATOR
return fgets(from, count, tmpf);
#else
*from = '\0';
#endif
return from;
}
/*
* 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[HDRSIZ];
char tmp[HDRSIZ];
register char *p, *p2, *b = buf;
int contd_hdr; /* true if next line is a continuation of the hdr we want */
if (!msg_get(n, tmp, sizeof tmp))
return NULL;
*b = 0;
while((p = fgets(tmp, sizeof(tmp), 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 = ' ', *++p2 = 0;
if (strlen(p) + (b-buf) < sizeof (buf))
b += Strcpy(b, p);
}
if (b > buf) /* now get rid of the trailing ", " */
*--b = 0, *--b = 0;
return (*buf)? buf: NULL;
}
do_hdrs(argc, argv, list)
register char **argv, list[];
{
register int pageful = 0;
SIGRET (*oldint)(), (*oldquit)();
int 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
*/
int fnd;
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 reads have passed screen bounds */
else if (cnt >= msg_cnt || !argc || !*argv)
cnt = max((cnt - screen), 0); /* adjust window to maintain position */
show_deleted = !!do_set(set_options, "show_deleted");
/* Make sure we have at least $screen headers to print */
if (cnt > 0 && !iscurses && !show_deleted && first_char != 'h') {
int tmp = cnt;
/* first count how many messages we can print without adjusting */
for (pageful = 0; pageful < screen && cnt < msg_cnt; cnt++)
if (isoff(msg[cnt].m_flags, DELETE))
pageful++;
/* if we can't print a pagefull of hdrs, back up till we can */
for (cnt = tmp; pageful < screen && cnt; --cnt)
if (isoff(msg[cnt].m_flags, DELETE))
pageful++;
pageful = 0; /* Used later as an index, so reset */
}
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) {
move(pageful, 0);
printw("%-.*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;
when 's': special = SAVED;
when 'p': special = PRESERVE;
otherwise: print("choose from n,u,o,d,r,s,p 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 M_XENIX
/*
* 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 /* M_XENIX */
} 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, *p2, *b;
int len, do_pad = FALSE, val, pad, got_dot, isauthor = 0, n;
char from[HDRSIZ], subject[256], date[64], lines[16];
char to[256], addr[256], name[256], status[4];
char Day[3], Mon[4], Tm[8], Yr[5], Wkday[4], *date_p;
/* status of the message */
if (ison(msg[cnt].m_flags, DELETE))
status[0] = '*';
else if (ison(msg[cnt].m_flags, PRESERVE))
status[0] = 'P';
else if (ison(msg[cnt].m_flags, SAVED))
status[0] = 'S';
else if (ison(msg[cnt].m_flags, OLD) && ison(msg[cnt].m_flags, UNREAD))
status[0] = 'U';
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] = addr[0] =
name[0] = Day[0] = Mon[0] = Tm[0] = Yr[0] = Wkday[0] = 0;
/* who's the message to */
if ((p = header_field(cnt, "resent-to")) ||
(p = header_field(cnt, "to")) ||
(p = header_field(cnt, "apparently-to")))
Strncpy(to, p);
/* who's the message from */
if ((p = header_field(cnt, "from")) && strcpy(from, p)
|| (p = reply_to(cnt, 0, from))) {
/* NOTE: this fails if the sender has '<' or '!' in
* the RFC822 comment fields -- leading "comment"
* or trailing (comment) -- but that isn't critical
*/
if ((p2 = rindex(p, '!')) || (p2 = index(p, '<')))
p = p2 + 1;
} else
p = strcpy(from, "unknown"); /* just in case */
/* If the From field contains 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 (!strncmp(p, login, strlen(login))) {
isauthor = TRUE;
(void) get_name_n_addr(to, name+4, addr+4);
if (addr[4])
(void) strncpy(addr, "TO: ", 4);
if (name[4]) { /* check to see if a name got added */
(void) strncpy(name, "TO: ", 4);
Strncpy(from, name);
} else
Strncpy(from, addr);
} else
(void) get_name_n_addr(from, name, addr);
if (ison(glob_flags, DATE_RECV))
date_p = msg[cnt].m_date_recv;
else
date_p = msg[cnt].m_date_sent;
date_to_string(date_p, Yr, Mon, Day, Wkday, Tm, date);
/* 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++ = ' ';
/* 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
*/
n = 9;
for (p = hdr_format; *p; p++)
if (*p == '\\')
switch (*++p) {
case 't':
while (n % 8)
n++, *b++ = ' ';
when 'n':
n = 1, *b++ = '\n';
otherwise: n++, *b++ = *p;
}
else if (*p == '%') {
char fmt[64];
p2 = fmt;
/* first check for string padding: %5n, %.4a, %10.5f, %-.3l etc. */
do_pad = pad = val = got_dot = 0;
*p2++ = '%';
if (p[1] != '-')
*p2++ = '-';
else
++p;
while (isdigit(*++p) || !got_dot && *p == '.') {
if (*p == '.')
got_dot = TRUE, val = pad, pad = 0;
else
pad = pad * 10 + *p - '0';
*p2++ = *p;
}
if (!got_dot && isdigit(p[-1])) {
*p2 = 0; /* assure null termination */
val = atoi(fmt+1);
if (val < 0)
val = -val;
p2 += strlen(sprintf(p2, ".%d", val));
}
pad = min(pad, val);
*p2++ = 's', *p2 = 0;
switch (*p) {
case 'f': p2 = from, do_pad = TRUE;
when 'a':
if (!*(p2 = addr))
p2 = from;
do_pad = TRUE;
when 'n':
if (!*(p2 = name))
p2 = from, do_pad = TRUE;
when '%': p2 = "%";
when 't': p2 = to;
when 's': p2 = subject;
when 'l': p2 = sprintf(lines, "%d", msg[cnt].m_lines);
when 'c': p2 = sprintf(lines, "%ld", msg[cnt].m_size);
when 'i': p2 = header_field(cnt, "message-id");
/* date formatting chars */
when 'd': p2 = date; /* the full date */
when 'T': p2 = Tm;
when 'M': p2 = Mon;
when 'Y': p2 = Yr;
when 'y': p2 = Yr+2;
when 'N': p2 = Day;
when 'D': case 'W': p2 = Wkday;
otherwise: continue; /* unknown formatting char */
}
if (do_pad && pad && strlen(p2) > pad) {
char *old_p2 = p2, *p3;
/* if addr is too long, move pointer forward till the
* "important" part is readable only for ! paths/addresses.
*/
while (p3 = index(p2, '!')) {
int tmp = strlen(p3+1); /* xenix has compiler problems */
p2 = p3+1;
if (tmp + isauthor*4 < pad) {
if (isauthor && (p2 -= 4) < old_p2)
p2 = old_p2;
break;
}
}
if (isauthor && p2 > old_p2+4 && !p3 && strlen(p2) + 4 > pad)
p2 -= 4;
if (old_p2 != p2 && isauthor)
(void) strncpy(p2, "TO: ", 4); /* doesn't null terminate */
}
len = strlen(sprintf(b, fmt, p2));
n += len, b += len;
/* Get around a bug in 5.5 IBM RT which pads with NULs not ' ' */
while (n && !*(b-1))
b--, n--;
} else
n++, *b++ = *p;
for (*b-- = 0; isspace(*b) && *b != '\n'; --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.
* route_addresses() is called 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)
char buf[];
{
register char *p = NULL, *p2, *b = buf, *field;
char line[256], name[256], addr[256];
if (field = do_set(set_options, "reply_to_hdr")) {
#ifndef MSG_SEPARATOR
if (!*field)
goto DoFrom; /* 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;
#ifndef MSG_SEPARATOR
if (!lcase_strncmp(field, "from_", -1))
goto DoFrom;
#endif /* MSG_SEPARATOR */
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, field = "reply-to")) ||
(p = header_field(n, field = "return-path")) ||
(p = header_field(n, field = "from")))))
skipspaces(0);
else if (!p) {
#ifndef MSG_SEPARATOR
DoFrom:
field = "from_";
/* if all else fails, then get the first token in "From" line */
if (p2 = msg_get(n, line, sizeof line))
p = index(p2, ' ');
else
return "";
skipspaces(1);
if (p2 = index(p, ' '))
*p2 = 0;
(void) unscramble_addr(p, line); /* p is safely recopied to line */
p = line;
#else /* MSG_SEPARATOR */
wprint("Warning: unable to find who msg %d is from!\n", n+1);
#endif /* MSG_SEPARATOR */
}
get_name_n_addr(p, name, addr);
if (!name[0] && (!lcase_strncmp(field, "return-path", -1) ||
!lcase_strncmp(field, "from_", -1))) {
/*
* Get the name of the author of the message we're replying to from the
* From: header since that header contains the author's name. Only do
* this if the address was gotten from the return-path or from_ lines
* because this is the only way to guarantee that the return address
* matches the author's name. Reply-To: may not be the same person!
* Check Resent-From: first since that's presumably more recent.
*/
if ((p = header_field(n, "resent-from")) ||
(p = header_field(n, "from")))
get_name_n_addr(p, name, NULL);
if (!name[0] && (p = header_field(n, "name")))
(void) strcpy(name, p);
if (name[0]) {
if ((p = any(name, "(<,\"")) && (*p == ',' || *p == '<'))
*b++ = '"';
b += Strcpy(b, name);
if (p && (*p == ',' || *p == '<'))
*b++ = '"';
*b++ = ' ', *b++ = '<';
}
b += Strcpy(b, addr);
if (name[0])
*b++ = '>', *b = 0;
} else
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, "resent-to")) || (p = header_field(n, "to")) ||
(p = header_field(n, "apparently-to"))) && *p) {
*b++ = ',', *b++ = ' ';
/* The assumption that HDRSIZ is correct is unwise, but I know it
* to be true for Mush. Be forewarned if you call this routine.
*/
p[HDRSIZ - (b - buf) - 2] = '\0'; /* prevent overflow */
b += Strcpy(b, p);
}
/* Also append the Resent-From address if there is one. */
if (all && (p = header_field(n, "resent-from")) && *p) {
*b++ = ',', *b++ = ' ';
/* Another trick to prevent overflow. See warning above. */
(void) strncpy(b, p, HDRSIZ - (b - buf) - 2);
buf[HDRSIZ - 3] = 0;
}
fix_up_addr(buf);
take_me_off(buf);
for (p = buf; *p == ',' || isspace(*p); p++)
;
if (!*p)
(void) strcpy(buf, login);
return 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 (lcase_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(p);
take_me_off(p);
return strcpy(buf, p);
}