Fixed IMAP SEARCH BEFORE command
This commit is contained in:
@@ -11,6 +11,7 @@ All notable changes to this project will be documented in this file. This projec
|
|||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Invalid DKIM signatures for empty message bodies.
|
- Invalid DKIM signatures for empty message bodies.
|
||||||
|
- Parsing IMAP `SEARCH BEFORE` commands.
|
||||||
|
|
||||||
## [0.5.0] - 2023-12-27
|
## [0.5.0] - 2023-12-27
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ resolver = "2"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
jmap_proto = { path = "../jmap-proto" }
|
jmap_proto = { path = "../jmap-proto" }
|
||||||
store = { path = "../store" }
|
store = { path = "../store", features = ["sqlite"] }
|
||||||
mail-parser = { version = "0.9", features = ["full_encoding", "serde_support", "ludicrous_mode"] }
|
mail-parser = { version = "0.9", features = ["full_encoding", "serde_support", "ludicrous_mode"] }
|
||||||
ahash = { version = "0.8" }
|
ahash = { version = "0.8" }
|
||||||
chrono = { version = "0.4"}
|
chrono = { version = "0.4"}
|
||||||
|
|||||||
@@ -128,7 +128,12 @@ pub fn parse_filters(
|
|||||||
} else if value.eq_ignore_ascii_case(b"BCC") {
|
} else if value.eq_ignore_ascii_case(b"BCC") {
|
||||||
filters.push(Filter::Bcc(decode_argument(tokens, decoder)?));
|
filters.push(Filter::Bcc(decode_argument(tokens, decoder)?));
|
||||||
} else if value.eq_ignore_ascii_case(b"BEFORE") {
|
} else if value.eq_ignore_ascii_case(b"BEFORE") {
|
||||||
filters.push(Filter::All);
|
filters.push(Filter::Before(parse_date(
|
||||||
|
&tokens
|
||||||
|
.next()
|
||||||
|
.ok_or_else(|| Cow::from("Expected date"))?
|
||||||
|
.unwrap_bytes(),
|
||||||
|
)?));
|
||||||
} else if value.eq_ignore_ascii_case(b"BODY") {
|
} else if value.eq_ignore_ascii_case(b"BODY") {
|
||||||
filters.push(Filter::Body(decode_argument(tokens, decoder)?));
|
filters.push(Filter::Body(decode_argument(tokens, decoder)?));
|
||||||
} else if value.eq_ignore_ascii_case(b"CC") {
|
} else if value.eq_ignore_ascii_case(b"CC") {
|
||||||
@@ -742,6 +747,16 @@ mod tests {
|
|||||||
sort: None,
|
sort: None,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
b"5 UID SEARCH BEFORE 1-Dec-2023\r\n".to_vec(),
|
||||||
|
search::Arguments {
|
||||||
|
tag: "5".to_string(),
|
||||||
|
result_options: vec![],
|
||||||
|
filter: vec![Filter::Before(1701388800)],
|
||||||
|
is_esearch: true,
|
||||||
|
sort: None,
|
||||||
|
},
|
||||||
|
),
|
||||||
] {
|
] {
|
||||||
let command_str = String::from_utf8_lossy(&command).into_owned();
|
let command_str = String::from_utf8_lossy(&command).into_owned();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ impl ImapResponse for Response {
|
|||||||
}
|
}
|
||||||
buf.extend_from_slice(b"* ");
|
buf.extend_from_slice(b"* ");
|
||||||
buf.extend_from_slice(self.total_messages.to_string().as_bytes());
|
buf.extend_from_slice(self.total_messages.to_string().as_bytes());
|
||||||
if self.recent_messages > 0 {
|
if !self.is_rev2 && self.recent_messages > 0 {
|
||||||
buf.extend_from_slice(
|
buf.extend_from_slice(
|
||||||
b" EXISTS\r\n* FLAGS (\\Answered \\Flagged \\Deleted \\Seen \\Draft \\Recent)\r\n",
|
b" EXISTS\r\n* FLAGS (\\Answered \\Flagged \\Deleted \\Seen \\Draft \\Recent)\r\n",
|
||||||
);
|
);
|
||||||
@@ -158,7 +158,7 @@ mod tests {
|
|||||||
),
|
),
|
||||||
concat!(
|
concat!(
|
||||||
"* 172 EXISTS\r\n",
|
"* 172 EXISTS\r\n",
|
||||||
"* FLAGS (\\Answered \\Flagged \\Deleted \\Seen \\Draft)\r\n",
|
"* FLAGS (\\Answered \\Flagged \\Deleted \\Seen \\Draft \\Recent)\r\n",
|
||||||
"* 5 RECENT\r\n",
|
"* 5 RECENT\r\n",
|
||||||
"* OK [UNSEEN 3] Unseen messages\r\n",
|
"* OK [UNSEEN 3] Unseen messages\r\n",
|
||||||
"* OK [PERMANENTFLAGS (\\Deleted \\Seen \\Answered \\Flagged \\Draft \\*)] All allowed\r\n",
|
"* OK [PERMANENTFLAGS (\\Deleted \\Seen \\Answered \\Flagged \\Draft \\*)] All allowed\r\n",
|
||||||
@@ -196,7 +196,7 @@ mod tests {
|
|||||||
concat!(
|
concat!(
|
||||||
"* OK [CLOSED] Closed previous mailbox\r\n",
|
"* OK [CLOSED] Closed previous mailbox\r\n",
|
||||||
"* 172 EXISTS\r\n",
|
"* 172 EXISTS\r\n",
|
||||||
"* FLAGS (\\Answered \\Flagged \\Deleted \\Seen \\Draft)\r\n",
|
"* FLAGS (\\Answered \\Flagged \\Deleted \\Seen \\Draft \\Recent)\r\n",
|
||||||
"* 5 RECENT\r\n",
|
"* 5 RECENT\r\n",
|
||||||
"* OK [UNSEEN 3] Unseen messages\r\n",
|
"* OK [UNSEEN 3] Unseen messages\r\n",
|
||||||
"* OK [PERMANENTFLAGS (\\Deleted \\Seen \\Answered \\Flagged \\Draft \\*)] All allowed\r\n",
|
"* OK [PERMANENTFLAGS (\\Deleted \\Seen \\Answered \\Flagged \\Draft \\*)] All allowed\r\n",
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import socket
|
|||||||
import time
|
import time
|
||||||
import threading
|
import threading
|
||||||
from email.message import Message
|
from email.message import Message
|
||||||
|
from email.utils import formatdate
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
def append_message(thread_id, start, end):
|
def append_message(thread_id, start, end):
|
||||||
conn = imaplib.IMAP4('localhost')
|
conn = imaplib.IMAP4('localhost')
|
||||||
@@ -10,15 +12,20 @@ def append_message(thread_id, start, end):
|
|||||||
conn.socket().setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
conn.socket().setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
|
|
||||||
|
base_date = datetime(2000, 1, 1)
|
||||||
|
|
||||||
for n in range(start, end):
|
for n in range(start, end):
|
||||||
|
current_date = base_date + timedelta(hours=n)
|
||||||
|
|
||||||
msg = Message()
|
msg = Message()
|
||||||
msg['From'] = 'somebody@some.where'
|
msg['From'] = 'somebody@some.where'
|
||||||
msg['To'] = 'john@example.org'
|
msg['To'] = 'john@example.org'
|
||||||
msg['Message-Id'] = f'unique.message.id.{n}@nowhere'
|
msg['Message-Id'] = f'unique.message.id.{n}@nowhere'
|
||||||
|
msg['Date'] = formatdate(time.mktime(current_date.timetuple()), localtime=False, usegmt=True)
|
||||||
msg['Subject'] = f"This is message #{n}"
|
msg['Subject'] = f"This is message #{n}"
|
||||||
msg.set_payload('...nothing...')
|
msg.set_payload('...nothing...')
|
||||||
|
|
||||||
response_code, response_details = conn.append('INBOX', '', None, str(msg).encode('utf-8'))
|
response_code, response_details = conn.append('INBOX', '', imaplib.Time2Internaldate(time.mktime(current_date.timetuple())), str(msg).encode('utf-8'))
|
||||||
if response_code != 'OK':
|
if response_code != 'OK':
|
||||||
print(f'Thread {thread_id}: Error while appending message #{n}: {response_code} {response_details}')
|
print(f'Thread {thread_id}: Error while appending message #{n}: {response_code} {response_details}')
|
||||||
break
|
break
|
||||||
|
|||||||
Reference in New Issue
Block a user