Skip to content

Commit

Permalink
message.c: always use the first X-[Original-]Delivered-To header
Browse files Browse the repository at this point in the history
  • Loading branch information
ksmurchison committed Nov 22, 2024
1 parent 7d92853 commit edf24b9
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 7 deletions.
78 changes: 78 additions & 0 deletions cassandane/tiny-tests/Sieve/jmapquery_multiple_deliveredto
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#!perl
use Cassandane::Tiny;

sub test_jmapquery_multiple_deliveredto
:min_version_3_3 :needs_component_jmap
{
my ($self) = @_;

my $imap = $self->{store}->get_client();
$imap->create("INBOX.matches") or die;

$self->{instance}->install_sieve_script(<<'EOF'
require ["x-cyrus-jmapquery", "x-cyrus-log", "variables", "fileinto"];
if
allof( not string :is "${stop}" "Y",
jmapquery text:
{
"operator" : "OR",
"conditions" : [
{
"deliveredTo" : "[email protected]"
},
{
"deliveredTo" : "xxx+*@yyy.zzz"
}
],
"operator" : "OR"
}
.
)
{
fileinto "INBOX.matches";
}
EOF
);

my $body = << 'EOF';
--047d7b33dd729737fe04d3bde348
Content-Type: text/plain; charset=UTF-8
plain
--047d7b33dd729737fe04d3bde348
Content-Type: image/tiff
Content-Transfer-Encoding: base64
abc=
--047d7b33dd729737fe04d3bde348--
EOF
$body =~ s/\r?\n/\r\n/gs;

xlog $self, "Deliver a matching message";
my $msg1 = $self->{gen}->generate(
subject => "Message 1",
extra_headers => [['X-Original-Delivered-To', '[email protected]'],
['X-Original-Delivered-To', '[email protected]']],
mime_type => "multipart/mixed",
mime_boundary => "047d7b33dd729737fe04d3bde348",
body => $body,
);
$self->{instance}->deliver($msg1);

$self->{store}->set_fetch_attributes('uid');

xlog "Assert that message got moved into INBOX.matches";
$self->{store}->set_folder('INBOX.matches');
$self->check_messages({ 1 => $msg1 }, check_guid => 0);

xlog $self, "Deliver a non-matching message";
my $msg2 = $self->{gen}->generate(subject => "Message 2");
$self->{instance}->deliver($msg2);
$msg2->set_attribute(uid => 1);

xlog "Assert that message got moved into INBOX";
$self->{store}->set_folder('INBOX');
$self->check_messages({ 1 => $msg2 }, check_guid => 0);
}
18 changes: 13 additions & 5 deletions imap/message.c
Original file line number Diff line number Diff line change
Expand Up @@ -5061,9 +5061,11 @@ EXPORTED int message_get_bcc(message_t *m, struct buf *buf)

EXPORTED int message_get_deliveredto(message_t *m, struct buf *buf)
{
int r = message_get_field(m, "X-Original-Delivered-To", MESSAGE_RAW, buf);
int r = message_get_field(m, "X-Original-Delivered-To",
MESSAGE_RAW|MESSAGE_FIRST, buf);
if (!r && buf_len(buf) == 0) {
r = message_get_field(m, "X-Delivered-To", MESSAGE_RAW, buf);
r = message_get_field(m, "X-Delivered-To",
MESSAGE_RAW|MESSAGE_FIRST, buf);
}
return r;
}
Expand Down Expand Up @@ -5336,15 +5338,21 @@ static void extract_one(struct buf *buf,
{
char *p = NULL;

if (raw->len && (flags & MESSAGE_LAST)) {
/* Skip all but the last header value */
if (raw->len && (flags & (MESSAGE_FIRST|MESSAGE_LAST))) {
/* Isolate the first (top-most) or last (bottom-most) header value */
const char *q = raw->s;
const char *last = raw->s;
while ((p = strnchr(q, '\r', raw->s + raw->len - q))) {
if (p >= raw->s + raw->len - 2)
break;
if (*(p+1) == '\n' && *(p+2) && !isspace(*(p+2)))
if (*(p+1) == '\n' && *(p+2) && !isspace(*(p+2))) {
if (flags & MESSAGE_FIRST) {
buf_truncate(raw, p + 2 - raw->s);
break;
}

last = p + 2;
}
q = p + 1;
}
if (last != raw->s)
Expand Down
11 changes: 9 additions & 2 deletions imap/message.h
Original file line number Diff line number Diff line change
Expand Up @@ -268,9 +268,16 @@ enum message_format
MESSAGE_TRIM= (1<<8),

/* This flag can be OR'd into the format argument to request that
* only the last field of the given name is returned. Normally only
* the first is returned, which is faster. */
* only the last field of the given name is returned
* (by parsing the header block top to bottom).
* Normally ALL the values of the named header are returned. */
MESSAGE_LAST= (1<<9),

/* This flag can be OR'd into the format argument to request that
* only the first field of the given name is returned
* (by parsing the header block top to bottom).
* Normally ALL the values of the named header are returned. */
MESSAGE_FIRST= (1<<10),
};

enum message_indexflags
Expand Down

0 comments on commit edf24b9

Please sign in to comment.