Eric Wong [Fri, 4 Jan 2019 11:53:02 +0000 (11:53 +0000)]
t/cgi.t: remove more redundant tests
Most of these test cases are in t/plack.t, already; and that
runs much faster. Just ensure the slashy corner case and search
stuff works. While we're at it, avoid using the
public-inbox-index command and just use the internal API to
index.
Eric Wong [Wed, 2 Jan 2019 00:50:55 +0000 (00:50 +0000)]
t/v2reindex: use the larger text to increase test reliability
libxapian30:amd64 1.4.9-1 on Debian sid seems to give an 8KB
position.glass database with "hello world" as the document
regardless of our indexlevel. Use the text of the AGPL-3.0 for
a more realisitic Xapian database size.
And perhaps tying our tests to the AGPL will make life more
difficult for would-be copyright violators :>
With the mboxrd downloaded, mutt is able to view them without
difficulty.
Note: this change would require reindexing of Xapian to pick up
the changes. But it's only two ancient messages, the first was
resent by the original sender and the second is too old to be
relevant.
Eric Wong [Wed, 26 Dec 2018 09:07:49 +0000 (09:07 +0000)]
tests: consolidate process spawning code.
IPC::Run provides a nice simplification in several places; and
we already use it (optionally) on a lot of tests.
For the non-test code, we still rely on our vfork-capable
Inline::C stuff since real-world server processes can get large
enough to where vfork is an advantage. Maybe Perl5 can use
CLONE_VFORK somehow, one day:
Eric Wong [Fri, 28 Dec 2018 06:22:55 +0000 (06:22 +0000)]
examples/cgit-commit-filter.lua: update URLs
Let's Encrypt is working out nicely, so we can rely on HTTPS,
now. Use 80x24.org instead of bogomips.org while we're at it,
since I don't think the latter will remain.
Eric Wong [Fri, 28 Dec 2018 10:16:11 +0000 (10:16 +0000)]
init: allow --skip of old epochs for -V2 repos
This allows archivists to publish incomplete archives with newer
mail while allowing "0.git" (or "1.git" and so on) epochs to be
added-after-the-fact (without affecting "git clone" followers).
A reindex will be necessary for Xapian and SQLite to catch up
once the old epochs are added; but the reindexing code is also
capable of tolerating missing epochs.
Eric Wong [Wed, 12 Dec 2018 23:18:13 +0000 (23:18 +0000)]
doc/hosted: add glibc and bug-gnulib mirrors
These have existed for a while, actually, so, we might as well
publicize them. While we're at it, add a disclaimer to
discourage reliance on single points of failure.
Eric Wong [Thu, 6 Dec 2018 02:40:06 +0000 (02:40 +0000)]
nntp: prevent event_read from firing twice in a row
When a client starts pipelining requests to us which trigger
long responses, we need to keep socket readiness checks disabled
and only enable them when our socket rbuf is drained.
Failure to do this caused aborted clients with
"BUG: nested long response" when Danga::Socket calls event_read
for read-readiness after our "next_tick" sub fires in the
same event loop iteration.
Reported-by: Jonathan Corbet <corbet@lwn.net>
cf. https://public-inbox.org/meta/20181013124658.23b9f9d2@lwn.net/
Jonathan Corbet [Sat, 13 Oct 2018 21:42:21 +0000 (15:42 -0600)]
Add Xrefs to over/xover lines
Putting the Xref field into xover lines allows newsreaders to mark
cross-posted messages read when catching up a group. That, in turn,
massively improves the life of crazy people who try to follow dozens of
kernel lists, where emails are often heavily cross-posted.
Jonathan Corbet [Sat, 13 Oct 2018 21:42:20 +0000 (15:42 -0600)]
Put the NNTP server name into Xref lines
RFC 5536 sec 3.2.14 says that the server-name in an Xref line is "which
news server generated the header field"; indeed, that is necessary for
newsreaders like gnus to handle references properly. So pick up the server
name from the config if available (the first name if there's more than
one), from the host name otherwise, and use it rather than the domain
name of the list server.
Tests have been adjusted to match the new behavior.
Eric W. Biederman [Fri, 10 Aug 2018 00:08:22 +0000 (19:08 -0500)]
Import.pm: When purging replace a purged file with a zero length file
This ensures that the number of added files remains the same and thus
the article numbers derived from a repository will remain the same.
I think this is the last place in public-inbox that has to be tweaked to
guarantee the generated article number will remain the same in an public
inbox archive.
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Eric Wong [Sun, 5 Aug 2018 08:19:25 +0000 (08:19 +0000)]
overidx: preserve `tid' column on re-indexing
Otherwise, walking backwards through history could mean the root
message in a thread forgets its `tid' and it prevents messages
from being looked up by it.
This bug was hidden by the fact that `sid' matches were often
good enough to link threads together.
Eric Wong [Sun, 5 Aug 2018 06:04:40 +0000 (06:04 +0000)]
view: distinguish strict and loose thread matches
The "loose" (Subject:-based) thread matching yields too many
hits for some common subjects (e.g. "[GIT] Networking" on LKML)
and causes thread skeletons to not show the current messages.
Favor strict matches in the query and only add loose matches
if there's space.
While working on this, I noticed the backwards --reindex walk
breaks `tid' on v1 repositories, at least. That bug was hidden
by the Subject: match logic and not discovered until now. It
will be fixed separately.
Reported-by: Konstantin Ryabitsev <konstantin@linuxfoundation.org>
Eric Wong [Fri, 3 Aug 2018 20:05:24 +0000 (20:05 +0000)]
Merge branch 'eb/index-incremental'
Incremental indexing fixes from Eric W. Biederman.
These prevents the highest message number in msgmap from
being reassigned after deletes in rare cases and ensures
messages are deleted from msgmap in v2.
* eb/index-incremental:
V2Writeable.pm: In unindex_oid delete the message from msgmap
V2Writeable.pm: Ensure that a found message number is in the msgmap
SearchIdx,V2Writeable: Update num_highwater on optimized deletes
t/v[12]reindex.t: Verify the num highwater is as expected
t/v[12]reindex.t Verify num_highwater
Msgmap.pm: Track the largest value of num ever assigned
SearchIdx.pm: Always assign numbers backwards during incremental indexing
t/v[12]reindex.t: Test incremental indexing works
t/v[12]reindex.t: Test that the resulting msgmap is as expected
t/v[12]reindex.t: Place expected second in Xapian tests
t/v2reindex.t: Isolate the test cases more
t/v1reindex.t: Isolate the test cases
Import.pm: Don't assume {in} and {out} always exist
Eric W. Biederman [Wed, 1 Aug 2018 16:43:44 +0000 (11:43 -0500)]
V2Writeable.pm: In unindex_oid delete the message from msgmap
Now that we track the num highwater mark it is safe to remove messages
from msgmap that have been previously allocated. Removing even the
highest numbered article will no longer cause new message numbers to
move backwards.
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Eric W. Biederman [Wed, 1 Aug 2018 16:43:43 +0000 (11:43 -0500)]
V2Writeable.pm: Ensure that a found message number is in the msgmap
The lookup to see if a num has already been assigned to a message
happens in a temporary copy of message map. It is possible that the
number has been removed from the current message map. The
unindex/reindex after a history rewrite triggered by a purge should be
one such case. Therefore add the number to the msgmap in case it is
not currently present.
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Eric W. Biederman [Wed, 1 Aug 2018 16:43:42 +0000 (11:43 -0500)]
SearchIdx,V2Writeable: Update num_highwater on optimized deletes
When performing an incremental index update with index_sync if a message is seen
to be both added and deleted update the num_highwater mark even though the
message is not otherwise indexed.
This ensures index_sync generates the same msgmap no matter which commit
it stops at during incremental syncs.
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Eric W. Biederman [Wed, 1 Aug 2018 16:43:39 +0000 (11:43 -0500)]
Msgmap.pm: Track the largest value of num ever assigned
Today the only thing that prevents public-inbox not reusing the
message numbers of deleted messages is the sqlite autoincrement magic
and that only works part of the time. The new incremental indexing
test has revealed areas where today public-inbox does try to reuse
numbers of deleted messages.
Reusing the message numbers of existing messages is a problem because
if a client ever sees messages that are subsequently deleted the
client will not see the new messages with their old numbers.
In practice this is difficult to trigger because it requires the most
recently added message to be removed and have the removal show up in a
separate pull request. Still it can happen and it should be handled.
Instead of infering the highset number ever used by finding the maximum
number in the message map, track the largest number ever assigned directly.
Update Msgmap to track this value and update the indexers to use this
value.
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Eric Wong [Mon, 30 Jul 2018 08:23:51 +0000 (08:23 +0000)]
search: (really) match the behavior of WWW for indexing text
Not sure what was going through my mind when I made my first
attempt at this, but we really want to make sure we index all
the text we display in the web view (and presumably anything a
reasonable mail client can display).
Followup-to: 0cf6196025d4e4880cd1ed859257ce21dd3cdcf6
("search: match the behavior of WWW for indexing text")
Eric W. Biederman [Wed, 1 Aug 2018 16:43:38 +0000 (11:43 -0500)]
SearchIdx.pm: Always assign numbers backwards during incremental indexing
When walking messages newest to oldest, assigning the larger numbers
before smaller numbers ensures older messages get smaller numbers.
This leads to the possibility of a msgmap that can be regenerated when
needed.
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Eric W. Biederman [Wed, 1 Aug 2018 16:43:37 +0000 (11:43 -0500)]
t/v[12]reindex.t: Test incremental indexing works
Capture interesting commits of the test repository in mark variables.
Use those marks to build interesting scenarios where index_sync proceeds
as if those marks are the heads of the repositor. Use this capability to
test what happens when adds and deletes are mixed within a repository.
Be sad because things don't yet work as they should.
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Eric W. Biederman [Wed, 1 Aug 2018 16:43:34 +0000 (11:43 -0500)]
t/v2reindex.t: Isolate the test cases more
While inspecting the tests I realized that because we have been
reusing variables there can be a memory between one test case and
another. Add scopes and local variables to prevent an unintended
memory between one test cases.
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Eric W. Biederman [Wed, 1 Aug 2018 16:43:33 +0000 (11:43 -0500)]
t/v1reindex.t: Isolate the test cases
While inspecting the tests I realized that because we have been
reusing variables there can be a memory between one test case and
another. Add scopes and local variables to prevent an unintended
memory between one test and another.
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Eric W. Biederman [Wed, 1 Aug 2018 16:43:32 +0000 (11:43 -0500)]
Import.pm: Don't assume {in} and {out} always exist
While working on one of the tests I did:
my $im = PublicInbox::V2Writable->new($ibx, 1);
my $im0 = $im->importer();
$im->add($mime);
Which resulted in a warning of the use of an undefined value from
atfork_child, and the test failing nastily. Inspection of the code
reveals this can happen anytime gfi_start has not been called.
So just fix atfork_child to skip closing file descriptors that have
not yet been setup.
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Eric W. Biederman [Mon, 30 Jul 2018 05:04:45 +0000 (00:04 -0500)]
ProcessPipe.pm: Use read not sysread
While playing with git fast export I discovered that mixing <> and
read would give inconsistent results. I tracked the issue down to
using sysread in ProcessPipe instead of plain read.
If it is desirable to use readline I can't see how using sysread
can work as readline to be efficient needs to use buffered I/O.
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Eric Wong [Sun, 29 Jul 2018 10:05:13 +0000 (10:05 +0000)]
mda: allow configuring globally without spamc support
This reuses some of the configuration from -watch, but remains
independent since some configurations will use -watch for some
inboxes and -mda for others.
The default remains "spamc" for -mda users so nothing changes
without explicit configuration.
Per-inbox configurations may also be supported in the future.
Eric Wong [Sun, 29 Jul 2018 09:34:41 +0000 (09:34 +0000)]
mda: v2: ensure message bodies are indexed
We must not clobber the original message string, as Email::MIME(*)
still needs it for iterating through parts in SearchIdx (but not
when handing it as a raw string to git-fast-import).
I've noticed message bodies (especially dfpre/dpost) were not
getting indexed when going through -mda (no problems with
-watch). This also did not affect v1 repos, since indexing is a
separate process for v1 and requires re-reading the data from
git.
Eric Wong [Fri, 20 Jul 2018 06:16:12 +0000 (06:16 +0000)]
search: use boolean prefixes for git blob queries
I've hit some case where probabilistic searches don't work when
using dfpre:/dfpost:/dfblob: search prefixes because stemming in
the query parser interferes.
In any case, our indexing code indexes longer/unabbreviated blob
names down to its 7 character abbreviation, so there should be
no need to do wildcard searches on git blob names.
Eric Wong [Thu, 19 Jul 2018 21:43:10 +0000 (21:43 +0000)]
tests: fixup indexlevel setting in tests
The correct field is underscore-less for consistency with
git-config naming conventions. While we're at it, beef up
the v2 tests with actual size checks, too.
I also noticed phrase searching still seems to work for
the limited test case, so I left it documented; but the
size checking verifies the space savings.
Eric W. Biederman [Thu, 19 Jul 2018 19:36:31 +0000 (14:36 -0500)]
Import.pm: Deal with potentially missing From and Sender headers
Use ||= '' to ensure that if the From or Sender header is not present
the code sees an empty string and instead of undefined.
I had some email messages with a From field without an @ (because the
sender was local) and without a Sender which were causing errors when
imported. I think this was bad enough that the email messages were
failing to be imported.
Signed-off-by: Eric Biederamn <ebiederm@xmission.com>
Eric Wong [Thu, 19 Jul 2018 03:21:38 +0000 (03:21 +0000)]
searchidx: respect XAPIAN_FLUSH_THRESHOLD env if set
Xapian documents and respect XAPIAN_FLUSH_THRESHOLD to define
the interval in documents to flush, so don't override it with
our own BATCH_BYTES. This is helpful for initial indexing for
those on slower storage but enough RAM.
It is unnecessary for -watch and frequent incremental indexing;
and it increases transaction times if -watch is playing "catch-up"
if it was stopped for a while.
The original BATCH_BYTES was tuned for a machine with little
memory as the default XAPIAN_FLUSH_THRESHOLD of 10000 documents
was causing swap storms. Using document counts also proved an
innaccurate estimator of RAM usage compared to the actual bytes
processed.
Eric W. Biederman [Wed, 18 Jul 2018 17:32:34 +0000 (12:32 -0500)]
public-inbox-init: Initialize indexlevel
If indexlevel is specified on the command line prefer that.
If indexlevel is specified in the config file prefer that.
If indexlevel is not specified anywhere default to full.
This should make indexlevel somewhat approachable.
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Eric W. Biederman [Wed, 18 Jul 2018 16:53:25 +0000 (11:53 -0500)]
SearchIdx: Allow the amount of indexing be configured
This adds a new inbox configuration option 'indexlevel' that can take
the values 'full', 'medium', and 'basic'.
When set to 'full' everything is indexed including the positions
of all terms.
When set to 'medium' everything except the positions of terms is
indexed.
When set to 'basic' terms and positions are not indexed. Just the
Overview database for NNTP is created. Which is still quite good and
allows searching for messages by Message-ID. But there are no indexes to support
searching inside the email messages themselves.
Update the reindex tests to exercise the full medium and basic code paths
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Eric W. Biederman [Wed, 18 Jul 2018 16:53:24 +0000 (11:53 -0500)]
SearchIdx: Add the mechanism for making all Xapian indexing optional
Create a new method add_xapian that holds all of the code to create
Xapian indexes. The creation of this method simpliy involved
idenitifying the relevant code and moving it from add_message.
A call is added to add_xapian from add_message to keep everything
working as it currently does. The new call is made conditional upon
index levels of 'full' and 'medium'. The index levels that index
positions and terms the two things public-inbox uses Xapian to index.
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Eric W. Biederman [Wed, 18 Jul 2018 16:53:23 +0000 (11:53 -0500)]
SearchIdx.pm: Make indexing search positions optional
About half the size of the Xapian search index turns out to be search
positions. The search positions are only used in a very narrow set of
queries. Make the search positions optional so people don't need to
pay the cost of queries they will never make.
This also makes public-inbox more approachable for light hacking as
generating all of the indexes is time consuming.
The way this is done is to add a method to SearchIdx called index_text
that wraps the call of the term generator method index_text. The new
index_text method takes care of calling both index_text and
increase_termpos (the two functions that are responsible for position
data).
Then index_users, index_diff_inc, index_old_diff_fn, index_diff,
index_body are made proper methods that calls the new index_text.
Callers of the new index_text are slightly simplified as they don't
need to call increase_termpos as well.
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Eric W. Biederman [Tue, 17 Jul 2018 22:06:17 +0000 (17:06 -0500)]
SearchIdx: Decrement regen_down even for added messages that are later deleted.
Decrement regen_down when visiting messages that appear in %D that we
know will later be deleted. This ensures consistent message numbers are
generated no matter which commit number is on top. Allowing deletes to
propagage separately from the messages they delete without causing
problems.
The v2 trees already do this and when the indexes are deleted and
rebuilt they maintain they commit numbers.
Add a v1 version of the v2reindex test to verify that reindexing is
working properly on v1 as well as v2.
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Eric Wong [Sat, 14 Jul 2018 00:46:01 +0000 (00:46 +0000)]
v2writable: unindex deleted messages after incremental fetch
The normal behavior is to prevent the deleted messages from
being indexed in the first place. However, when fetching
incrementally via git; public-inbox-index needs to account for
deleted files which were created outside of the most recent
fetch/reindexing window.
Reported-by: Eric W. Biederman <ebiederm@xmission.com>
Eric W. Biederman [Sat, 7 Jul 2018 18:22:28 +0000 (13:22 -0500)]
Import: Don't copy nulls from emails into git
Recently I ran git --git-dir=lkml/git/1.git fsck
and it reported:
> warning in commit 299dbd50b6995c6debe2275f0df984ce697fb4cc: nulInCommit: NULL byte inthe commit object body
Which I found quite scary. Nulls in the wrong place have a bad tendency
to make programs misbehave.
It turns out someone had placed "=?iso-8859-1?q?=00?=" at the end of
their subject line. Which is the mime encoding for NULL. Email::Mime
had correctly decoded the header, and then public-inbox had simply
copied the contents of the header into the subject line of the git
commit.
To prevent that from causing problems replace nulls in such subject
lines with spaces.
Signed-off-by: Eric Biederman <ebiederm@xmission.com>
Upon examination with git show --pretty=raw all of the problem commits
had a time zone that was not 4 digits long. This time zone had been
passed straight from the Date line in the email into the author line
of the commit.
Looking into that I discovered that str2time takes into account the
time zone, and was actually able to process these weird time zones.
So get the normalized time zone with strptime and convert it from
seconds from gmt to hours and minutes from gmt.
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Eric Wong [Wed, 4 Jul 2018 10:50:25 +0000 (10:50 +0000)]
v2: fill alternates with old epochs on init from mirrors
For v2 repositories with multiple epochs, we must not forget
about earlier epochs in clones. Ensure we update the alternates
file with all known epochs up to the current one.
Reported-by: Eric W. Biederman <ebiederm@xmission.com>
https://public-inbox.org/meta/871scj2vzi.fsf@xmission.com/
Eric Wong [Wed, 13 Jun 2018 22:43:56 +0000 (22:43 +0000)]
www: use undecoded paths for Message-ID extraction
In PSGI, PATH_INFO contains URI-decoded paths which cause
problems when Message-IDs contain ambiguous characters for used
for routing. Instead, extract the undecoded path from
REQUEST_URI and use that.
Konstantin Ryabitsev [Mon, 18 Jun 2018 17:51:02 +0000 (13:51 -0400)]
Tweak over.sqlite3 queries for sqlite < 3.8
The query planner in sqlite3 < 3.8 is not very clever, so when it sees
num mentioned in the query filter, it decides not to use the fast idx_ts
index and goes for the much slower autoindex. CentOS-7 still has
sqlite-3.7, so loading the http landing page of a very large archive
(LKML) was taking over 18 seconds, as oppposed to milliseconds on a
system with sqlite-3.8 and above:
$ time sqlite3 -line over.sqlite3 'SELECT ts,ds,ddd FROM over \
WHERE num > 0 ORDER BY ts DESC LIMIT 1000;' > /dev/null
real 0m19.610s
user 0m17.805s
sys 0m1.805s
$ sqlite3 -line over.sqlite3 'EXPLAIN QUERY PLAN SELECT ts,ds,ddd \
FROM over WHERE num > 0 ORDER BY ts DESC LIMIT 1000;'
selectid = 0
order = 0
from = 0
detail = SEARCH TABLE over USING INDEX sqlite_autoindex_over_1 (num>?) (~250000 rows)
However, if we slightly tweak the query per SQlite recommendations [1]
by adding + to the num filter, we force it to use the correct index
and see much faster performance:
$ time sqlite3 -line over.sqlite3 'SELECT ts,ds,ddd FROM over \
WHERE +num > 0 ORDER BY ts DESC LIMIT 1000;' > /dev/null
real 0m0.007s
user 0m0.005s
sys 0m0.002s
$ sqlite3 -line over.sqlite3 'EXPLAIN QUERY PLAN SELECT ts,ds,ddd \
FROM over WHERE +num > 0 ORDER BY ts DESC LIMIT 1000;'
selectid = 0
order = 0
from = 0
detail = SCAN TABLE over USING INDEX idx_ts (~1464303 rows)
This appears to be the only place where this is needed in order to avoid
running into this issue.
As far as I can tell, this change has no impact on systems running newer
sqlite3 (>= 3.8).
Konstantin Ryabitsev [Fri, 15 Jun 2018 19:11:23 +0000 (15:11 -0400)]
Contribute SELinux policy for EL7
This adds a SELinux policy suitable for RHEL/CentOS 7. It assumes the
following:
- public-inbox-httpd and public-inbox-nntpd are running via systemd
on sane ports (119 and 80/8080)
- /var/lib/public-inbox is the location for mainrepos
- /var/run/public-inbox is the location for PERL_INLINE_DIRECTORY
- /var/log/public-inbox is the location for logs
- mail delivery is done via postfix-pipe or public-inbox-watch via
the provided example systemd service
Signed-off-by: Konstantin Ryabitsev <konstantin@linuxfoundation.org>
Leah Neukirchen [Tue, 12 Jun 2018 15:36:52 +0000 (17:36 +0200)]
public-inbox-mda: use <sysexits.h> status codes where applicable
Many MTA understand these and map them to sensible SMTP error messages.
Inability to find an inbox results in "5.1.1 user unknown".
Misformatted messages are rejected with "5.6.0 data format error".
Unsupported inbox versions are reported as "5.3.5 local configuration error".
All of these are interpreted as permanent failures.
Eric Wong [Wed, 30 May 2018 02:54:48 +0000 (02:54 +0000)]
respect umask if core.sharedRepository is not set
This is consistent with git itself and the previous behavior
was a result of misunderstanding of how git interprets this.
And adjust tests slightly to match the new behavior.
Reported-by: Konstantin Ryabitsev <konstantin@linuxfoundation.org>
<38873789-ab42-65a1-20c9-12c30b171f4f@linuxfoundation.org>
Eric Wong [Thu, 24 May 2018 08:32:16 +0000 (08:32 +0000)]
workaround Xapian OFD locks w/o close-on-exec
Xapian v1.2.21..v1.2.24 (inclusive) use OFD locks but failed to
set the close-on-exec flag on those locks. So we must continue
to work around those old versions by ensuring Xapian file
descriptors aren't held any longer than necessary when in
long-running git processes.
Reported-by: Konstantin Ryabitsev <konstantin@linuxfoundation.org>
Eric Wong [Fri, 11 May 2018 19:20:15 +0000 (19:20 +0000)]
content_id: workaround quote handling change in Email::* modules
I'm not entirely sure where the behavior change lies, but
it seems to be in some of the latest CPAN versions of these
modules. In any case, this only affects the test setup and
not actual behavior.