Added -messageid switch to send(1) and post(8). This allows selection
authorDavid Levine <levinedl@acm.org>
Sat, 21 Jul 2012 21:17:41 +0000 (16:17 -0500)
committerDavid Levine <levinedl@acm.org>
Sat, 21 Jul 2012 21:17:41 +0000 (16:17 -0500)
of the style to use for generated Message-ID and Content-ID header
fields.  The default localname style is pid.time@localname, where time
is in seconds, and matches previous behavior.  The random style
replaces the localname with some (pseudo)random bytes and uses
microsecond-resolution time.

17 files changed:
Makefile.am
docs/pending-release-notes
h/mh.h
h/prototypes.h
man/post.man
man/send.man
sbr/base64.c [new file with mode: 0644]
sbr/m_rand.c [new file with mode: 0644]
sbr/message_id.c [new file with mode: 0644]
test/post/test-messageid [new file with mode: 0755]
test/post/test-mts
uip/mhbuildsbr.c
uip/mhoutsbr.c
uip/post.c
uip/send.c
uip/sendsbr.c
uip/whatnowsbr.c

index 387c31c..54c1250 100644 (file)
@@ -65,7 +65,7 @@ TESTS = test/ali/test-ali \
        test/post/test-post-basic test/post/test-post-multiple \
        test/post/test-post-dcc test/post/test-post-fcc \
        test/post/test-post-multifrom test/post/test-post-envelope \
-       test/post/test-post-group test/post/test-mts \
+       test/post/test-post-group test/post/test-mts test/post/test-messageid \
        test/prompter/test-prompter \
        test/rcv/test-rcvdist test/rcv/test-rcvpack test/rcv/test-rcvstore \
        test/refile/test-refile \
@@ -462,15 +462,15 @@ uninstall-hook:
 ##
 ## Our rules to build our internal libraries (libmh.a, libmts.a)
 ##
-sbr_libmh_a_SOURCES = sbr/addrsbr.c sbr/ambigsw.c sbr/atooi.c sbr/brkstring.c \
-                     sbr/check_charset.c sbr/client.c sbr/closefds.c \
-                     sbr/concat.c sbr/context_del.c sbr/context_find.c \
-                     sbr/context_foil.c sbr/context_read.c \
+sbr_libmh_a_SOURCES = sbr/addrsbr.c sbr/ambigsw.c sbr/atooi.c sbr/base64.c \
+                     sbr/brkstring.c sbr/check_charset.c sbr/client.c \
+                     sbr/closefds.c sbr/concat.c sbr/context_del.c \
+                     sbr/context_find.c sbr/context_foil.c sbr/context_read.c \
                      sbr/context_replace.c sbr/context_save.c \
                      sbr/copy.c sbr/copyip.c sbr/cpydata.c \
                      sbr/cpydgst.c sbr/crawl_folders.c sbr/discard.c \
                      sbr/done.c sbr/dtime.c sbr/escape_addresses.c \
-                     sbr/error.c  sbr/ext_hook.c sbr/fdcompare.c \
+                     sbr/error.c sbr/ext_hook.c sbr/fdcompare.c \
                      sbr/folder_addmsg.c sbr/folder_delmsgs.c \
                      sbr/folder_free.c sbr/folder_pack.c \
                      sbr/folder_read.c sbr/folder_realloc.c sbr/gans.c \
@@ -480,8 +480,9 @@ sbr_libmh_a_SOURCES = sbr/addrsbr.c sbr/ambigsw.c sbr/atooi.c sbr/brkstring.c \
                      sbr/fmt_rfc2047.c sbr/fmt_scan.c sbr/lock_file.c \
                      sbr/m_atoi.c sbr/m_backup.c sbr/m_convert.c \
                      sbr/m_draft.c sbr/m_getfld.c sbr/m_gmprot.c \
-                     sbr/m_maildir.c sbr/m_name.c \
-                     sbr/makedir.c sbr/mts.c sbr/norm_charmap.c sbr/path.c \
+                     sbr/m_maildir.c sbr/m_name.c sbr/m_rand.c \
+                     sbr/makedir.c sbr/message_id.c sbr/mts.c \
+                     sbr/norm_charmap.c sbr/path.c \
                      sbr/peekc.c sbr/pidwait.c sbr/pidstatus.c \
                      sbr/print_help.c sbr/print_sw.c sbr/print_version.c \
                      sbr/push.c sbr/putenv.c sbr/refile.c sbr/remdir.c \
index dd8c395..c286c3d 100644 (file)
@@ -16,6 +16,12 @@ NEW FEATURES
   mhbuild will honor MIME directives by default.  And added support
   for special #on/#off/#pop directives to control the MIME directive
   processing state.
+- Added -messageid switch to send(1) and post(8).  This allows
+  selection of the style to use for generated Message-ID and
+  Content-ID header fields.  The default localname style is
+  pid.time@localname, where time is in seconds, and matches previous
+  behavior.  The random style replaces the localname with some
+  (pseudo)random bytes and uses microsecond-resolution time.
 
 ----------------------------
 OBSOLETE/DEPRECATED FEATURES
diff --git a/h/mh.h b/h/mh.h
index 09d9f27..225d0c9 100644 (file)
--- a/h/mh.h
+++ b/h/mh.h
@@ -298,6 +298,13 @@ extern char *defpath;              /* pathname of user's profile      */
 extern char *ctxpath;          /* pathname of user's context      */
 extern struct node *m_defs;    /* list of profile/context entries */
 
+/* What style to use for generated Message-ID and Content-ID header
+   fields.  The localname style is pid.time@localname, where time is
+   in seconds.  The random style replaces the localname with some
+   (pseudo)random bytes and uses microsecond-resolution time. */
+int save_message_id_style (const char *);
+char *message_id (time_t, int);
+
 /*
  * These standard strings are defined in config.c.  They are the
  * only system-dependent parameters in nmh, and thus by redefining
index 9c4b208..d62fb7a 100644 (file)
@@ -82,10 +82,12 @@ char *m_maildir (char *);
 char *m_mailpath (char *);
 char *m_name (int);
 int m_putenv (char *, char *);
+int m_rand (unsigned char *, size_t);
 char *m_mktemp(const char *, int *, FILE **);
 char *m_mktemp2(const char *, const char *, int *, FILE **);
 void m_unknown(FILE *);
 int makedir (char *);
+char *message_id (time_t, int);
 char *nmh_getpass(const char *);
 char *norm_charmap(char *);
 char *new_fs (char *, char *, char *);
@@ -166,3 +168,4 @@ int what_now (char *, int, int, char *, char *,
        int, struct msgs *, char *, int, char *, int);
 int WhatNow(int, char **);
 int writeBase64aux(FILE *, FILE *);
+int writeBase64 (unsigned char *, size_t, unsigned char *);
index 24465fc..bd048c0 100644 (file)
@@ -16,6 +16,8 @@ post \- deliver a message
 .RB [ \-format " | " \-noformat ]
 .RB [ \-mime " | " \-nomime ]
 .RB [ \-msgid " | " \-nomsgid ]
+.RB [ \-messageid
+.IR localname " | " random ]
 .RB [ \-verbose " | " \-noverbose ]
 .RB [ \-watch " | " \-nowatch ]
 .RB [ \-width
@@ -112,6 +114,23 @@ switch indicates that a \*(lqMessage\-ID:\*(rq or
 \*(lqResent\-Message\-ID:\*(rq field should be added to the header.
 .PP
 The
+.B \-messageid
+switch selects the style used for the part appearing after the @
+in \*(lqMessage\-ID:\*(rq, \*(lqResent\-Message\-ID:\*(rq, and
+\*(lqContent\-ID:\*(rq header fields.  The two acceptable options are
+.B localname
+(which is the default),
+and
+.BR random .
+With
+.BR localname ,
+the local hostname is used.  With
+.BR random ,
+a random sequence of characters is used instead.  Note that the
+.B \-msgid
+switch must be enabled for this switch to have any effect.
+.PP
+The
 .B \-verbose
 switch indicates that the user should be informed of
 each step of the posting/filing process.
@@ -246,6 +265,7 @@ mhmail(1), send(1), mh\-mail(5), mh\-alias(5), mh\-tailor(5),
 .RB ` \-format '
 .RB ` \-nomime '
 .RB ` \-nomsgid '
+.RB ` "\-messageid\ localname" '
 .RB ` \-noverbose '
 .RB ` \-nowatch '
 .RB ` "\-width\ 72" '
index 73d922d..157c445 100644 (file)
@@ -23,6 +23,8 @@ send \- send a message
 .RB [ \-forward " | " \-noforward ]
 .RB [ \-mime " | " \-nomime ]
 .RB [ \-msgid " | " \-nomsgid ]
+.RB [ \-messageid
+.IR localname " | " random ]
 .RB [ \-push " | " \-nopush ]
 .RB [ \-split
 .IR seconds ]
@@ -293,6 +295,23 @@ If
 is specified, then a \*(lqMessage\-ID:\*(rq field will also
 be added to the message.
 .PP
+The
+.B \-messageid
+switch selects the style used for the part appearing after the @
+in \*(lqMessage\-ID:\*(rq, \*(lqResent\-Message\-ID:\*(rq, and
+\*(lqContent\-ID:\*(rq header fields.  The two acceptable options are
+.B localname
+(which is the default),
+and
+.BR random .
+With
+.BR localname ,
+the local hostname is used.  With
+.BR random ,
+a random sequence of characters is used instead.  Note that the
+.B \-msgid
+switch must be enabled for this switch to have any effect.
+.PP
 If
 .B send
 is re\-distributing a message (when invoked by
@@ -451,6 +470,7 @@ comp(1), dist(1), forw(1), repl(1), mh\-alias(5), mh\-tailor(5), post(8)
 .RB ` \-forward '
 .RB ` \-nomime '
 .RB ` \-nomsgid '
+.RB ` "\-messageid\ localname" '
 .RB ` \-nopush '
 .RB ` \-noverbose '
 .RB ` \-nowatch '
diff --git a/sbr/base64.c b/sbr/base64.c
new file mode 100644 (file)
index 0000000..c3045ab
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * base64.c -- routines for converting to base64
+ *
+ * This code is Copyright (c) 2012, by the authors of nmh.  See the
+ * COPYRIGHT file in the root directory of the nmh distribution for
+ * complete copyright information.
+ */
+
+#include <h/mh.h>
+#include <h/mime.h>
+
+static char nib2b64[0x40+1] =
+       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+int
+writeBase64aux (FILE *in, FILE *out)
+{
+    unsigned int cc, n;
+    char inbuf[3];
+
+    n = BPERLIN;
+    while ((cc = fread (inbuf, sizeof(*inbuf), sizeof(inbuf), in)) > 0) {
+       unsigned long bits;
+       char *bp;
+       char outbuf[4];
+
+       if (cc < sizeof(inbuf)) {
+           inbuf[2] = 0;
+           if (cc < sizeof(inbuf) - 1)
+               inbuf[1] = 0;
+       }
+       bits = (inbuf[0] & 0xff) << 16;
+       bits |= (inbuf[1] & 0xff) << 8;
+       bits |= inbuf[2] & 0xff;
+
+       for (bp = outbuf + sizeof(outbuf); bp > outbuf; bits >>= 6)
+           *--bp = nib2b64[bits & 0x3f];
+       if (cc < sizeof(inbuf)) {
+           outbuf[3] = '=';
+           if (cc < sizeof inbuf - 1)
+               outbuf[2] = '=';
+       }
+
+       fwrite (outbuf, sizeof(*outbuf), sizeof(outbuf), out);
+
+       if (cc < sizeof(inbuf)) {
+           putc ('\n', out);
+           return OK;
+       }
+
+       if (--n <= 0) {
+           n = BPERLIN;
+           putc ('\n', out);
+       }
+    }
+    if (n != BPERLIN)
+       putc ('\n', out);
+
+    return OK;
+}
+
+
+/* Caller is responsible for ensuring that the out array is long
+   enough.  Given length is that of in, out should be have at
+   least this capacity:
+     4 * [length/3]  +  length/57  +  2
+   But double the length will certainly be sufficient. */
+int
+writeBase64 (unsigned char *in, size_t length, unsigned char *out)
+{
+    unsigned int n = BPERLIN;
+
+    while (1) {
+       unsigned long bits;
+       unsigned char *bp;
+       unsigned int cc;
+       for (cc = 0, bp = in; length > 0 && cc < 3; ++cc, ++bp, --length)
+          /* empty */ ;
+
+       if (cc == 0) {
+           break;
+       } else {
+           bits = (in[0] & 0xff) << 16;
+           if (cc > 1) {
+               bits |= (in[1] & 0xff) << 8;
+               if (cc > 2) {
+                   bits |= in[2] & 0xff;
+               }
+           }
+       }
+
+       for (bp = out + 4; bp > out; bits >>= 6)
+           *--bp = nib2b64[bits & 0x3f];
+       if (cc < 3) {
+           out[3] = '=';
+           if (cc < 2)
+               out[2] = '=';
+           out += 4;
+           n = 0;
+           break;
+       }
+
+       in += 3;
+       out += 4;
+       if (--n <= 0) {
+           n = BPERLIN;
+           *out++ = '\n';
+       }
+    }
+    if (n != BPERLIN)
+       *out++ = '\n';
+
+    *out = '\0';
+
+    return OK;
+}
diff --git a/sbr/m_rand.c b/sbr/m_rand.c
new file mode 100644 (file)
index 0000000..4d24888
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * m_rand -- provides pseudorandom bytes
+ *
+ * This code is Copyright (c) 2012, by the authors of nmh.  See the
+ * COPYRIGHT file in the root directory of the nmh distribution for
+ * complete copyright information.
+ */
+
+#include <stdlib.h>  /* for abs(), srand(), rand() */
+#include <stdio.h>   /* for fopen(), fread(), fclose() */
+#include <unistd.h>  /* for getpid() */
+#include <time.h>    /* for time() */
+
+static int seeded = 0;
+
+
+int
+m_rand (unsigned char *buf, size_t n) {
+  if (! seeded) {
+    FILE *devurandom;
+    unsigned int seed;
+
+    if ((devurandom = fopen ("/dev/urandom", "r"))) {
+      if (fread (&seed, sizeof (seed), 1, devurandom) == 1) seeded = 1;
+      fclose (devurandom);
+    }
+
+    if (! seeded) {
+      /* This seed calculation is from Helmut G. Katzgraber, "Random
+         Numbers in Scientific Computing:  An Introduction",
+         arXiv:1005.4117v1 [physics.comp-ph], 22 May 2010, p. 19.
+         time() and getpid() shouldn't fail on POSIX platforms. */
+      seed = abs ((int) ((time (0) * 181 * ((getpid ()-83) * 359)) % 104729));
+      seeded = 1;
+    }
+
+    srand (seed);
+  }
+
+  while (n > 0) {
+    int rnd = rand ();
+    unsigned char *rndp = (unsigned char *) &rnd;
+    unsigned int i;
+
+    for (i = 0; i < sizeof rnd  &&  n > 0;  ++i, --n) {
+      *buf++ = *rndp++;
+    }
+  }
+
+  return 0;
+}
diff --git a/sbr/message_id.c b/sbr/message_id.c
new file mode 100644 (file)
index 0000000..d0a6dd9
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * message-id.c -- construct the body of a Message-ID or Content-ID
+ *                 header field
+ *
+ * This code is Copyright (c) 2012, by the authors of nmh.  See the
+ * COPYRIGHT file in the root directory of the nmh distribution for
+ * complete copyright information.
+ */
+
+#include <h/mh.h>
+#include <unistd.h>   /* for getpid() */
+#include <sys/time.h> /* for gettimeofday() */
+#include <stdio.h>
+
+
+#define NMH_MESSAGE_ID_LOCALNAME 0
+#define NMH_MESSAGE_ID_RANDOM 1
+
+static int message_id_style = NMH_MESSAGE_ID_LOCALNAME;
+static char message_id_[BUFSIZ];
+
+
+/* Convert name of message id style to integer value and store it. */
+int
+save_message_id_style (const char *value) {
+  if (! mh_strcasecmp (value, "localname")) {
+    message_id_style = NMH_MESSAGE_ID_LOCALNAME;
+    return 0;
+  } else if (! mh_strcasecmp (value, "random")) {
+    message_id_style = NMH_MESSAGE_ID_RANDOM;
+    return 0;
+  } else {
+    return 1;
+  }
+}
+
+
+char *
+message_id (time_t tclock, int content_id) {
+  if (message_id_style == NMH_MESSAGE_ID_LOCALNAME) {
+    char *format = content_id  ?  "<%d.%ld.%%d@%s>"  :  "<%d.%ld@%s>";
+
+    snprintf (message_id_, sizeof message_id_, format,
+              (int) getpid (), (long) tclock, LocalName (1));
+  } else if  (message_id_style == NMH_MESSAGE_ID_RANDOM) {
+    char *format = content_id ? "<%d-%ld.%06ld%%d@%s>" : "<%d-%ld.%06ld@%s>";
+    /* Use a sequence of digits divisible by 3 because that will
+       expand to base64 without any waste.  Must be shorter than 58,
+       see below. */
+    unsigned char rnd[12];
+
+    if (m_rand (rnd, sizeof rnd) == 0) {
+      pid_t pid;
+      struct timeval now;
+      /* All we really need is 4 * [sizeof rnd/3] + 2, as long as the
+         base64 encoding stays shorter than 76 bytes so embedded
+         newlines aren't necessary.  But use double the sizeof rnd
+         just to be safe. */
+      unsigned char rnd_base64[2 * sizeof rnd];
+      int i;
+
+      writeBase64 (rnd, sizeof rnd, rnd_base64);
+
+      for (i = strlen ((const char *) rnd_base64) - 1;
+           i > 0  &&  iscntrl (rnd_base64[i]);
+           --i) {
+        /* Remove trailing newline.  rnd_base64 had better be shorter
+           than 76 characters, so don't bother to look for embedded
+           newlines. */
+        rnd_base64[i] = '\0';
+      }
+
+      /* Neither of these can fail according to the POSIX spec. */
+      pid = getpid ();
+      gettimeofday (&now, 0);
+
+      snprintf (message_id_, sizeof message_id_, format,
+                pid, (long) now.tv_sec, (long) now.tv_usec, rnd_base64);
+    }
+  } else {
+    /* Should never get here. */
+    adios (0, "invalid message id style \"%s\"", message_id_style);
+  }
+
+
+  return message_id_;
+}
diff --git a/test/post/test-messageid b/test/post/test-messageid
new file mode 100755 (executable)
index 0000000..b072cac
--- /dev/null
@@ -0,0 +1,161 @@
+#!/bin/sh
+#
+# Test post -messageid
+#
+
+set -e
+
+if test -z "${MH_OBJ_DIR}"; then
+    srcdir=`dirname "$0"`/../..
+    MH_OBJ_DIR=`cd "$srcdir" && pwd`; export MH_OBJ_DIR
+fi
+
+. "${MH_OBJ_DIR}/test/common.sh"
+
+setup_test
+testname="${MH_TEST_DIR}/$$"
+
+
+cat > "${MH_TEST_DIR}/Mail/draft" <<EOF
+From: Mr Nobody <nobody@example.com>
+To: Somebody Else <somebody@example.com>
+Subject: Test
+
+This is a test
+EOF
+
+cat > "${testname}.expected" <<EOF
+EHLO nosuchhost.example.com
+MAIL FROM:<nobody@example.com>
+RCPT TO:<somebody@example.com>
+DATA
+From: Mr Nobody <nobody@example.com>
+To: Somebody Else <somebody@example.com>
+Subject: Test
+Date:
+
+This is a test
+.
+QUIT
+EOF
+
+# check invalid -messageid selection
+run_test "send -draft -messageid invalid" \
+"post: unsupported messageid \"invalid\"
+send: message not delivered to anyone"
+
+#### Rely on sendmail/pipe below to override default mts.
+mts_fakesendmail="${MHMTSCONF}-fakesendmail"
+cp "${MHMTSCONF}" "$mts_fakesendmail"
+printf "%s\n" "sendmail: ${srcdir}/test/fakesendmail" >>"$mts_fakesendmail"
+MHMTSCONF="$mts_fakesendmail"
+
+# $1: -messageid switch selection
+# arguments: expected output(s)
+test_messageid ()
+{
+  msgid_style="$1"
+  send -draft -mts sendmail/pipe -msgid -messageid "$msgid_style"
+  shift
+
+  # fakesendmail drops the message and any cc's into this mbox.
+  mbox="${MH_TEST_DIR}"/Mail/fakesendmail.mbox
+  inc -silent -file "$mbox"
+  rm -f "$mbox" "$mbox.map"
+
+  n=1
+  for expected in "$@"; do
+    cur=`mhpath cur`
+    # Verify that Message-ID is of the right form.  We'll see how
+    # portable these grep regular expressions are.
+    case "$msgid_style" in
+      localname)
+        # e.g., Message-ID: <5348.1342884222@localhost.localdomain>
+        id='^Message-ID: <[0-9]\{1,\}\.[0-9]\{1,\}@'
+        ;;
+      random)
+        # e.g., Message-ID: <5364-1342884222.165897@ldYMFXwUbBqKcZwg>
+        id=\
+'^Message-ID: <[0-9]\{1,\}-[0-9]\{1,\}\.[0-9]\{6,6\}@[+/0-9A-Za-z]\{16,16\}'
+        ;;
+      *)         printf "$0: unexpected messageid: $msgid_style"; exit 1;;
+    esac
+
+    if grep "$id" "$cur" >/dev/null; then
+      :
+    else
+      mv "$cur" "${testname}.actual"
+      printf "$0: unexpected "$msgid_style" Message-ID format, \
+see ${testname}.actual\n"
+      exit 1
+    fi
+
+    #
+    # It's hard to calculate the exact Date: header post is going to
+    # use, so we'll just use sed to remove the actual date so we can easily
+    # compare it against our "correct" output.  And same for
+    # Message-ID.
+    #
+    sed -e 's/^Date:.*/Date:/' \
+        -e 's/^Message-ID:.*/Message-ID:/' \
+        "$cur" > "${testname}.actual$n"
+
+    check "${testname}.actual$n" "$expected"
+
+    if [ "$cur" != "`mhpath last`" ]; then
+      folder next >/dev/null
+      arith_eval $n + 1; n=$arith_val
+    fi
+  done
+}
+
+# check -messageid localname (the default)
+cat > "${MH_TEST_DIR}/Mail/draft" <<EOF
+From: Mr Nobody <nobody@example.com>
+To: Somebody Else <somebody@example.com>
+Subject: Test
+
+This is a test
+.
+EOF
+
+cat > "${testname}.expected" <<EOF
+From: Mr Nobody <nobody@example.com>
+To: Somebody Else <somebody@example.com>
+Subject: Test
+Date:
+Message-ID:
+
+This is a test
+.
+EOF
+
+test_messageid localname "${testname}.expected"
+
+# check -messageid random
+cat > "${MH_TEST_DIR}/Mail/draft" <<EOF
+From: Mr Nobody <nobody@example.com>
+To: Somebody Else <somebody@example.com>
+Subject: Test
+
+This is a test
+.
+EOF
+
+cat > "${testname}.expected" <<EOF
+From: Mr Nobody <nobody@example.com>
+To: Somebody Else <somebody@example.com>
+Subject: Test
+Date:
+Message-ID:
+
+This is a test
+.
+EOF
+
+test_messageid random "${testname}.expected"
+
+
+rm -f ${MHMTSCONF}
+
+exit ${failed:-0}
index 29fb478..6011549 100755 (executable)
@@ -50,7 +50,7 @@ cp "${MHMTSCONF}" "$mts_fakesendmail"
 printf "%s\n" "sendmail: ${srcdir}/test/fakesendmail" >>"$mts_fakesendmail"
 MHMTSCONF="$mts_fakesendmail"
 
-# $1: option switches for send
+# $1: -mts switch selection
 # remaining arguments: expected output(s)
 test_sendmail ()
 {
index 00a9408..0ebdaba 100644 (file)
@@ -895,20 +895,19 @@ use_forw:
 static void
 set_id (CT ct, int top)
 {
-    char msgid[BUFSIZ];
+    char contentid[BUFSIZ];
     static int partno;
     static time_t clock = 0;
     static char *msgfmt;
 
     if (clock == 0) {
        time (&clock);
-       snprintf (msgid, sizeof(msgid), "<%d.%ld.%%d@%s>\n",
-               (int) getpid(), (long) clock, LocalName(1));
+       snprintf (contentid, sizeof(contentid), "%s\n", message_id (clock, 1));
        partno = 0;
-       msgfmt = getcpy(msgid);
+       msgfmt = getcpy(contentid);
     }
-    snprintf (msgid, sizeof(msgid), msgfmt, top ? 0 : ++partno);
-    ct->c_id = getcpy (msgid);
+    snprintf (contentid, sizeof(contentid), msgfmt, top ? 0 : ++partno);
+    ct->c_id = getcpy (contentid);
 }
 
 
index 8324991..97f97f0 100644 (file)
@@ -57,9 +57,6 @@ static char ebcdicsafe[0x100] = {
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 };
 
-static char nib2b64[0x40+1] =
-       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
 /*
  * prototypes
  */
@@ -74,7 +71,7 @@ static void output_headers (CT, FILE *);
 static int writeExternalBody (CT, FILE *);
 static int write8Bit (CT, FILE *);
 static int writeQuoted (CT, FILE *);
-static int writeBase64 (CT, FILE *);
+static int writeBase64ct (CT, FILE *);
 
 
 /*
@@ -198,7 +195,7 @@ output_content (CT ct, FILE *out)
 
        case CE_BASE64:
            putc ('\n', out);
-           result = writeBase64 (ct, out);
+           result = writeBase64ct (ct, out);
            break;
 
        case CE_BINARY:
@@ -410,7 +407,7 @@ three_print:
  */
 
 static int
-writeBase64 (CT ct, FILE *out)
+writeBase64ct (CT ct, FILE *out)
 {
     int        fd, result;
     char *file;
@@ -424,51 +421,3 @@ writeBase64 (CT ct, FILE *out)
     (*ct->c_ceclosefnx) (ct);
     return result;
 }
-
-
-int
-writeBase64aux (FILE *in, FILE *out)
-{
-    unsigned int cc, n;
-    char inbuf[3];
-
-    n = BPERLIN;
-    while ((cc = fread (inbuf, sizeof(*inbuf), sizeof(inbuf), in)) > 0) {
-       unsigned long bits;
-       char *bp;
-       char outbuf[4];
-
-       if (cc < sizeof(inbuf)) {
-           inbuf[2] = 0;
-           if (cc < sizeof(inbuf) - 1)
-               inbuf[1] = 0;
-       }
-       bits = (inbuf[0] & 0xff) << 16;
-       bits |= (inbuf[1] & 0xff) << 8;
-       bits |= inbuf[2] & 0xff;
-
-       for (bp = outbuf + sizeof(outbuf); bp > outbuf; bits >>= 6)
-           *--bp = nib2b64[bits & 0x3f];
-       if (cc < sizeof(inbuf)) {
-           outbuf[3] = '=';
-           if (cc < sizeof inbuf - 1)
-               outbuf[2] = '=';
-       }
-
-       fwrite (outbuf, sizeof(*outbuf), sizeof(outbuf), out);
-
-       if (cc < sizeof(inbuf)) {
-           putc ('\n', out);
-           return OK;
-       }
-
-       if (--n <= 0) {
-           n = BPERLIN;
-           putc ('\n', out);
-       }
-    }
-    if (n != BPERLIN)
-       putc ('\n', out);
-
-    return OK;
-}
index 3c47161..edc17d7 100644 (file)
@@ -133,6 +133,8 @@ static struct swit switches[] = {
     { "mhlproc", -3 },
 #define MTSSW                   40
     { "mts smtp|sendmail/smtp|sendmail/pipe", 2 },
+#define MESSAGEIDSW             41
+    { "messageid localname|random", 2 },
     { NULL, 0 }
 };
 
@@ -526,6 +528,13 @@ main (int argc, char **argv)
                        adios (NULL, "missing argument to %s", argp[-2]);
                     save_mts_method (cp);
                    continue;
+
+               case MESSAGEIDSW:
+                   if (!(cp = *argp++) || *cp == '-')
+                       adios (NULL, "missing argument to %s", argp[-2]);
+                    if (save_message_id_style (cp) != 0)
+                       adios (NULL, "unsupported messageid \"%s\"", cp);
+                   continue;
            }
        }
        if (msg)
@@ -970,8 +979,7 @@ finish_headers (FILE *out)
 
            fprintf (out, "Date: %s\n", dtime (&tclock, 0));
            if (msgid)
-               fprintf (out, "Message-ID: <%d.%ld@%s>\n",
-                       (int) getpid (), (long) tclock, LocalName (1));
+               fprintf (out, "Message-ID: %s\n", message_id (tclock, 0));
            /*
             * If we have multiple From: addresses, make sure we have an
             * Sender: header.  If we don't have one, then generate one
@@ -1020,8 +1028,8 @@ finish_headers (FILE *out)
 
            fprintf (out, "Resent-Date: %s\n", dtime (&tclock, 0));
            if (msgid)
-               fprintf (out, "Resent-Message-ID: <%d.%ld@%s>\n",
-                       (int) getpid (), (long) tclock, LocalName (1));
+               fprintf (out, "Resent-Message-ID: %s\n",
+                        message_id (tclock, 0));
            /*
             * If we have multiple Resent-From: addresses, make sure we have an
             * Resent-Sender: header.  If we don't have one, then generate one
@@ -1276,8 +1284,7 @@ make_bcc_file (int dashstuff)
 
     fprintf (out, "Date: %s\n", dtime (&tclock, 0));
     if (msgid)
-       fprintf (out, "Message-ID: <%d.%ld@%s>\n",
-               (int) getpid (), (long) tclock, LocalName (1));
+       fprintf (out, "Message-ID: %s\n", message_id (tclock, 0));
     if (subject)
        fprintf (out, "Subject: %s", subject);
     fprintf (out, "BCC:\n");
index b9b2da0..7f0529e 100644 (file)
@@ -124,6 +124,8 @@ static struct swit switches[] = {
     { "notls", TLSminc(-5) },
 #define MTSSW                48
     { "mts smtp|sendmail/smtp|sendmail/pipe", 2 },
+#define MESSAGEIDSW          49
+    { "messageid localname|random", 2 },
     { NULL, 0 }
 };
 
@@ -304,6 +306,7 @@ main (int argc, char **argv)
                case USERSW:
                case PORTSW:
                case MTSSW:
+               case MESSAGEIDSW:
                    vec[vecp++] = --cp;
                    if (!(cp = *argp++) || *cp == '-')
                        adios (NULL, "missing argument to %s", argp[-2]);
index 37a63a6..3865258 100644 (file)
@@ -678,8 +678,7 @@ splitmsg (char **vec, int vecp, char *drft, struct stat *st, int delay)
        vec[vecp++] = "-queued";
 
     time (&clock);
-    snprintf (msgid, sizeof(msgid), "<%d.%ld@%s>",
-               (int) getpid(), (long) clock, LocalName(1));
+    snprintf (msgid, sizeof(msgid), "%s", message_id (clock, 0));
 
     fseek (in, start, SEEK_SET);
     for (partno = 1; partno <= nparts; partno++) {
index a5dbb2b..1d21bd3 100644 (file)
@@ -1075,6 +1075,8 @@ static struct swit  sendswitches[] = {
     { "notls", TLSminc(-5) },
 #define MTSSW            47
     { "mts smtp|sendmail/smtp|sendmail/pipe", 2 },
+#define MESSAGEIDSW      48
+    { "messageid localname|random", 2 },
     { NULL, 0 }
 };
 
@@ -1252,6 +1254,7 @@ sendit (char *sp, char **arg, char *file, int pushed)
                case USERSW:
                case PORTSW:
                case MTSSW:
+               case MESSAGEIDSW:
                    vec[vecp++] = --cp;
                    if (!(cp = *argp++) || *cp == '-') {
                        advise (NULL, "missing argument to %s", argp[-2]);