This is from.c in view mode; [Download] [Up]
static char rcsid[] = "@(#)$Id: from.c,v 5.4 1992/12/11 01:45:04 syd Exp $";
/*******************************************************************************
* The Elm Mail System - $Revision: 5.4 $ $State: Exp $
*
* Copyright (c) 1988-1992 USENET Community Trust
* Copyright (c) 1986,1987 Dave Taylor
*******************************************************************************
* Bug reports, patches, comments, suggestions should be sent to:
*
* Syd Weinstein, Elm Coordinator
* elm@DSI.COM dsinc!elm
*
*******************************************************************************
* $Log: from.c,v $
* Revision 5.4 1992/12/11 01:45:04 syd
* remove sys/types.h include, it is now included by defs.h
* and this routine includes defs.h or indirectly includes defs.h
* From: Syd
*
* Revision 5.3 1992/11/07 21:03:33 syd
* fix typo
*
* Revision 5.2 1992/11/07 20:05:52 syd
* change to use header_cmp to allow for linear white space around the colon
* From: Syd
*
* Revision 5.1 1992/10/04 00:46:45 syd
* Initial checkin as of 2.4 Release at PL0
*
*
******************************************************************************/
/** print out whom each message is from in the pending folder or specified
one, including a subject line if available.
**/
#include "elmutil.h"
#include "s_from.h"
#ifdef PWDINSYS
# include <sys/pwd.h>
#else
# include <pwd.h>
#endif
#include <sys/stat.h>
#define LINEFEED (char) 10
#define metachar(c) (c == '=' || c == '+' || c == '%')
/* ancient wisdom */
#ifndef TRUE
# define TRUE 1
# define FALSE 0
#endif
/* for explain(), positive and negative */
#define POS 1
#define NEG 0
/* defines for selecting messages by Status: */
#define NEW_MSG 0x1
#define OLD_MSG 0x2
#define READ_MSG 0x4
#define UNKNOWN 0x8
#define ALL_MSGS 0xf
/* exit statuses */
#define EXIT_SELECTED 0 /* Selected messages present */
#define EXIT_MAIL 1 /* Mail present, but no selected messages */
#define EXIT_NO_MAIL 2 /* No messages at all */
#define EXIT_ERROR 3 /* Error */
FILE *mailfile;
int number = FALSE, /* should we number the messages?? */
veryquiet = FALSE,/* should we be print any output at all? */
quiet = FALSE, /* only print mail/no mail and/or summary */
selct = FALSE, /* select these types of messages */
summarize = FALSE,/* print a summary of how many messages of each type */
verbose = FALSE; /* and should we prepend a header? */
char infile[SLEN]; /* current file name */
char realname[SLEN]; /* the username of the user who ran the program */
extern char *whos_mail(), *explain();
main(argc, argv)
int argc;
char *argv[];
{
char *cp;
int multiple_files = FALSE, output_files = FALSE;
int user_mailbox = FALSE, c;
struct passwd *pass;
#ifndef _POSIX_SOURCE
struct passwd *getpwuid();
#endif
int hostlen, domlen;
int total_msgs = 0, selected_msgs = 0;
int file_exists;
struct stat statbuf;
extern int optind;
extern char *optarg;
#ifdef I_LOCALE
setlocale(LC_ALL, "");
#endif
elm_msg_cat = catopen("elm2.4", 0);
/*
* check the first character of the command basename to
* use as the selection criterion.
*/
cp = argv[0] + strlen(argv[0]) - 1;
while (cp != argv[0] && cp[-1] != '/')
cp--;
switch (*cp) {
case 'n': selct |= NEW_MSG; break;
case 'u':
case 'o': selct |= OLD_MSG; break;
case 'r': selct |= READ_MSG; break;
}
while ((c = getopt(argc, argv, "hnQqSs:v")) != EOF)
switch (c) {
case (int)'n': number++; break;
case (int)'Q': veryquiet++; break;
case (int)'q': quiet++; break;
case (int)'S': summarize++; break;
case (int)'v': verbose++; break;
case (int)'s': if (optarg[1] == '\0') {
switch (*optarg) {
case 'n':
case 'N': selct |= NEW_MSG; break;
case 'o':
case 'O':
case 'u':
case 'U': selct |= OLD_MSG; break;
case 'r':
case 'R': selct |= READ_MSG; break;
default: usage(argv[0]);
exit(EXIT_ERROR);
}
} else if (istrcmp(optarg,"new") == 0)
selct |= NEW_MSG;
else if (istrcmp(optarg,"old") == 0)
selct |= OLD_MSG;
else if (istrcmp(optarg,"unread") == 0)
selct |= OLD_MSG;
else if (istrcmp(optarg,"read") == 0)
selct |= READ_MSG;
else {
usage(argv[0]);
exit(EXIT_ERROR);
}
break;
case (int)'h': print_help();
exit(EXIT_ERROR);
case (int)'?': usage(argv[0]);
printf(catgets(elm_msg_cat,
FromSet,FromForMoreInfo,
"For more information, type \"%s -h\"\n"),
argv[0]);
exit(EXIT_ERROR);
}
if (quiet && verbose) {
fprintf(stderr,catgets(elm_msg_cat,FromSet,FromNoQuietVerbose,
"Can't have quiet *and* verbose!\n"));
exit(EXIT_ERROR);
}
if (veryquiet) {
if (freopen("/dev/null", "w", stdout) == NULL) {
fprintf(stderr,catgets(elm_msg_cat,FromSet,FromCantOpenDevNull,
"Can't open /dev/null for \"very quiet\" mode.\n"));
exit(EXIT_ERROR);
}
}
/* default is all messages */
if (selct == 0 || selct == (NEW_MSG|OLD_MSG|READ_MSG))
selct = ALL_MSGS;
if((pass = getpwuid(getuid())) == NULL) {
fprintf(stderr,catgets(elm_msg_cat,FromSet,FromNoPasswdEntry,
"You have no password entry!"));
exit(EXIT_ERROR);
}
strcpy(username,pass->pw_name);
strcpy(realname,username);
/*
* from init.c: Get the host name as per configured behavior.
*/
#ifdef HOSTCOMPILED
strncpy(hostname, HOSTNAME, sizeof(hostname) - 1);
hostname[sizeof(hostname) - 1] = '\0';
#else
gethostname(hostname, sizeof(hostname));
#endif
gethostdomain(hostdomain, sizeof(hostdomain));
/*
* see init.c for an explanation of this!
*/
hostlen = strlen(hostname);
domlen = strlen(hostdomain);
if (hostlen >= domlen) {
if (istrcmp(&hostname[hostlen - domlen], hostdomain) == 0)
strcpy(hostfullname, hostname);
else {
strcpy(hostfullname, hostname);
strcat(hostfullname, hostdomain);
}
} else {
if (istrcmp(hostname, hostdomain + 1) == 0)
strcpy(hostfullname, hostname);
else {
strcpy(hostfullname, hostname);
strcat(hostfullname, hostdomain);
}
}
infile[0] = '\0';
if (optind == argc) {
/*
* determine mail file from environment variable if found,
* else use password entry
*/
if ((cp = getenv("MAIL")) == NULL) {
sprintf(infile,"%s%s",mailhome, username);
}
else
strcpy(infile, cp);
optind -= 1; /* ensure one pass through loop */
}
multiple_files = (argc - optind > 1);
for ( ; optind < argc; optind++) {
/* copy next argument into infile */
if (multiple_files) {
strcpy(infile, argv[optind]);
printf("%s%s: \n", output_files++ > 0 ? "\n":"", infile);
}
else if (infile[0] == '\0')
strcpy(infile, argv[optind]);
if (metachar(infile[0])) {
if (expand(infile) == 0) {
fprintf(stderr,catgets(elm_msg_cat,
FromSet,FromCouldntExpandFilename,
"%s: couldn't expand filename %s!\n"),
argv[0], infile);
exit(EXIT_ERROR);
}
}
/* check if this is a mailbox or not, and attempt to open it */
if (strncmp(infile, mailhome, strlen(mailhome)) == 0)
user_mailbox = TRUE;
else
user_mailbox = FALSE;
/* pardon the oversimplification here */
if (stat(infile, &statbuf) == -1)
file_exists = FALSE;
else
file_exists = TRUE;
if (file_exists && (statbuf.st_mode & S_IFMT) != S_IFREG) {
printf(catgets(elm_msg_cat,FromSet,FromNotRegularFile,
"\"%s\" is not a regular file!\n"), infile);
continue;
}
if ((mailfile = fopen(infile,"r")) == NULL) {
if (user_mailbox && file_exists && statbuf.st_size == 0)
printf(catgets(elm_msg_cat,FromSet,FromNoMail,"No mail.\n"));
else {
if (infile[0] == '/' || file_exists == TRUE)
printf(catgets(elm_msg_cat,FromSet,FromCouldntOpenFolder,
"Couldn't open folder \"%s\".\n"), infile);
else {
/* only try mailhome if file not found */
sprintf(infile,"%s%s", mailhome, argv[optind]);
if ((mailfile = fopen(infile,"r")) == NULL) {
printf(catgets(elm_msg_cat,
FromSet,FromCouldntOpenFolderPlural,
"Couldn't open folders \"%s\" or \"%s\".\n"),
argv[optind], infile);
continue; /* let's try the next file */
} else
user_mailbox = TRUE;
}
}
}
/* if the open was successful, read the headers */
if (mailfile != NULL) {
/*
* if this is a mailbox, use the identity of the mailbox owner.
* this affects the "To" processing.
*/
if (strncmp(infile, mailhome, strlen(mailhome)) == 0)
strcpy(username, infile+strlen(mailhome));
else
strcpy(username, realname);
/*
* then get full username
*/
if((cp = get_full_name(username)) != NULL)
strcpy(full_username, cp);
else
strcpy(full_username, username);
read_headers(user_mailbox, &total_msgs, &selected_msgs);
/*
* we know what to say; now we have to figure out *how*
* to say it!
*/
/* no messages at all? */
if (total_msgs == 0) {
if (user_mailbox)
printf(catgets(elm_msg_cat,FromSet,FromStringNoMail,
"%s no mail.\n"), whos_mail(infile));
else
if (!summarize)
printf(catgets(elm_msg_cat,FromSet,FromNoMesgInFolder,
"No messages in that folder!\n"));
}
else
/* no selected messages then? */
if (selected_msgs == 0) {
if (user_mailbox)
printf(catgets(elm_msg_cat,FromSet,FromNoExplainMail,
"%s no %s mail.\n"), whos_mail(infile),
explain(selct,NEG));
else
if (!summarize)
printf(catgets(elm_msg_cat,
FromSet,FromNoExplainMessages,
"No %s messages in that folder.\n"),
explain(selct,NEG));
}
else
/* there's mail, but we just want a one-liner */
if (quiet && !summarize) {
if (user_mailbox)
printf(catgets(elm_msg_cat,FromSet,FromStringStringMail,
"%s %s mail.\n"), whos_mail(infile),
explain(selct,POS));
else
printf(catgets(elm_msg_cat,FromSet,FromThereAreMesg,
"There are %s messages in that folder.\n"),
explain(selct,POS));
}
fclose(mailfile);
}
} /* for each arg */
/*
* return "shell true" (0) if there are selected messages;
* 1 if there are messages, but no selected messages;
* 2 if there are no messages at all.
*/
if (selected_msgs > 0)
exit(EXIT_SELECTED);
else if (total_msgs > 0)
exit(EXIT_MAIL);
else
exit(EXIT_NO_MAIL);
}
read_headers(user_mailbox, total_msgs, selected)
int user_mailbox;
int *total_msgs;
int *selected;
{
/** Read the headers, output as found. User-Mailbox is to guarantee
that we get a reasonably sensible message from the '-v' option
**/
char buffer[SLEN], to_whom[SLEN], from_whom[SLEN], subject[SLEN];
char who[SLEN];
register int in_header = FALSE, count = 0, selected_msgs = 0;
int status, i;
int summary[ALL_MSGS];
#ifdef MMDF
int newheader = FALSE;
#endif /* MMDF */
for (i=0; i<ALL_MSGS; i++)
summary[i] = 0;
while (mail_gets(buffer, SLEN, mailfile) != 0) {
if (index(buffer, '\n') == NULL && !feof(mailfile)) {
int c;
while ((c = getc(mailfile)) != EOF && c != '\n')
; /* keep reading */
}
#ifdef MMDF
if (strcmp(buffer, MSG_SEPARATOR) == 0) {
newheader = !newheader;
if (newheader) {
subject[0] = '\0';
to_whom[0] = '\0';
in_header = TRUE;
if (user_mailbox)
status = NEW_MSG;
else
status = READ_MSG;
}
}
#else
if (first_word(buffer,"From ")
&& real_from(buffer, from_whom)) {
subject[0] = '\0';
to_whom[0] = '\0';
in_header = TRUE;
if (user_mailbox)
status = NEW_MSG;
else
status = READ_MSG;
}
#endif /* MMDF */
else if (in_header) {
#ifdef MMDF
if (first_word(buffer,"From "))
real_from(buffer, from_whom);
#endif /* MMDF */
if (first_word(buffer,">From "))
forwarded(buffer, from_whom); /* return address */
else if (header_cmp(buffer,"Subject", NULL) ||
header_cmp(buffer,"Re", NULL)) {
if (subject[0] == '\0') {
remove_header_keyword(buffer);
strcpy(subject, buffer);
}
}
else if (header_cmp(buffer,"From", NULL) ||
header_cmp(buffer, ">From", NULL))
parse_arpa_who(buffer, from_whom, FALSE);
else if (header_cmp(buffer, "To", NULL))
figure_out_addressee(index(buffer, ':') + 1, to_whom);
else if (header_cmp(buffer, "Status", NULL)) {
remove_header_keyword(buffer);
switch (*buffer) {
case 'N': status = NEW_MSG; break;
case 'O': status = OLD_MSG; break;
case 'R': status = READ_MSG; break;
default: status = UNKNOWN; break;
}
if (buffer[0] == 'O' && buffer[1] == 'R')
status = READ_MSG;
}
else if (buffer[0] == LINEFEED) {
in_header = FALSE;
#ifdef MMDF
if (*from_whom == '\0')
strcpy(from_whom,username);
#endif /* MMDF */
count++;
summary[status]++;
if ((status & selct) != 0) {
/* what a mess! */
if (verbose && selected_msgs == 0) {
if (user_mailbox) {
if (selct == ALL_MSGS)
printf(catgets(elm_msg_cat,FromSet,FromFollowingMesg,
"%s the following mail messages:\n"),
whos_mail(infile));
else
printf(catgets(elm_msg_cat,FromSet,FromStringStringMail,
"%s %s mail.\n"), whos_mail(infile),
explain(selct,POS));
}
else
printf(catgets(elm_msg_cat,
FromSet,FromFolderContainsFollowing,
"Folder contains the following %s messages:\n"),
explain(selct,POS));
}
selected_msgs++;
if (! quiet) {
if (tail_of(from_whom, who, to_whom) == 1) {
strcpy(buffer, "To ");
strcat(buffer, who);
strcpy(who, buffer);
}
if (number)
printf("%3d: %-20s %s\n", count, who, subject);
else
printf("%-20s %s\n", who, subject);
}
}
}
}
}
*selected = selected_msgs;
*total_msgs = count;
/* print a message type summary */
if (summarize) {
int output=FALSE, unknown = 0;
if (user_mailbox)
printf("%s ", whos_mail(infile));
else
printf(catgets(elm_msg_cat,FromSet,FromFolderContains,
"Folder contains "));
for (i=0; i<ALL_MSGS; i++) {
if (summary[i] > 0) {
if (output)
printf(", ");
switch (i) {
case NEW_MSG:
case OLD_MSG:
case READ_MSG:
printf("%d %s ",summary[i], explain(i,POS));
if (summary[i] == 1)
printf("%s",catgets(elm_msg_cat,
FromSet,FromMessage,"message"));
else
printf("%s",catgets(elm_msg_cat,
FromSet,FromMessagePlural,"messages"));
output = TRUE;
break;
default:
unknown += summary[i];
}
}
}
if (unknown)
{
printf("%d ",unknown);
if (unknown == 1)
printf("%s",catgets(elm_msg_cat,
FromSet,FromMessage,"message"));
else
printf("%s",catgets(elm_msg_cat,
FromSet,FromMessagePlural,"messages"));
printf("%s "," of unknown status");
output = TRUE;
}
if (output)
printf(".\n");
else
printf(catgets(elm_msg_cat,FromSet,FromNoMessages,
"no messages.\n"));
}
}
int
real_from(buffer, who)
char *buffer, *who;
{
/***** returns true iff 's' has the seven 'from' fields,
initializing the who to the sender *****/
char junk[SLEN];
junk[0] = '\0';
sscanf(buffer, "%*s %s %*s %*s %*s %*s %s",
who, junk);
return(junk[0] != '\0');
}
forwarded(buffer, who)
char *buffer, *who;
{
/** change 'from' and date fields to reflect the ORIGINATOR of
the message by iteratively parsing the >From fields... **/
char machine[SLEN], buff[SLEN], holding_from[SLEN];
machine[0] = '\0';
holding_from[0] = '\0';
sscanf(buffer, "%*s %s %*s %*s %*s %*s %*s %*s %*s %*s %s",
holding_from, machine);
if(machine[0] == '\0') /* try for address with timezone in date */
sscanf(buffer, "%*s %s %*s %*s %*s %*s %*s %*s %*s %s",
holding_from, machine);
if (machine[0] == '\0') /* try for srm address */
sscanf(buffer, "%*s %s %*s %*s %*s %*s %*s %*s %s",
holding_from, machine);
if (machine[0] == '\0')
sprintf(buff, holding_from[0] ? holding_from :
catgets(elm_msg_cat,FromSet,FromAnon, "anonymous"));
else
sprintf(buff,"%s!%s", machine, holding_from);
strncpy(who, buff, SLEN);
}
/*
* Return an appropriate string as to whom this mailbox belongs.
*/
char *
whos_mail(filename)
char *filename;
{
static char whos_who[SLEN];
char *mailname;
if (strncmp(filename, mailhome, strlen(mailhome)) == 0) {
mailname = filename + strlen(mailhome);
if (*mailname == '/')
mailname++;
if (strcmp(mailname, realname) == 0)
strcpy(whos_who,catgets(elm_msg_cat,
FromSet,FromYouHave,"You have"));
else {
strcpy(whos_who, mailname);
strcat(whos_who,catgets(elm_msg_cat,FromSet,FromHas, " has"));
}
}
else
/* punt... */
strcpy(whos_who,catgets(elm_msg_cat,
FromSet,FromYouHave,"You have"));
return whos_who;
}
usage(prog)
char *prog;
{
printf(catgets(elm_msg_cat,FromSet,FromUsage,
"Usage: %s [-n] [-v] [-s {new|old|read}] [filename | username] ...\n"),
prog);
}
print_help()
{
printf(catgets(elm_msg_cat,FromSet,FromHelpTitle,
"frm -- list from and subject lines of messages in mailbox or folder\n"));
usage("frm");
printf(catgets(elm_msg_cat,FromSet,FromHelpText,
"\noption summary:\n\
-h\tprint this help message.\n\
-n\tdisplay the message number of each message printed.\n\
-Q\tvery quiet -- no output is produced. This option allows shell\n\
\tscripts to check frm's return status without having output.\n\
-q\tquiet -- only print summaries for each mailbox or folder.\n\
-S\tsummarize the number of messages in each mailbox or folder.\n\
-s status only select messages with the specified status.\n\
\t'status' is one of \"new\", \"old\", \"unread\" (same as \"old\"),\n\
\tor \"read\". The first letter need only be specified.\n\
-v\tprint a verbose header.\n"));
}
/* explanation of messages visible after selection */
/* usage: "... has the following%s messages ...", explain(selct,POS) */
char *
explain(selection, how_to_say)
int selection;
int how_to_say;
{
switch (selection) {
case NEW_MSG:
return catgets(elm_msg_cat,FromSet,FromNew,"new");
case OLD_MSG:
return catgets(elm_msg_cat,FromSet,FromUnread,"unread");
case READ_MSG:
return catgets(elm_msg_cat,FromSet,FromRead,"read");
case (NEW_MSG|OLD_MSG):
if (how_to_say == POS)
return catgets(elm_msg_cat,FromSet,FromNewAndUnread,
"new and unread");
else
return catgets(elm_msg_cat,FromSet,FromNewOrUnread,
"new or unread");
case (NEW_MSG|READ_MSG):
if (how_to_say == POS)
return catgets(elm_msg_cat,FromSet,FromNewAndRead,
"new and read");
else
return catgets(elm_msg_cat,FromSet,FromNewOrRead,
"new or read");
case (READ_MSG|OLD_MSG):
if (how_to_say == POS)
return catgets(elm_msg_cat,FromSet,FromReadAndUnread,
"read and unread");
else
return catgets(elm_msg_cat,FromSet,FromReadOrUnread,
"read or unread");
case ALL_MSGS:
return "";
default:
return catgets(elm_msg_cat,FromSet,FromUnknown,"unknown");
}
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.