		  Building mm under Sun Solaris 2.1
			    [24-Feb-1993]

			  Nelson H. F. Beebe
		   Center for Scientific Computing
		      Department of Mathematics
			  University of Utah
		       Salt Lake City, UT 84112
				 USA
		Email: beebe@math.utah.edu (Internet)


mm will not build under Sun SPARCstation Solaris 2.1 with the
Sun-supplied unbundled C compiler, /opt/SUNWspro/bin/cc, because that
compiler is at System VR4 level.

I modified the Makefile to select the lines

MACHINE=-DBSD
CCMDLIB=$(CCMD)/ccmd.a

Solaris 2.1 does not have /lib/cpp, but if the compatibility package
has been loaded, it is available elsewhere in the file system.  I used

make CC=/usr/ucb/cc CPP=/usr/ccs/lib/cpp

to get the compatibility-mode compiler and preprocessor, and modified
to Makefile further to

MACHINE=-DBSD -D__solaris

Note added on [25-Oct-1993]:
	The __solaris symbol is needed in dt.c and dates.h to get
	System V style time zone handling within a Berkeley-style
	environment.  dt.c concealed a long-standing portability
	problem in Solaris: there is a gettimeofday() function in
	Solaris 2.x, but it has only one argument (struct timeval *tp)
	in native mode, instead of the conventional (struct timeval
	*tp, struct timezone *tz) in Berkeley UNIX.  Furthermore, no
	prototype exists for it in any system header file, so the
	compiler doesn't catch the mismatch.  The Berkeley
	compatibility-mode library, /usr/ucblib/libucb.{a,so} is
	supposed to contain the Berkeley version of gettimeofday(),
	but it has the System V version instead().  The result was
	then that tz was not set, and had stack-dependent garbage
	values that were included in the result of dt.c:mkdate(); this
	resulted in nonsense time values being written into the header
	lines of mail.txt files, with the result that "mm> headers
	since tomorrow" could produce output.  The solution has been
	to call gettimeofday() with one argument for Solaris, and to
	use the System-V style global timezone value for adjusting the
	value returned by mkdate().
	
With a few changes, all under RCS control, I was able to build it
successfully using BSD compatibility mode, which is easily obtained by

csh:
	set path=(/usr/ucb $path)
sh:
	PATH=/usr/ucb:$PATH ; export PATH

PROVIDED that the compatibility package was installed on Solaris 2.x.

The source code changes fall into these types:
	(1) addition of missing argument-less function prototypes inside
	a few functions
	(2) insertion of missing int modifiers in typeless declarations
	(3) replacements of semicolons by commas in lists of the type
		int	foo,
			bar;
			baz,
			mung;

Here are "rcsdiff -c" context differences that may be used with patch
to update the mm/mm-0.90/mm tree from Columbia University to Solaris.

Script started on Wed Feb 24 22:11:47 1993

101 sunrise::mm> rcsdiff -c *
===================================================================
RCS file: RCS/Makefile,v
retrieving revision 1.1
diff -c -r1.1 Makefile
*** /tmp/T0a004T7	Wed Feb 24 22:12:08 1993
--- Makefile	Wed Feb 24 21:58:07 1993
***************
*** 5,13 ****
  # is not sold for profit, provided this copyright notice is retained.
  #

! # $Header: /usr/local/src/mm/mm-0.94/mm/RCS/README.SOLARIS,v 1.3 2005/05/31 14:40:25 beebe Exp beebe $

  CC = gcc

  .SUFFIXES: .H .h
  .c.o: ; $(CC) $(CFLAGS) -c $*.c
--- 5,15 ----
  # is not sold for profit, provided this copyright notice is retained.
  #

! # $Header: /usr/local/src/mm/mm-0.94/mm/RCS/README.SOLARIS,v 1.3 2005/05/31 14:40:25 beebe Exp beebe $

  CC = gcc
+ # On Solaris 2.1, must built mm in compatibility mode
+ CC = /usr/ucb/cc

  .SUFFIXES: .H .h
  .c.o: ; $(CC) $(CFLAGS) -c $*.c
***************
*** 17,29 ****

  # if you don't have a preprocessor predefine, then define your machine
  # type here:
! #MACHINE=-DBSD
  # if a next do this
  #MACHINE=-DNEXT

  CCMD = ../ccmd
! #CCMDLIB=$(CCMD)/ccmd.a
! CCMDLIB=-L/usr/local/lib -lccmd
  INCLUDE = -I$(CCMD)
  DEBUG = -g -DDEBUG
  #DEBUG = -g -Bstatic -Dsun_stdio_bug -DDEBUG
--- 19,32 ----

  # if you don't have a preprocessor predefine, then define your machine
  # type here:
! MACHINE=-DBSD
! MACHINE=-DBSD -D__solaris
  # if a next do this
  #MACHINE=-DNEXT

  CCMD = ../ccmd
! CCMDLIB=$(CCMD)/ccmd.a
! #CCMDLIB=-L/usr/local/lib -lccmd
  INCLUDE = -I$(CCMD)
  DEBUG = -g -DDEBUG
  #DEBUG = -g -Bstatic -Dsun_stdio_bug -DDEBUG
===================================================================
RCS file: RCS/compat.c,v
retrieving revision 1.1
diff -c -r1.1 compat.c
*** /tmp/T0a004T7	Wed Feb 24 22:12:10 1993
--- compat.c	Wed Feb 24 21:24:54 1993
***************
*** 270,275 ****
--- 270,276 ----
  {
      char *cp;
      FILE *fp, *mm_popen ();
+     char *index ();

      if (fp = mm_popen (cmd, "r")) {
  	if (fgets (result, maxlen, fp) == result) {
===================================================================
RCS file: RCS/dates.c,v
retrieving revision 1.1
diff -c -r1.1 dates.c
*** /tmp/T0a004T7	Wed Feb 24 22:12:11 1993
--- dates.c	Wed Feb 24 21:40:28 1993
***************
*** 206,215 ****
  	    day_names[t->tm_wday],
  	    t->tm_mday, month_names[t->tm_mon], t->tm_year /*+ 1900*/,
  	    t->tm_hour, t->tm_min, t->tm_sec,
! #if BSD
  	    timezone(tb.timezone, t->tm_isdst)
  #endif
! #if SYSV
  	    tzname[t->tm_isdst ? 1 : 0]
  #endif
  	    );
--- 206,215 ----
  	    day_names[t->tm_wday],
  	    t->tm_mday, month_names[t->tm_mon], t->tm_year /*+ 1900*/,
  	    t->tm_hour, t->tm_min, t->tm_sec,
! #if BSD && !__solaris
  	    timezone(tb.timezone, t->tm_isdst)
  #endif
! #if SYSV || __solaris
  	    tzname[t->tm_isdst ? 1 : 0]
  #endif
  	    );
===================================================================
RCS file: RCS/edit.c,v
retrieving revision 1.1
diff -c -r1.1 edit.c
*** /tmp/T0a004T7	Wed Feb 24 22:12:12 1993
--- edit.c	Wed Feb 24 21:46:44 1993
***************
*** 530,535 ****
--- 530,536 ----
    char *parse_input_file();
    mail_msg *msg, *get_outgoing();	/* the parsed message. */
    message tmessage;
+   mail_msg *parse_msg();

    noise ("from file");
    fname = parse_input_file( nil, nil, false); /* get the filename */
***************
*** 655,660 ****
--- 656,662 ----
  {
      char *ntext, *otext;
      mail_msg *m;
+     mail_msg *get_outgoing();

      if (mode & MM_SEND) {
  	confirm();
***************
*** 681,686 ****
--- 683,689 ----
  {
      char *otext, *ntext;
      message *m = &cf->msgs[n];
+     keylist free_keylist();
      if (n <= 0)
  	return (true);			/* no initializing or ending */

===================================================================
RCS file: RCS/file.c,v
retrieving revision 1.1
diff -c -r1.1 file.c
*** /tmp/T0a004T7	Wed Feb 24 22:12:12 1993
--- file.c	Wed Feb 24 21:57:27 1993
***************
*** 121,128 ****

      cf = nf;				/* make new file current */

!     /* "take" filename.rc */
!     (void) take_file(filename, top_level_parser, FALSE);

      if (cf) do_flagged();

--- 121,129 ----

      cf = nf;				/* make new file current */

!     /* "take" filename.rc if it is "safe" */
!     if (safe_rc_file(filename))
! 	(void) take_file(filename, top_level_parser, FALSE);

      if (cf) do_flagged();

***************
*** 1120,1123 ****
--- 1121,1148 ----
      if ((stat(file, &statb) == 0) && (statb.st_size == 0))
  	return (TRUE);			/* it's empty */
      return (FALSE);
+ }
+
+
+ /*
+  * safe_rc_file:
+  * filename.rc is "safe" if it is owned either by the user running MM or
+  * if the file is owned by root AND the file is not group or world writable.
+  */
+
+ int
+ safe_rc_file(fname)
+ char *fname;
+ {
+     struct stat sbuf;
+
+     if (stat(fname, &sbuf) != 0) {
+ 	return(FALSE);
+     }
+     if (!(sbuf.st_uid == UID || sbuf.st_uid == 0) ||
+ 	sbuf.st_mode & 022) {
+ 	fprintf (stderr, "%s not safe, ignoring\n", fname);
+ 	return(FALSE);
+     }
+     return(TRUE);
  }
===================================================================
RCS file: RCS/parse.c,v
retrieving revision 1.1
diff -c -r1.1 parse.c
*** /tmp/T0a004T7	Wed Feb 24 22:12:15 1993
--- parse.c	Wed Feb 24 21:49:41 1993
***************
*** 840,845 ****
--- 840,846 ----
  			      NULL, NULL, NULL };
      static fdb cfmfdb = { _CMCFM, CM_SDH, NULL, NULL, "confirm to unset",
  			      NULL, NULL };
+     char *getwd();

      dirfdb._cmhlp = help ? help : "directory name";
      dirfdb._cmdef = def;
===================================================================
RCS file: RCS/rd.c,v
retrieving revision 1.1
diff -c -r1.1 rd.c
*** /tmp/T0a004T7	Wed Feb 24 22:12:16 1993
--- rd.c	Wed Feb 24 21:49:49 1993
***************
*** 56,62 ****
  					/* pop 3 client.   not written yet */
      { "pop3", pop3_open, pop3_close, pop3_rdmsg, pop3_wrmsg, pop3_probe },
  };
! num_msg_ops = sizeof(msg_ops) / sizeof(msg_handler);

  /*
   * make sure to update keywrd formatkeys[], which should be in
--- 56,62 ----
  					/* pop 3 client.   not written yet */
      { "pop3", pop3_open, pop3_close, pop3_rdmsg, pop3_wrmsg, pop3_probe },
  };
! int num_msg_ops = sizeof(msg_ops) / sizeof(msg_handler);

  /*
   * make sure to update keywrd formatkeys[], which should be in
===================================================================
RCS file: RCS/sendcmds.c,v
retrieving revision 1.1
diff -c -r1.1 sendcmds.c
*** /tmp/T0a004T7	Wed Feb 24 22:12:17 1993
--- sendcmds.c	Wed Feb 24 21:51:27 1993
***************
*** 400,405 ****
--- 400,406 ----
  {
      char *p, *cp;
      int lines,i;
+     char *safe_strcpy();

      if (reply_indent == NULL || strlen(reply_indent) == 0) {
  	return(safe_strcpy (msg));
***************
*** 458,463 ****
--- 459,465 ----
      int len;
      int ret;
      static addresslist temp = { NULL, NULL };
+     char *safe_strcat();

      parse_addresses(&temp);
      free_msg(&outgoing);
***************
*** 538,543 ****
--- 540,546 ----
      char *forwardees = NULL;
      char *head = NULL;
      char *forward_header(), *forward_banner();
+     char *safe_strcat();
      int ret;

      free_msg(&outgoing);
***************
*** 669,674 ****
--- 672,678 ----
  {
      int len;
      static addresslist temp = { NULL, NULL };
+     char *safe_strcpy();

      /* not a memory leak unless parse_msg starts to malloc */
      msg = parse_msg(&(cf->msgs[which]));
===================================================================
RCS file: RCS/sendmail.c,v
retrieving revision 1.1
diff -c -r1.1 sendmail.c
*** /tmp/T0a004T7	Wed Feb 24 22:12:17 1993
--- sendmail.c	Wed Feb 24 21:52:25 1993
***************
*** 652,657 ****
--- 652,658 ----
  {
      int result = true;
      char *cp, *sender, *from, *host, *create_sender();
+     char *safe_strcpy();

      sender = create_sender();
      str = (char *) safe_strcpy (str);	/* our personal copy */
===================================================================
RCS file: RCS/set.c,v
retrieving revision 1.1
diff -c -r1.1 set.c
*** /tmp/T0a004T7	Wed Feb 24 22:12:18 1993
--- set.c	Wed Feb 24 21:54:21 1993
***************
*** 62,68 ****
  	prompt_for_bcc = SET_NO,	/* prompt for bcc on send */
  	prompt_for_cc = SET_YES,	/* prompt for cc on send */
  	prompt_for_fcc = SET_NO,	/* prompt for fcc on send */
!         prompt_rcpt_always = SET_NO;	/* prompt even when "send foo" */
  	reply_all = SET_NO,		/* don't reply to everyone */
          reply_include_me = SET_NO,	/* replies go to self too */
      	reply_initial_display = SET_NO,	/* display To, Cc, etc when replying */
--- 62,68 ----
  	prompt_for_bcc = SET_NO,	/* prompt for bcc on send */
  	prompt_for_cc = SET_YES,	/* prompt for cc on send */
  	prompt_for_fcc = SET_NO,	/* prompt for fcc on send */
!         prompt_rcpt_always = SET_NO,	/* prompt even when "send foo" */
  	reply_all = SET_NO,		/* don't reply to everyone */
          reply_include_me = SET_NO,	/* replies go to self too */
      	reply_initial_display = SET_NO,	/* display To, Cc, etc when replying */
***************
*** 74,80 ****
          suspend_on_quit = SET_NO,	/* suspend when a quit is done */
          terse_text_prompt = SET_NO,	/* don't be terse when prompting */
  	use_editor_always = SET_NO,	/* don't use the editor by default */
!     	use_crt_filter_always = SET_NO;	/* don't always filter things */
  	use_invalid_address = SET_ASK;	/* ask about invalid addresses */

  string	crt_filter = { PAGER },
--- 74,80 ----
          suspend_on_quit = SET_NO,	/* suspend when a quit is done */
          terse_text_prompt = SET_NO,	/* don't be terse when prompting */
  	use_editor_always = SET_NO,	/* don't use the editor by default */
!     	use_crt_filter_always = SET_NO,	/* don't always filter things */
  	use_invalid_address = SET_ASK;	/* ask about invalid addresses */

  string	crt_filter = { PAGER },
102 sunrise::mm> exit
103 sunrise::mm> exit

script done on Wed Feb 24 22:12:24 1993
