From 9f8f8b1e1d553774865f2c177191c359c3dc652c Mon Sep 17 00:00:00 2001 From: David Levine Date: Sat, 21 Jul 2012 16:17:41 -0500 Subject: [PATCH] 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. --- Makefile.am | 17 ++--- docs/pending-release-notes | 6 ++ h/mh.h | 7 ++ h/prototypes.h | 3 + man/post.man | 20 ++++++ man/send.man | 20 ++++++ sbr/base64.c | 116 +++++++++++++++++++++++++++++++ sbr/m_rand.c | 51 ++++++++++++++ sbr/message_id.c | 87 ++++++++++++++++++++++++ test/post/test-messageid | 161 ++++++++++++++++++++++++++++++++++++++++++++ test/post/test-mts | 2 +- uip/mhbuildsbr.c | 11 ++- uip/mhoutsbr.c | 57 +--------------- uip/post.c | 19 ++++-- uip/send.c | 3 + uip/sendsbr.c | 3 +- uip/whatnowsbr.c | 3 + 17 files changed, 509 insertions(+), 77 deletions(-) create mode 100644 sbr/base64.c create mode 100644 sbr/m_rand.c create mode 100644 sbr/message_id.c create mode 100755 test/post/test-messageid diff --git a/Makefile.am b/Makefile.am index 387c31c..54c1250 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 \ diff --git a/docs/pending-release-notes b/docs/pending-release-notes index dd8c395..c286c3d 100644 --- a/docs/pending-release-notes +++ b/docs/pending-release-notes @@ -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 --- 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 diff --git a/h/prototypes.h b/h/prototypes.h index 9c4b208..d62fb7a 100644 --- a/h/prototypes.h +++ b/h/prototypes.h @@ -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 *); diff --git a/man/post.man b/man/post.man index 24465fc..bd048c0 100644 --- a/man/post.man +++ b/man/post.man @@ -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" ' diff --git a/man/send.man b/man/send.man index 73d922d..157c445 100644 --- a/man/send.man +++ b/man/send.man @@ -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 index 0000000..c3045ab --- /dev/null +++ b/sbr/base64.c @@ -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 +#include + +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 index 0000000..4d24888 --- /dev/null +++ b/sbr/m_rand.c @@ -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 /* for abs(), srand(), rand() */ +#include /* for fopen(), fread(), fclose() */ +#include /* for getpid() */ +#include /* 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 index 0000000..d0a6dd9 --- /dev/null +++ b/sbr/message_id.c @@ -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 +#include /* for getpid() */ +#include /* for gettimeofday() */ +#include + + +#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 index 0000000..b072cac --- /dev/null +++ b/test/post/test-messageid @@ -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" < +To: Somebody Else +Subject: Test + +This is a test +EOF + +cat > "${testname}.expected" < +RCPT TO: +DATA +From: Mr Nobody +To: Somebody Else +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" < +To: Somebody Else +Subject: Test + +This is a test +. +EOF + +cat > "${testname}.expected" < +To: Somebody Else +Subject: Test +Date: +Message-ID: + +This is a test +. +EOF + +test_messageid localname "${testname}.expected" + +# check -messageid random +cat > "${MH_TEST_DIR}/Mail/draft" < +To: Somebody Else +Subject: Test + +This is a test +. +EOF + +cat > "${testname}.expected" < +To: Somebody Else +Subject: Test +Date: +Message-ID: + +This is a test +. +EOF + +test_messageid random "${testname}.expected" + + +rm -f ${MHMTSCONF} + +exit ${failed:-0} diff --git a/test/post/test-mts b/test/post/test-mts index 29fb478..6011549 100755 --- a/test/post/test-mts +++ b/test/post/test-mts @@ -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 () { diff --git a/uip/mhbuildsbr.c b/uip/mhbuildsbr.c index 00a9408..0ebdaba 100644 --- a/uip/mhbuildsbr.c +++ b/uip/mhbuildsbr.c @@ -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); } diff --git a/uip/mhoutsbr.c b/uip/mhoutsbr.c index 8324991..97f97f0 100644 --- a/uip/mhoutsbr.c +++ b/uip/mhoutsbr.c @@ -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; -} diff --git a/uip/post.c b/uip/post.c index 3c47161..edc17d7 100644 --- a/uip/post.c +++ b/uip/post.c @@ -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"); diff --git a/uip/send.c b/uip/send.c index b9b2da0..7f0529e 100644 --- a/uip/send.c +++ b/uip/send.c @@ -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]); diff --git a/uip/sendsbr.c b/uip/sendsbr.c index 37a63a6..3865258 100644 --- a/uip/sendsbr.c +++ b/uip/sendsbr.c @@ -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++) { diff --git a/uip/whatnowsbr.c b/uip/whatnowsbr.c index a5dbb2b..1d21bd3 100644 --- a/uip/whatnowsbr.c +++ b/uip/whatnowsbr.c @@ -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]); -- 1.7.10.4