[comp.sources.unix] v15i012: mp - mail pretty printer v1.4

sources-request@munnari.oz (05/27/88)

Submitted by: richb@sunaus.oz (Rich Burridge)
Posting-number: Volume 15, Issue 12
Archive-name: mp/Part01



The mp program is used in conjunction with the print option
of your mail program. It generates a PostScript output file,
which is a pretty printed version of your mail message. It
has been tested on a Sun using /usr/ucb/mail and the window-
based mailtool program. With little or no modification, it
should be possible to make this work with other mailers.

See the README file for more details.

    Rich.

------CUT HERE------CUT HERE------
#! /bin/sh
# this is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh to create the files:
#	README
#	Makefile
#	mp.c
#	mp.pro.ps
#	mp.1
# This archive created: Wed May 25 12:00:29 EST 1988
#
#
export PATH; PATH=/bin:$PATH
#
if [ -f README ]
then
echo shar: will not over-write existing file README
else
echo shar: extracting 'README',     1531 characters
cat > README <<'Funky_Stuff'

  mp README v1.4    3/3/87
  ------------------------

The mp program is to be used in conjunction with mailtool or mail for
producing a pretty print of your mail items. It uses a PostScript
prologue file which normally resides in /usr/local, but this can be
overwritten by use of the -p option.

Do a "make" followed by a "make install" which will compile the mp program
and put the files in their default locations. You will probably have to
be super-user when you do the "make install"

This version of mp, which has been rewritten from the original by Steve
Holden (Sun UK) in the ICON language, to C. 

It is designed to be used in conjunction with the print button in the
mailtool program, or the 'pipe' command from withing mail.

Add (or alter) the following two lines in your .mailrc file:

set printmail='mp | lpr'
set cmd="mp | lpr &"

Source your .mailrc file again, and you are ready. This has been tested
with a LaserWriter with an A4 paper tray, running Transcript v2.0. Please
let us know if this requires any modification to run in the US.

Any problems, suggestions, bugs or flames to me or Steve please.

Rich Burridge                             Steve Holden
Sun Microsystems                          Sun Microsystems,
49/53 Hotham Parade,                      Lord Street,
Sydney, N.S.W. 2164,                      Cheshire, SK1 3ND,
AUSTRALIA.                                ENGLAND.

sun!sunaus!richb                          sun!sunuk!nuksun!steve
rburridge@Sun.COM                         sholden@Sun.COM
Funky_Stuff
len=`wc -c < README`
if [ $len !=     1531 ] ; then
echo error: README was $len bytes long, should have been     1531
fi
fi # end of overwriting check
if [ -f Makefile ]
then
echo shar: will not over-write existing file Makefile
else
echo shar: extracting 'Makefile',      539 characters
cat > Makefile <<'Funky_Stuff'
#
#  mp distribtution source makefile    steve holden
#  C version by Rich Burridge.
#
#  @(#)Makefile	1.4  3/3/88.
#

FILES   = README Makefile mp.c mp.pro.ps mp.1
CFLAGS  = -g
TAPE    = /dev/rst0

mp:     mp.c
	cc $(CFLAGS) -o mp mp.c

install:
	install mp /usr/local/bin
	cp mp.pro.ps /usr/local

backup:
	cp mp.c mp.c~
	cp mp.pro.ps mp.pro.ps~

lint:
	lint mp.c

shar:
	shar.script $(FILES) > archive

clean:
	rm -f mp

distribution:
	-mt -f $(TAPE) rewind
	tar cvbf 126 $(TAPE) $(FILES)
purge:
	-rm -f *.c *.ps mp.1 testmail Makefile
Funky_Stuff
len=`wc -c < Makefile`
if [ $len !=      539 ] ; then
echo error: Makefile was $len bytes long, should have been      539
fi
fi # end of overwriting check
if [ -f mp.c ]
then
echo shar: will not over-write existing file mp.c
else
echo shar: extracting 'mp.c',     7190 characters
cat > mp.c <<'Funky_Stuff'

/*  mp.c - take a mail file and format each line for the LaserWriter.
 *
 *         Original written in the Icon language by Steve Holden - Sun UK.
 *         Converted to C and modified by Rich Burridge - Sun Australia.
 *
 *         v1.4   3 March 1988.
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/file.h>
#include <string.h>
#include <time.h>

#define  PATCHLEVEL   2

#define  FPRINTF      (void) fprintf    /* To make lint happy. */
#define  PRINTF       (void) printf
#define  SPRINTF      (void) sprintf
#define  SSCANF       (void) sscanf
#define  STRCPY       (void) strcpy
#define  STRNCPY      (void) strncpy

/* States for the mail processing automation. */
#define  FROMLINE     0      /* Searching for the initial From line. */
#define  DOHEADER     1      /* Processing rest of message header. */
#define  DOMESSAGE    2      /* Processing text in message body. */

#define  EQUAL(val)   !strncmp(val,nextline,strlen(val))
#define  LINELENGTH   80     /* Number of characters per line. */
#define  MAXLINE      256     /* Length of character strings. */
#define  PAGELENGTH   60     /* Number of lines per page. */

time_t time() ;
struct tm *localtime() ;
char *asctime(), *getlogin(), *gets() ;
char subject[MAXLINE] ;    /* Subject line for this message. */
FILE *fopen(), *pf ;

int lindex ;             /* Index pointer to nextline. */
int linect = 0 ;         /* Line count on current page. */
int maybe_more = 0 ;     /* Message header continuation line indicator. */
int non_space ;          /* Indicates if nextline has a non-space char. */
int pn = 1 ;             /* Page number within message. */
int removednl ;          /* Set if a newline was removed from this line. */


/*ARGSUSED*/
main(argc,argv)
int argc ;
char **argv ;
{
  char **args ;
  char nextline[MAXLINE] ;   /* Next line of the mail message. */
  char prologue[MAXLINE] ;   /* Name of PostScript prologue file. */
  char username[MAXLINE] ;   /* The username of the mail file owner. */
  int state ;                /* State of message processing automation. */
  long clock ;               /* Used by the localtime function call. */
  struct tm *tm ;            /* Used by the localtime and asctime calls. */

  char *progname = *argv ;                    /* This programs name. */
  STRCPY(prologue, "/usr/local/mp.pro.ps") ;  /* Set up default values. */
  STRCPY(username, getlogin()) ;

  if (argv)
    {
      for (args = ++argv; *args; args++)
        if (strcmp(*args, "-p") == 0)
          {
            if (*(args+1) == NULL) prologue[0] = '\0' ;
            else STRCPY(prologue, *(args+1)) ;
            args++ ;
            if (!strlen(prologue))
              {
                FPRINTF(stderr,"%s: -p needs prologue name as next argument.\n",progname) ;
                exit(1) ;
              }
          }
        else
          {
            FPRINTF(stderr,"%s: Unknown option %s\n",progname,*args) ;
            exit(1) ;
          }
    }

  if ((pf = fopen(prologue, "r")) == NULL)
    {
      FPRINTF(stderr,"%s: Prologue file not found.\n",progname) ;
      exit(1) ;
    } 
  while (fgets(nextline,MAXLINE,pf) != NULL) PRINTF("%s",nextline) ;

  defwrite("loginname",username) ;
  clock = time((time_t *) 0) ;
  tm = localtime(&clock) ;
  defwrite("timenow",asctime(tm)) ;
  PRINTF("%%%%EndProlog\n") ;

  state = FROMLINE ;
  startpage() ;
  while (fgets(nextline,LINELENGTH+1,stdin) != NULL)
    {
      removednl = 0 ;
      if (nextline[strlen(nextline)-1] == '\n')
        {
          removednl = 1 ;
          nextline[strlen(nextline)-1] = '\0' ;
        }
      non_space = 0 ;
      for (lindex = 0; lindex < strlen(nextline); lindex++)
        if (nextline[lindex] != ' ')
          {
            non_space = 1 ;
            break ;
          }
      switch (state)
        {
          case FROMLINE  : if (EQUAL("From"))
                             {
                               boldshow(nextline) ;
                               state = DOHEADER ;
                             }
                           break ;
          case DOHEADER  : if (EQUAL("From") || EQUAL("Date") || EQUAL("Subject"))
                             {
                               mixedshow(nextline) ;
                               maybe_more = 0 ;
                             }
                           else if (EQUAL("To") || EQUAL("Cc"))
                             {
                               mixedshow(nextline) ;
                               maybe_more = 1 ;
                             }
                           else if (EQUAL(" ") && non_space && maybe_more)
                             textshow(nextline) ;
                           else if ((EQUAL(" ") && (!non_space)) || (!strlen(nextline)))
                             {
                               state = DOMESSAGE ;
                               PRINTF("Courier\n") ;
                               PRINTF("() showline\n") ;
                             }
                           else maybe_more = 0 ;
                           break ;
          case DOMESSAGE : textshow(nextline) ;
        }
    }
  endpage() ;
  PRINTF("%%%%Trailer\n") ;
  PRINTF("%%%%Pages: %1d\n",pn) ;
}


boldshow(s)
char *s ;
{
  useline() ;
  PRINTF("Bold ") ;
  startline() ;
  expand(s) ;
  endline() ;
}


mixedshow(s)
char *s ;
{
  char first[MAXLINE] ;

  useline() ;
  SSCANF(s,"%s",first) ;
  PRINTF("Bold (%s) show Roman (",first) ;
  expand(&s[strlen(first)]) ;
  endline() ;
  if (!strcmp("Subject:",first))
    {
      PRINTF("/subject (") ;
      expand(&s[strlen(first)]) ;
      STRCPY(subject,&s[strlen(first)]) ;
      PRINTF(") def\n") ;
    }
}


textshow(s)
char *s ;
{
  if (*s == '\014')
    {
      if (removednl)        /* Is this the bogus formfeed at the end? */
        {
          linect = PAGELENGTH ;
          useline() ;
        }
      return ;
    }
  useline() ;
  startline() ;
  expand(s) ;
  endline() ;
}


expand(s)
char *s ;
{
  int i,j,n ;

  n = 0 ;
  for (i = 0; i < strlen(s); i++)
    {
      switch (s[i])
        {
          case '\\'   : PRINTF("\\\\") ;
                        n++ ;
                        break ;
          case '('    : PRINTF("\\(") ;
                        n++ ;
                        break ;
          case ')'    : PRINTF("\\)") ;
                        n++ ;
                        break ;
          case '\t'   : for (j = 0; j < (8 - (n % 8)); j++)
                        PRINTF(" ") ;
                        n = n + 8 - (n % 8) ;
                        break ;
          default     : PRINTF("%c",s[i]) ;
                        n++ ;
        }
      if (!(i % LINELENGTH) && i)
        {
          endline() ;
          startline() ;
        }
    }
}


useline()
{
  if (++linect > PAGELENGTH)
    {
      endpage() ;
      startpage() ;
      PRINTF("/subject (") ;
      expand(subject) ;
      PRINTF(") def\n") ;
    }
}


startline()
{
  PRINTF("(") ;
}


startpage()
{
  PRINTF("%%%%Page: ? %1d\n",pn) ;
}


endline()
{
  PRINTF(") showline\n") ;
}


endpage()
{
  linect = 0 ;
  PRINTF("(%1d) endpage\n",pn++) ;
}


defwrite(name,def)
char *name, *def ;
{
  PRINTF("/%s (%s) def\n",name,def) ;
}
Funky_Stuff
len=`wc -c < mp.c`
if [ $len !=     7190 ] ; then
echo error: mp.c was $len bytes long, should have been     7190
fi
fi # end of overwriting check
if [ -f mp.pro.ps ]
then
echo shar: will not over-write existing file mp.pro.ps
else
echo shar: extracting 'mp.pro.ps',     1754 characters
cat > mp.pro.ps <<'Funky_Stuff'
%!PS-Adobe-1.0
%%Creator: Steve Holden
%%Modifed: Rich Burridge
%%Title: @(#)mp.pro.ps	1.4    3/3/88
%%CreationDate: see above
%%DocumentFonts: Times-Bold Times-Roman Courier
%%Pages: (atend)
%%EndComments
%

/subject () def
save /nuksunmailsave exch def
/font1d /Times-Bold findfont 10 scalefont def

/font2d /Times-Roman findfont 10 scalefont def

/font3d /Courier findfont 9 scalefont def

/fontHd /Helvetica-BoldOblique findfont 15 scalefont def

/fontH2 /Helvetica-BoldOblique findfont 10 scalefont def

/fontNd /Times-Bold findfont 12 scalefont def

/Bold {font1d setfont} def
/Roman {font2d setfont} def
/Courier {font3d setfont} def
/fontH {fontHd setfont} def
/fontD {fontH2 setfont} def
/fontN {fontNd setfont} def

Courier

/endpage
{
    gsave
    fontH
    newpath
    90 756 moveto
    100 736 10 180 270 arc
    536 736 10 270 0 arc
    536 756 10 0 90 arc
    100 756 10 90 180 arc
    closepath 0.75 setgray fill
    newpath
    318 746 15 0 360 arc
    gsave 1 setgray fill grestore
    closepath
    0 setgray stroke
    100 740 moveto
    (Mail for ) show
    loginname (\(null\)) eq {(printing)} {loginname} ifelse show
    fontD
    timenow stringwidth pop neg 536 add 740 moveto timenow show
    fontN
    dup stringwidth pop 2 div neg 318 add 740 moveto show
    fontH
    newpath
    90 60 moveto
    100 40 10 180 270 arc
    536 40 10 270 0 arc
    536 60 10 0 90 arc
    100 60 10 90 180 arc
    closepath 0.75 setgray fill
    0 setgray
    100 44 moveto subject show
    grestore
    showpage		% display it
    newpage		% reset parameters for next
} def

/newpage
{ /lct 0 def
  /ypos 700 def
  100 ypos moveto
} def

/showline { show /ypos ypos 10 sub def 100 ypos moveto } def

newpage			% establish first page parameters
Funky_Stuff
len=`wc -c < mp.pro.ps`
if [ $len !=     1754 ] ; then
echo error: mp.pro.ps was $len bytes long, should have been     1754
fi
fi # end of overwriting check
if [ -f mp.1 ]
then
echo shar: will not over-write existing file mp.1
else
echo shar: extracting 'mp.1',     1056 characters
cat > mp.1 <<'Funky_Stuff'
.TH MP 1 "3 March 1988"
.\"@(#)mp.1	1.4	3/3/88
.SH NAME
mp \- mail printer
.SH SYNOPSIS
\fBmp\fP 
[ \fB-p\fP \fIprolog filename\fP ]
.SH DESCRIPTION
.IX  mp "" "\fLmp\fP \(em mail printing program"
.IX  mail "mp command" "" "\fLmp\fP \(em mail printing"
.IX "mail printing" "mp command" "" "\fLmp\fP \(em mail printing"
\fIMp\fP produces PostScript output which can be used to print mail on
a LaserWriter.
The format adopted has shaded stripes containing banner information
at the top and bottom of every page.
\fIMp\fP reads standard input for the mail file and sends its output
to standard output.
.SH OPTIONS
.TP
\fB-p\fP \fIprolog filename\fP
The default location for the PostScript prologue file is
/usr/local/mp.pro.ps. This options allows a different location to be
specified.
.SH FILES
.TP
/usr/local/mp.pro.ps
PostScript prologue to define required vocabulary for mail printing.
Editing this file will alow you to introduce some stylistic variation
in the printing of mail.
.TP
.SH "SEE ALSO"
mail(1)
.SH BUGS
Does not process more than one file.
Funky_Stuff
len=`wc -c < mp.1`
if [ $len !=     1056 ] ; then
echo error: mp.1 was $len bytes long, should have been     1056
fi
fi # end of overwriting check