Skip to content

Commit

Permalink
jmap_mail.c: update Email/import logic for receivedAt property
Browse files Browse the repository at this point in the history
This updates Email/import to set the receivedAt property to:

- the Email/import receivedAt argument, if present
- the value of the X-Deliveredinternaldate header, if present
- the value of the first valid Received header, if present
- the value of the Date header, if present
- the current time, if none of the above are present or valid
  • Loading branch information
rsto committed Apr 11, 2024
1 parent 617e0a1 commit 1af9f6c
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 16 deletions.
19 changes: 19 additions & 0 deletions cassandane/tiny-tests/JMAPEmail/email_import_received_at
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,25 @@ sub test_email_import_received_at
desc => 'not set',
wantSentAt => undef,
wantReceivedAt => undef,
}, {
desc => 'receivedAt from first valid Received header',
headers => "Date: Sat, 1 Jan 2022 01:00:00 +1100\r\n" .
"Received: from rcv1 ([192.168.0.1]) by bar (Baz); invalid datetime\r\n" .
"Received: from rcv2 ([192.168.0.2]) by tux (Qux); Sat, 13 Aug 2022 12:01:10 -0200\r\n" .
"Received: from rcv3 ([192.168.0.3]) by baz (Hkl); Sat, 13 Aug 2022 12:00:45 -0200\r\n",
wantSentAt => '2022-01-01T01:00:00+11:00',
wantReceivedAt => '2022-08-13T14:01:10Z',
skipVersionBefore => qw(3,9),
}, {
desc => 'receivedAt from X-DeliveredInternalDate header',
headers => "Date: Sat, 1 Jan 2022 01:00:00 +1100\r\n" .
"Received: from rcv1 ([192.168.0.2]) by tux (Qux); Sat, 13 Aug 2022 12:01:10 -0200\r\n" .
"Received: from rcv2 ([192.168.0.3]) by baz (Hkl); Sat, 13 Aug 2022 12:00:45 -0200\r\n" .
"X-DeliveredInternalDate: Mon, 15 Aug 2022 13:00:45 -0200\r\n",
,
wantSentAt => '2022-01-01T01:00:00+11:00',
wantReceivedAt => '2022-08-15T15:00:45Z',
skipVersionBefore => qw(3,9),
});

while (my ($i, $tc) = each @testCases) {
Expand Down
71 changes: 55 additions & 16 deletions imap/jmap_mail.c
Original file line number Diff line number Diff line change
Expand Up @@ -13236,6 +13236,57 @@ static int msgimport_checkacl_cb(const mbentry_t *mbentry, void *xrock)
return 0;
}

static time_t _email_import_parse_received_at(const char *blob, size_t blob_len)
{
message_t *msg = message_new_from_data(blob, blob_len);
struct buf buf = BUF_INITIALIZER;
time_t received_at = 0;
enum message_format format = MESSAGE_DECODED | MESSAGE_TRIM;

if (!msg)
goto done;

if (!message_get_field(msg, "X-Deliveredinternaldate", format, &buf)) {
buf_appendcstr(&buf, "\r\n");
const char *hdr = buf_cstring(&buf);
char *val = NULL;
message_parse_string(hdr, &val);
if (time_from_rfc822(val, &received_at) < 0)
received_at = 0;
xzfree(val);
}

if (!received_at && !message_get_field(msg, "Received", format, &buf)) {
buf_appendcstr(&buf, "\r\n");
const char *hdr = buf_cstring(&buf);
char *val = NULL;
do {
message_parse_received_date(hdr, &val);
if (time_from_rfc822(val, &received_at) < 0)
received_at = 0;
hdr = strchr(hdr, '\n');
if (hdr)
hdr = strchr(hdr + 1, ':');
xzfree(val);
} while (!received_at && hdr++);
}

if (!received_at && !message_get_field(msg, "Date", format, &buf)) {
buf_appendcstr(&buf, "\r\n");
const char *hdr = buf_cstring(&buf);
char *val = NULL;
message_parse_string(hdr, &val);
if (time_from_rfc822(val, &received_at) < 0)
received_at = 0;
xzfree(val);
}

done:
message_unref(&msg);
buf_free(&buf);
return received_at;
}

static void _email_import(jmap_req_t *req,
json_t *jemail_import,
json_t **new_email,
Expand Down Expand Up @@ -13356,26 +13407,14 @@ static void _email_import(jmap_req_t *req,

/* set receivedAt property */
time_t internaldate = 0;
const char *received_at = json_string_value(json_object_get(jemail_import, "receivedAt"));
const char *received_at =
json_string_value(json_object_get(jemail_import, "receivedAt"));
if (received_at) {
time_from_iso8601(received_at, &internaldate);
}
else {
/* check for Received and Date Header */
struct body *mybody = xzmalloc(sizeof(struct body));
r = message_parse_mapped(buf_base(&content), buf_len(&content), mybody, NULL);
if (!r) {
const char *date = mybody->received_date ?
mybody->received_date : mybody->date;
if (date) {
time_t t = 0;
if (time_from_rfc822(date, &t) > 0) {
internaldate = t;
}
}
}
message_free_body(mybody);
free(mybody);
internaldate = _email_import_parse_received_at(buf_base(&content),
buf_len(&content));
}
if (!internaldate)
internaldate = time(NULL);
Expand Down

0 comments on commit 1af9f6c

Please sign in to comment.