static char rcsid[] = "@(#)$Id: from.c,v 1.9 1996/05/09 15:51:39 wfp5p Exp $";

/*******************************************************************************
 *  The Elm Mail System  -  $Revision: 1.9 $   $State: Exp $
 *
 *                      Copyright (c) 1988-1995 USENET Community Trust
 * 			Copyright (c) 1986,1987 Dave Taylor
 *******************************************************************************
 * Bug reports, patches, comments, suggestions should be sent to:
 *
 *      Bill Pemberton, Elm Coordinator
 *      flash@virginia.edu
 *
 *******************************************************************************
 * $Log: from.c,v $
 * Revision 1.9  1996/05/09  15:51:39  wfp5p
 * Alpha 10
 *
 * Revision 1.8  1996/03/14  17:30:08  wfp5p
 * Alpha 9
 *
 * Revision 1.7  1995/09/29  17:42:42  wfp5p
 * Alpha 8 (Chip's big changes)
 *
 * Revision 1.6  1995/09/11  15:19:35  wfp5p
 * Alpha 7
 *
 * Revision 1.5  1995/07/18  19:00:12  wfp5p
 * Alpha 6
 *
 * Revision 1.4  1995/06/08  13:41:38  wfp5p
 * A few mostly cosmetic changes
 *
 * Revision 1.3  1995/05/01  13:46:27  wfp5p
 * Changes to make frm -q look right
 *
 * Revision 1.2  1995/04/20  21:02:07  wfp5p
 * Added the showreply feature and emacs key bindings.
 *
 * Revision 1.1.1.1  1995/04/19  20:38:40  wfp5p
 * Initial import of elm 2.4 PL0 as base for elm 2.5.
 *
 ******************************************************************************/

/** print out whom each message is from in the pending folder or specified 
    one, including a subject line if available.

**/

#define INTERN
#include "elm_defs.h"
#include "elm_globals.h"
#include "mailfile.h"
#include "s_from.h"
#include "port_stat.h"

#define metachar(c)	(c == '=' || c == '+' || c == '%')

/* 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 */
      tidy  = FALSE,    /* tidy output with long 'from's */
      useMlists = FALSE,/* include "mailing list" info in the report */
      summarize = FALSE,/* print a summary of how many messages of each type */
      verbose = FALSE;	/* and should we prepend a header? */

int columns = 0;	/* columns on the screen */

char infile[SLEN];	/* current file name */

extern char *whos_mail(), *explain();


main(argc, argv)
int argc;
char *argv[];
{
	char *cp;
	char *default_list[2];
	int  output_files = FALSE;
	int  user_mailbox = FALSE, doing_default_incoming, c;
        int TreatAsSpool = 0;
	int total_msgs = 0, selected_msgs = 0;
	int file_exists;
	struct stat statbuf;

	extern int optind;
	extern char *optarg;

	char *rawarg;

	initialize_common();

	/*
	 * 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, "lMhnQqSs:tv")) != EOF) 
	  switch (c) {
	    case 'l': useMlists++;	break;
	    case 'n': number++;	break;
            case 'M': TreatAsSpool++;break;
	    case 'Q': veryquiet++;	break;
	    case 'q': quiet++;	break;
	    case 'S': summarize++; break; 
	    case 't': tidy++;      break;
	    case 'v': verbose++;	break;
	    case '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 'h': print_help();
			   exit(EXIT_ERROR);
	    case '?': 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;

#ifdef TIOCGWINSZ
	{
	  struct winsize w; 
	  if (ioctl(1,TIOCGWINSZ,&w) != -1 && w.ws_col > 0)
	    columns = w.ws_col;
	}
#endif
	if (columns == 0) columns = 80;

	if ((argc -= optind) == 0) {
	    argc = 1;
	    argv = default_list;
	    default_list[0] = incoming_folder;
	    default_list[1] = NULL;
	    doing_default_incoming = TRUE;
	} else {
	    argv += optind;
	    doing_default_incoming = FALSE;
	}

	while (*argv != NULL) {

	  (void) strfcpy(infile, rawarg = *argv++, sizeof(infile));
	
	  if (argc > 1 && verbose)
	    printf("%s%s:\n", (output_files++ > 0 ? "\n" : ""), infile);

	  if (metachar(infile[0]) && expand(infile) == 0) {
	     fprintf(stderr,catgets(elm_msg_cat,
				    FromSet,FromCouldntExpandFilename,
				    "%s: couldn't expand filename %s!\n"), 
		     argv[0], infile);
	     exit(EXIT_ERROR);
	  }

	  /* see if this is some user's mailbox */
	  user_mailbox = (
		TreatAsSpool
		|| streq(infile, incoming_folder)
		|| strncmp(infile, mailhome, strlen(mailhome)) == 0
	  );

	  /* pardon the oversimplification here */
	  file_exists = (stat(infile, &statbuf) == 0);
	  if (file_exists && !S_ISREG(statbuf.st_mode)) {
	    printf(catgets(elm_msg_cat,FromSet,FromNotRegularFile,
			   "\"%s\" is not a regular file!\n"), infile);
	    continue;
	  }

	  if ((mailfile = fopen(infile,"r")) == NULL) {

	    if (doing_default_incoming) {
		if (verbose)
		  printf(catgets(elm_msg_cat,FromSet,FromNoMail,"No mail.\n"));
		continue;
	    }

	    if (infile[0] == '/' || file_exists == TRUE)  {
	      printf(catgets(elm_msg_cat,FromSet,FromCouldntOpenFolder,
			     "Couldn't open folder \"%s\".\n"), infile);
	      continue;
	    }

	    /* only try mailhome if file not found */
	    sprintf(infile, "%s%s", mailhome, rawarg);
	    if ((mailfile = fopen(infile,"r")) == NULL) {
	      printf(catgets(elm_msg_cat,
			     FromSet,FromCouldntOpenFolderPlural,
			     "Couldn't open folders \"%s\" or \"%s\".\n"),
		     rawarg, infile);
	      continue;
	    }
	    user_mailbox = TRUE;

	  }

	  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
	 **/

	struct header_rec hdr;
	char *buffer;
	char to_whom[SLEN], from_whom[SLEN], subject[SLEN];
	char who[SLEN];
	char outbuf[SLEN], *bp;
	char all_to[LONG_STRING];
	register int in_header = FALSE, count = 0, selected_msgs = 0;
	int in_to_list = FALSE;
	int expect_header = 0;
	long content_length, last_offset;
	int status, i;
	int indent, width;
	int summary[ALL_MSGS];
	int line_bytes;
	struct mailFile mailFile; 
	int flush_lines = FALSE;
#ifdef MMDF
	int newheader = FALSE;
#endif /* MMDF */
	extern struct addrs patterns;
	extern struct addrs mlnames;
	static struct addrs allto;
	static struct addrs user;
	static char *to_me = NULL;
	static char *to_many = NULL;
	static char *cc_me = NULL;	/* not implemented */
	static int initialized = FALSE;
	FAST_COMP_DECLARE;

	if (!initialized) {
	  if (useMlists) {
	    mlist_init();
	    allto.len = allto.max = 0; allto.str = NULL;
	    user.len  = user.max  = 0; user.str = NULL;
	    mlist_push(&user, user_name);
	    /* search for to_me/to_many override */
	    for (i=0; i < patterns.len; i++) {
	      if (patterns.str[i] == NULL)
		continue;
	      if (strcmp(patterns.str[i], TO_ME_TOKEN) == 0) {
		to_me = mlnames.str[i];
	      }
	      else if (strcmp(patterns.str[i], TO_MANY_TOKEN) == 0) {
		to_many = mlnames.str[i];
	      }
	      else if (strcmp(patterns.str[i], CC_ME_TOKEN) == 0) {
		cc_me = mlnames.str[i];
	      }
	    }
	    if (to_me == NULL)   to_me   = TO_ME_DEFAULT;
	    if (to_many == NULL) to_many = TO_MANY_DEFAULT;
	    if (cc_me == NULL)   cc_me   = CC_ME_DEFAULT;
	  }
	  initialized = 1;
	}

	/* amount to indent subject if who is too long */
	indent = 22;	/* who field width plus blanks */
	if (number) indent += 5;
	if (useMlists) indent += 15;
	width = columns - indent;

	for (i=0; i<ALL_MSGS; i++)
	  summary[i] = 0;

	mailFile_attach(&mailFile, mailfile); 

	while ((line_bytes = mailFile_gets(&buffer, &mailFile)) != 0) { 
	  if (expect_header && buffer[0] == '\n') continue; 
	  flush_lines = (buffer[line_bytes-1] != '\n');

	  /* preload first char of line for fast string comparisons */
	  fast_comp_load(buffer[0]);

#ifdef MMDF
          if (strcmp(buffer, MSG_SEPARATOR) == 0) {
	    newheader = !newheader;
	    if (newheader) {
	      subject[0] = '\0';
	      to_whom[0] = '\0';
	      all_to[0] = '\0';
	      in_header = TRUE;
	      expect_header = FALSE;
	      content_length = 0;
	      if (user_mailbox)
		status = NEW_MSG;
	      else
		status = READ_MSG;
	    }
	  }
#else
	  if (fast_strbegConst(buffer, "From ") && real_from(buffer, &hdr)) {
	    strcpy(from_whom, hdr.from);
	    subject[0] = '\0';
	    to_whom[0] = '\0';
	    all_to[0] = '\0';
	    in_header = TRUE;
	    expect_header = FALSE;
	    content_length = 0;
	    if (user_mailbox)
	      status = NEW_MSG;
	    else
	      status = READ_MSG;
	  }
#endif /* MMDF */
	  else if (expect_header) {
	    /* didn't find a header where we expected, so go back */
	    /* and search for a new header */
	    dprint(1, (debugfile, "Error -- didn't find a header: %s\n", buffer));
	    mailFile_seek(&mailFile, last_offset);
	    expect_header=FALSE;
	    continue;
	  }
	  else if (in_header) {
	    if (!isspace(buffer[0]))
	      in_to_list = FALSE;
#ifdef MMDF
	    if (real_from(buffer, &hdr))
	      strcpy(from_whom, hdr.from);
	    else
#endif /* MMDF */
	    if (fast_strbegConst(buffer,">From ")) 
	      forwarded(buffer, from_whom); /* return address */
	    else if (fast_header_cmp(buffer,"Subject", (char *)NULL) ||
		     fast_header_cmp(buffer,"Re", (char *)NULL)) {
	      if (subject[0] == '\0') {
	        remove_header_keyword(buffer);
		 strncpy(subject, buffer, sizeof(subject)-1);
		 subject[sizeof(subject)-1] = '\0';
	      }
	    }
	    else if (fast_header_cmp(buffer,"From", (char *)NULL))
	      parse_arpa_who(buffer+5, from_whom);
	    else if (fast_header_cmp(buffer, ">From", (char *)NULL))
	      parse_arpa_who(buffer+6, from_whom);
	    else if (fast_header_cmp(buffer, "To", (char *)NULL)) {
	      strfcat(all_to, buffer+3, LONG_STRING);
	      figure_out_addressee(buffer+3, user_name, to_whom);
	      in_to_list = TRUE;
	    }
	    else if (useMlists && fast_header_cmp(buffer, "Apparently-To", NULL)) {
	      strfcat(all_to, buffer+14, LONG_STRING);
	      in_to_list = TRUE; 
	    }
	    else if (useMlists && fast_header_cmp(buffer, "Cc", (char *)NULL)) {
	      strfcat(all_to, buffer+3, LONG_STRING);
	      in_to_list = TRUE;
	    }
	    else if (fast_header_cmp(buffer, "Status", (char *)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 (fast_header_cmp(buffer, "Content-Length", (char *)NULL)) {
	      remove_header_keyword(buffer);
	      content_length = atoi(buffer);
	    }
	    else if (useMlists && isspace(buffer[0]) && in_to_list)
		strfcat(all_to, buffer, LONG_STRING);
	    else if (buffer[0] == '\n') {
	      in_header = FALSE;
#ifdef MMDF
	      if (*from_whom == '\0')
                strcpy(from_whom, user_name);
#endif /* MMDF */
	      count++;
	      summary[status]++;
	      if (content_length > 0) {
		last_offset = mailFile_tell(&mailFile);
		mailFile_seek(&mailFile, last_offset + content_length);
		expect_header = TRUE;
	      }

	      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) {
		    char buf[SLEN];
		    strcpy(buf, "To ");
		    strcat(buf, who);
		    strcpy(who, buf);
		  }

		  bp = outbuf;

		  if (number) {
		    sprintf(bp, "%3d: ", count);
		    bp += strlen(bp);
		  }

		  if (useMlists) {
		    parseaddrs(all_to, &allto, FALSE);
		    if (addrmatch(&allto, &user) >= 0) {
		      if (allto.len == 1)
			sprintf(bp, "%-14.14s", to_me);
		      else
			sprintf(bp, "%-14.14s", to_many);
		    } else {
		      int match = addrmatch(&allto, &patterns);
		      if (match >= 0) {
			sprintf(bp, "%-14.14s", mlnames.str[match]);
		      }
		      else {
			if (allto.len > 0)
			  sprintf(bp, "(%-12.12s)", allto.str[0]);
			else
			  sprintf(bp, "***           ");
		      }
		    }
		    bp += strlen(bp);
		    *bp++ = ' ';
		  }
 
		  /***
		  *	Print subject on next line if the Who part blows
		  *	the alignment
		  ***/

		  sprintf(bp, "%-20s  ", who);
		  bp += strlen(bp);

		  if (tidy && strlen(who) > 20) {
		    outbuf[columns-1] = '\0';
		    puts(outbuf);
		    if (*subject != '\0') {
		      subject[columns-indent-1] = '\0';
		      printf("%*s%s\n", indent, "", subject);
		    }
		  }
		  else {
		    sprintf(bp, "%s", subject);
		    outbuf[columns-1] = '\0';
		    puts(outbuf);
		  }
		}
	      }
	    }
	  }
	  /* throw away lines until we get a NL */
	  if (flush_lines) {
	    do {
	      line_bytes = mailFile_gets(&buffer, &mailFile);
	    } while (line_bytes > 0 && buffer[line_bytes-1] != '\n');
	  }
	}
	mailFile_detach(&mailFile);

	*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"));
	}
}


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, user_name) == 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 [-l] [-n] [-v] [-t] [-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\
-l\tinclude information about who each message is to (mailing list info).\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\".  Only the first letter need be specified.\n\
-t\ttry to align subjects even if 'from' text is long.\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");
	}
}


syntax highlighted by Code2HTML, v. 0.9.1