Skip to content

Commit

Permalink
g3proxy: test and fix IMAP interception for thunderbird
Browse files Browse the repository at this point in the history
  • Loading branch information
zh-jq-b committed Aug 5, 2024
1 parent 6c4e47a commit 6cac299
Show file tree
Hide file tree
Showing 8 changed files with 39 additions and 24 deletions.
6 changes: 6 additions & 0 deletions doc/standards.md
Original file line number Diff line number Diff line change
Expand Up @@ -356,8 +356,14 @@ The code should comply to these, but should be more compliant to existing popula

- [rfc9051](https://datatracker.ietf.org/doc/html/rfc9051)
: Internet Message Access Protocol (IMAP) - Version 4rev2
- [rfc3501](https://datatracker.ietf.org/doc/html/rfc3501)
: INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1
- [rfc7162](https://datatracker.ietf.org/doc/html/rfc7162)
: IMAP Extensions: Quick Flag Changes Resynchronization (CONDSTORE) and Quick Mailbox Resynchronization (QRESYNC)
- [iana-imap-capabilities](https://www.iana.org/assignments/imap-capabilities/imap-capabilities.xhtml)
: Internet Message Access Protocol (IMAP) Capabilities Registry
- [rfc2971](https://datatracker.ietf.org/doc/html/rfc2971.html)
: IMAP4 ID extension

## NNTP

Expand Down
15 changes: 7 additions & 8 deletions g3proxy/src/inspect/imap/authenticated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ where
if let Some(mut rsp) = self.cmd_pipeline.take_ongoing_response() {
self.handle_rsp_continue_line(line, &mut rsp, clt_w).await?;
if let Some(size) = rsp.literal_data {
self.cmd_pipeline.set_ongoing_response(rsp);
self.relay_server_literal(size, clt_w, ups_r, relay_buf).await?;
}
} else {
Expand Down Expand Up @@ -136,7 +137,7 @@ where
Ok(cmd) => {
let mut action = ClientAction::Loop;
match cmd.parsed {
ParsedCommand::Capability | ParsedCommand::NoOperation => {
ParsedCommand::Capability | ParsedCommand::NoOperation | ParsedCommand::Id => {
self.cmd_pipeline.insert_completed(cmd);
}
ParsedCommand::Logout => {
Expand All @@ -159,6 +160,7 @@ where
| ParsedCommand::Subscribe
| ParsedCommand::Unsubscribe
| ParsedCommand::List
| ParsedCommand::Lsub
| ParsedCommand::Status
| ParsedCommand::Append => {
if let Some(literal) = cmd.literal_arg {
Expand All @@ -171,13 +173,7 @@ where
}
}
ParsedCommand::Idle => {
if self.mailbox_selected {
BadResponse::reply_invalid_command(clt_w, cmd.tag.as_str())
.await
.map_err(ServerTaskError::ClientTcpWriteFailed)?;
return Ok(action);
}
self.cmd_pipeline.insert_completed(cmd);
self.cmd_pipeline.set_ongoing_command(cmd);
action = ClientAction::Idle;
}
ParsedCommand::Close
Expand Down Expand Up @@ -249,6 +245,9 @@ where
r = relay_buf.cmd_recv_buf.recv_cmd_line(clt_r) => {
let line = r?;
return if line == b"DONE\r\n" {
ups_w.write_all_flush(line)
.await
.map_err(ServerTaskError::UpstreamWriteFailed)?;
Ok(None)
} else {
let _ = ByeResponse::reply_client_protocol_error(clt_w).await;
Expand Down
3 changes: 3 additions & 0 deletions g3proxy/src/inspect/imap/forward.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,9 @@ where
"no ongoing IMAP command found when received continuation request"
)));
};
if cmd.parsed == ParsedCommand::Idle {
return Ok(ResponseAction::Loop);
}
let Some(literal) = cmd.literal_arg else {
let _ = ByeResponse::reply_upstream_protocol_error(clt_w).await;
return Err(ServerTaskError::UpstreamAppError(anyhow!(
Expand Down
2 changes: 1 addition & 1 deletion g3proxy/src/inspect/imap/not_authenticated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ where
Ok(cmd) => {
let mut action = ClientAction::Loop;
match cmd.parsed {
ParsedCommand::Capability | ParsedCommand::NoOperation => {
ParsedCommand::Capability | ParsedCommand::NoOperation | ParsedCommand::Id => {
self.cmd_pipeline.insert_completed(cmd);
}
ParsedCommand::Logout => {
Expand Down
16 changes: 7 additions & 9 deletions lib/g3-imap-proto/src/command/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ pub enum ParsedCommand {
Subscribe,
Unsubscribe,
List,
Lsub,
Namespace,
Status,
Append,
Expand All @@ -65,6 +66,7 @@ pub enum ParsedCommand {
Copy,
Move,
Uid,
Id,
Unknown,
}

Expand Down Expand Up @@ -163,7 +165,7 @@ impl Command {
let upper_cmd = cmd.to_uppercase();

let left = &left[p + 1..];
let mut literal_arg = None;
let literal_arg = LiteralArgument::check(left)?;
let parsed = match upper_cmd.as_bytes() {
b"AUTHENTICATE" => ParsedCommand::Auth,
b"LOGIN" => ParsedCommand::Login, // TODO parse username
Expand All @@ -176,20 +178,16 @@ impl Command {
b"SUBSCRIBE" => ParsedCommand::Subscribe,
b"UBSUBSCRIBE" => ParsedCommand::Unsubscribe,
b"LIST" => ParsedCommand::List,
b"LSUB" => ParsedCommand::Lsub,
b"STATUS" => ParsedCommand::Status,
b"APPEND" => {
literal_arg = LiteralArgument::check(left)?;
ParsedCommand::Append
}
b"SEARCH" => {
literal_arg = LiteralArgument::check(left)?;
ParsedCommand::Search
}
b"APPEND" => ParsedCommand::Append,
b"SEARCH" => ParsedCommand::Search,
b"FETCH" => ParsedCommand::Fetch,
b"STORE" => ParsedCommand::Store,
b"COPY" => ParsedCommand::Copy,
b"MOVE" => ParsedCommand::Move,
b"UID" => ParsedCommand::Uid,
b"ID" => ParsedCommand::Id,
_ => ParsedCommand::Unknown,
};

Expand Down
17 changes: 12 additions & 5 deletions lib/g3-imap-proto/src/response/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ pub enum CommandData {
Enabled,
Capability,
Fetch,
Id,
Other,
}

Expand Down Expand Up @@ -157,7 +158,11 @@ impl Response {
command_data: CommandData::Capability,
literal_data: None,
})),
"LIST" | "NAMESPACE" | "STATUS" | "SEARCH" | "ESEARCH" | "FLAGS" => {
"ID" => Ok(Response::CommandData(UntaggedResponse {
command_data: CommandData::Id,
literal_data: None,
})),
"LIST" | "LSUB" | "NAMESPACE" | "STATUS" | "SEARCH" | "ESEARCH" | "FLAGS" => {
Ok(Response::CommandData(UntaggedResponse {
command_data: CommandData::Other,
literal_data: None,
Expand All @@ -184,10 +189,12 @@ impl Response {
let result =
str::from_utf8(left).map_err(ResponseLineError::InvalidUtf8Response)?;
match result.to_uppercase().as_str() {
"EXISTS" | "EXPUNGE" => Ok(Response::CommandData(UntaggedResponse {
command_data: CommandData::Other,
literal_data: None,
})),
"EXISTS" | "EXPUNGE" | "RECENT" => {
Ok(Response::CommandData(UntaggedResponse {
command_data: CommandData::Other,
literal_data: None,
}))
}
_ => Err(ResponseLineError::UnknownUntaggedResult),
}
}
Expand Down
1 change: 1 addition & 0 deletions lib/g3-io-ext/src/io/line_recv_buf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ impl<const MAX_LINE_SIZE: usize> LineRecvBuf<MAX_LINE_SIZE> {
&self.buf[start..end]
} else {
self.line_start += max_size;
self.line_end = self.line_start;
&self.buf[start..self.line_start]
}
}
Expand Down
3 changes: 2 additions & 1 deletion lib/g3-io-ext/src/io/line_recv_vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ impl LineRecvVec {

pub fn with_data(data: &[u8], cap: usize) -> Self {
let mut buf = Vec::with_capacity(cap);
buf.copy_from_slice(data);
buf.extend_from_slice(data);
if cap > data.len() {
buf.resize(cap, 0);
}
Expand Down Expand Up @@ -145,6 +145,7 @@ impl LineRecvVec {
&self.buf[start..end]
} else {
self.line_start += max_size;
self.line_end = self.line_start;
&self.buf[start..self.line_start]
}
}
Expand Down

0 comments on commit 6cac299

Please sign in to comment.