|
|
|
@ -25,11 +25,6 @@ use std::{
|
|
|
|
|
time::SystemTime,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
use nom::{
|
|
|
|
|
branch::alt, bytes::complete::tag, combinator::map, multi::separated_list1,
|
|
|
|
|
sequence::separated_pair,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
use super::{ImapConnection, ImapProtocol, ImapServerConf, UIDStore};
|
|
|
|
|
use crate::{
|
|
|
|
|
conf::AccountSettings,
|
|
|
|
@ -43,17 +38,6 @@ pub struct ManageSieveConnection {
|
|
|
|
|
pub inner: ImapConnection,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn managesieve_capabilities(input: &[u8]) -> Result<Vec<(&[u8], &[u8])>> {
|
|
|
|
|
let (_, ret) = separated_list1(
|
|
|
|
|
tag(b"\r\n"),
|
|
|
|
|
alt((
|
|
|
|
|
separated_pair(quoted_raw, tag(b" "), quoted_raw),
|
|
|
|
|
map(quoted_raw, |q| (q, &b""[..])),
|
|
|
|
|
)),
|
|
|
|
|
)(input)?;
|
|
|
|
|
Ok(ret)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(PartialEq, Eq, Debug, Copy, Clone)]
|
|
|
|
|
pub enum ManageSieveResponse<'a> {
|
|
|
|
|
Ok {
|
|
|
|
@ -66,11 +50,203 @@ pub enum ManageSieveResponse<'a> {
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mod parser {
|
|
|
|
|
impl ManageSieveConnection {
|
|
|
|
|
pub fn new(
|
|
|
|
|
account_hash: crate::backends::AccountHash,
|
|
|
|
|
account_name: String,
|
|
|
|
|
s: &AccountSettings,
|
|
|
|
|
event_consumer: crate::backends::BackendEventConsumer,
|
|
|
|
|
) -> Result<Self> {
|
|
|
|
|
let server_hostname = get_conf_val!(s["server_hostname"])?;
|
|
|
|
|
let server_username = get_conf_val!(s["server_username"])?;
|
|
|
|
|
let server_password = get_conf_val!(s["server_password"])?;
|
|
|
|
|
let server_port = get_conf_val!(s["server_port"], 4190)?;
|
|
|
|
|
let danger_accept_invalid_certs: bool =
|
|
|
|
|
get_conf_val!(s["danger_accept_invalid_certs"], false)?;
|
|
|
|
|
let timeout = get_conf_val!(s["timeout"], 16_u64)?;
|
|
|
|
|
let timeout = if timeout == 0 {
|
|
|
|
|
None
|
|
|
|
|
} else {
|
|
|
|
|
Some(std::time::Duration::from_secs(timeout))
|
|
|
|
|
};
|
|
|
|
|
let server_conf = ImapServerConf {
|
|
|
|
|
server_hostname: server_hostname.to_string(),
|
|
|
|
|
server_username: server_username.to_string(),
|
|
|
|
|
server_password: server_password.to_string(),
|
|
|
|
|
server_port,
|
|
|
|
|
use_starttls: true,
|
|
|
|
|
use_tls: true,
|
|
|
|
|
danger_accept_invalid_certs,
|
|
|
|
|
protocol: ImapProtocol::ManageSieve,
|
|
|
|
|
timeout,
|
|
|
|
|
};
|
|
|
|
|
let uid_store = Arc::new(UIDStore {
|
|
|
|
|
is_online: Arc::new(Mutex::new((
|
|
|
|
|
SystemTime::now(),
|
|
|
|
|
Err(Error::new("Account is uninitialised.")),
|
|
|
|
|
))),
|
|
|
|
|
..UIDStore::new(
|
|
|
|
|
account_hash,
|
|
|
|
|
account_name.into(),
|
|
|
|
|
event_consumer,
|
|
|
|
|
server_conf.timeout,
|
|
|
|
|
)
|
|
|
|
|
});
|
|
|
|
|
Ok(Self {
|
|
|
|
|
inner: ImapConnection::new_connection(
|
|
|
|
|
&server_conf,
|
|
|
|
|
#[cfg(debug_assertions)]
|
|
|
|
|
"ManageSieveConnection::new()".into(),
|
|
|
|
|
uid_store,
|
|
|
|
|
),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub async fn havespace(&mut self) -> Result<()> {
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub async fn putscript(&mut self, script_name: &[u8], script: &[u8]) -> Result<()> {
|
|
|
|
|
let mut ret = Vec::new();
|
|
|
|
|
self.inner
|
|
|
|
|
.send_literal(format!("Putscript {{{len}+}}\r\n", len = script_name.len()).as_bytes())
|
|
|
|
|
.await?;
|
|
|
|
|
self.inner.send_literal(script_name).await?;
|
|
|
|
|
self.inner
|
|
|
|
|
.send_literal(format!(" {{{len}+}}\r\n", len = script.len()).as_bytes())
|
|
|
|
|
.await?;
|
|
|
|
|
self.inner.send_literal(script).await?;
|
|
|
|
|
self.inner
|
|
|
|
|
.read_response(&mut ret, RequiredResponses::empty())
|
|
|
|
|
.await?;
|
|
|
|
|
let (_rest, response) = parser::response_oknobye(&ret)?;
|
|
|
|
|
match response {
|
|
|
|
|
ManageSieveResponse::Ok { .. } => Ok(()),
|
|
|
|
|
ManageSieveResponse::NoBye { code, message } => Err(format!(
|
|
|
|
|
"Could not upload script: {} {}",
|
|
|
|
|
code.map(String::from_utf8_lossy).unwrap_or_default(),
|
|
|
|
|
message.map(String::from_utf8_lossy).unwrap_or_default()
|
|
|
|
|
)
|
|
|
|
|
.into()),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub async fn listscripts(&mut self) -> Result<Vec<(Vec<u8>, bool)>> {
|
|
|
|
|
let mut ret = Vec::new();
|
|
|
|
|
self.inner.send_command_raw(b"Listscripts").await?;
|
|
|
|
|
self.inner
|
|
|
|
|
.read_response(&mut ret, RequiredResponses::empty())
|
|
|
|
|
.await?;
|
|
|
|
|
let (_rest, scripts) =
|
|
|
|
|
parser::terminated(parser::listscripts, parser::tag_no_case(b"OK"))(&ret)?;
|
|
|
|
|
Ok(scripts
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|(n, a)| (n.to_vec(), a))
|
|
|
|
|
.collect::<Vec<(Vec<u8>, bool)>>())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub async fn checkscript(&mut self, script: &[u8]) -> Result<()> {
|
|
|
|
|
let mut ret = Vec::new();
|
|
|
|
|
self.inner
|
|
|
|
|
.send_literal(format!("Checkscript {{{len}+}}\r\n", len = script.len()).as_bytes())
|
|
|
|
|
.await?;
|
|
|
|
|
self.inner.send_literal(script).await?;
|
|
|
|
|
self.inner
|
|
|
|
|
.read_response(&mut ret, RequiredResponses::empty())
|
|
|
|
|
.await?;
|
|
|
|
|
let (_rest, response) = parser::response_oknobye(&ret)?;
|
|
|
|
|
match response {
|
|
|
|
|
ManageSieveResponse::Ok { .. } => Ok(()),
|
|
|
|
|
ManageSieveResponse::NoBye { code, message } => Err(format!(
|
|
|
|
|
"Checkscript reply: {} {}",
|
|
|
|
|
code.map(String::from_utf8_lossy).unwrap_or_default(),
|
|
|
|
|
message.map(String::from_utf8_lossy).unwrap_or_default()
|
|
|
|
|
)
|
|
|
|
|
.into()),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub async fn setactive(&mut self, script_name: &[u8]) -> Result<()> {
|
|
|
|
|
let mut ret = Vec::new();
|
|
|
|
|
self.inner
|
|
|
|
|
.send_literal(format!("Setactive {{{len}+}}\r\n", len = script_name.len()).as_bytes())
|
|
|
|
|
.await?;
|
|
|
|
|
self.inner.send_literal(script_name).await?;
|
|
|
|
|
self.inner
|
|
|
|
|
.read_response(&mut ret, RequiredResponses::empty())
|
|
|
|
|
.await?;
|
|
|
|
|
let (_rest, response) = parser::response_oknobye(&ret)?;
|
|
|
|
|
match response {
|
|
|
|
|
ManageSieveResponse::Ok { .. } => Ok(()),
|
|
|
|
|
ManageSieveResponse::NoBye { code, message } => Err(format!(
|
|
|
|
|
"Could not set active script: {} {}",
|
|
|
|
|
code.map(String::from_utf8_lossy).unwrap_or_default(),
|
|
|
|
|
message.map(String::from_utf8_lossy).unwrap_or_default()
|
|
|
|
|
)
|
|
|
|
|
.into()),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub async fn getscript(&mut self, script_name: &[u8]) -> Result<Vec<u8>> {
|
|
|
|
|
let mut ret = Vec::new();
|
|
|
|
|
self.inner
|
|
|
|
|
.send_literal(format!("Getscript {{{len}+}}\r\n", len = script_name.len()).as_bytes())
|
|
|
|
|
.await?;
|
|
|
|
|
self.inner.send_literal(script_name).await?;
|
|
|
|
|
self.inner
|
|
|
|
|
.read_response(&mut ret, RequiredResponses::empty())
|
|
|
|
|
.await?;
|
|
|
|
|
if let Ok((_, ManageSieveResponse::NoBye { code, message })) =
|
|
|
|
|
parser::response_oknobye(&ret)
|
|
|
|
|
{
|
|
|
|
|
return Err(format!(
|
|
|
|
|
"Could not set active script: {} {}",
|
|
|
|
|
code.map(String::from_utf8_lossy).unwrap_or_default(),
|
|
|
|
|
message.map(String::from_utf8_lossy).unwrap_or_default()
|
|
|
|
|
)
|
|
|
|
|
.into());
|
|
|
|
|
}
|
|
|
|
|
let (_rest, script) =
|
|
|
|
|
parser::terminated(parser::getscript, parser::tag_no_case(b"OK"))(&ret)?;
|
|
|
|
|
Ok(script.to_vec())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub async fn deletescript(&mut self, script_name: &[u8]) -> Result<()> {
|
|
|
|
|
let mut ret = Vec::new();
|
|
|
|
|
self.inner
|
|
|
|
|
.send_literal(
|
|
|
|
|
format!("Deletescript {{{len}+}}\r\n", len = script_name.len()).as_bytes(),
|
|
|
|
|
)
|
|
|
|
|
.await?;
|
|
|
|
|
self.inner.send_literal(script_name).await?;
|
|
|
|
|
self.inner
|
|
|
|
|
.read_response(&mut ret, RequiredResponses::empty())
|
|
|
|
|
.await?;
|
|
|
|
|
let (_rest, response) = parser::response_oknobye(&ret)?;
|
|
|
|
|
match response {
|
|
|
|
|
ManageSieveResponse::Ok { .. } => Ok(()),
|
|
|
|
|
ManageSieveResponse::NoBye { code, message } => Err(format!(
|
|
|
|
|
"Could not delete script: {} {}",
|
|
|
|
|
code.map(String::from_utf8_lossy).unwrap_or_default(),
|
|
|
|
|
message.map(String::from_utf8_lossy).unwrap_or_default()
|
|
|
|
|
)
|
|
|
|
|
.into()),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub async fn renamescript(&mut self) -> Result<()> {
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub mod parser {
|
|
|
|
|
use nom::{
|
|
|
|
|
branch::alt,
|
|
|
|
|
bytes::complete::tag,
|
|
|
|
|
character::complete::crlf,
|
|
|
|
|
combinator::{iterator, map, opt},
|
|
|
|
|
multi::separated_list1,
|
|
|
|
|
sequence::separated_pair,
|
|
|
|
|
};
|
|
|
|
|
pub use nom::{
|
|
|
|
|
bytes::complete::{is_not, tag_no_case},
|
|
|
|
@ -79,6 +255,34 @@ mod parser {
|
|
|
|
|
|
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
|
|
/// Return a byte sequence surrounded by "s and decoded if necessary
|
|
|
|
|
pub fn quoted_raw(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
|
|
|
if input.is_empty() || input[0] != b'"' {
|
|
|
|
|
return Err(nom::Err::Error((input, "empty").into()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let mut i = 1;
|
|
|
|
|
while i < input.len() {
|
|
|
|
|
if input[i] == b'\"' && input[i - 1] != b'\\' {
|
|
|
|
|
return Ok((&input[i + 1..], &input[1..i]));
|
|
|
|
|
}
|
|
|
|
|
i += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Err(nom::Err::Error((input, "no quotes").into()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn managesieve_capabilities(input: &[u8]) -> Result<Vec<(&[u8], &[u8])>> {
|
|
|
|
|
let (_, ret) = separated_list1(
|
|
|
|
|
tag(b"\r\n"),
|
|
|
|
|
alt((
|
|
|
|
|
separated_pair(quoted_raw, tag(b" "), quoted_raw),
|
|
|
|
|
map(quoted_raw, |q| (q, &b""[..])),
|
|
|
|
|
)),
|
|
|
|
|
)(input)?;
|
|
|
|
|
Ok(ret)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn sieve_name(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
|
|
|
crate::backends::imap::protocol_parser::string_token(input)
|
|
|
|
|
}
|
|
|
|
@ -148,6 +352,10 @@ mod parser {
|
|
|
|
|
))(input)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_managesieve_listscripts() {
|
|
|
|
|
let input_1 = b"\"summer_script\"\r\n\"vacation_script\"\r\n{13}\r\nclever\"script\r\n\"main_script\" ACTIVE\r\nOK";
|
|
|
|
@ -273,209 +481,4 @@ mod parser {
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Return a byte sequence surrounded by "s and decoded if necessary
|
|
|
|
|
pub fn quoted_raw(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
|
|
|
|
if input.is_empty() || input[0] != b'"' {
|
|
|
|
|
return Err(nom::Err::Error((input, "empty").into()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let mut i = 1;
|
|
|
|
|
while i < input.len() {
|
|
|
|
|
if input[i] == b'\"' && input[i - 1] != b'\\' {
|
|
|
|
|
return Ok((&input[i + 1..], &input[1..i]));
|
|
|
|
|
}
|
|
|
|
|
i += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Err(nom::Err::Error((input, "no quotes").into()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl ManageSieveConnection {
|
|
|
|
|
pub fn new(
|
|
|
|
|
account_hash: crate::backends::AccountHash,
|
|
|
|
|
account_name: String,
|
|
|
|
|
s: &AccountSettings,
|
|
|
|
|
event_consumer: crate::backends::BackendEventConsumer,
|
|
|
|
|
) -> Result<Self> {
|
|
|
|
|
let server_hostname = get_conf_val!(s["server_hostname"])?;
|
|
|
|
|
let server_username = get_conf_val!(s["server_username"])?;
|
|
|
|
|
let server_password = get_conf_val!(s["server_password"])?;
|
|
|
|
|
let server_port = get_conf_val!(s["server_port"], 4190)?;
|
|
|
|
|
let danger_accept_invalid_certs: bool =
|
|
|
|
|
get_conf_val!(s["danger_accept_invalid_certs"], false)?;
|
|
|
|
|
let timeout = get_conf_val!(s["timeout"], 16_u64)?;
|
|
|
|
|
let timeout = if timeout == 0 {
|
|
|
|
|
None
|
|
|
|
|
} else {
|
|
|
|
|
Some(std::time::Duration::from_secs(timeout))
|
|
|
|
|
};
|
|
|
|
|
let server_conf = ImapServerConf {
|
|
|
|
|
server_hostname: server_hostname.to_string(),
|
|
|
|
|
server_username: server_username.to_string(),
|
|
|
|
|
server_password: server_password.to_string(),
|
|
|
|
|
server_port,
|
|
|
|
|
use_starttls: true,
|
|
|
|
|
use_tls: true,
|
|
|
|
|
danger_accept_invalid_certs,
|
|
|
|
|
protocol: ImapProtocol::ManageSieve,
|
|
|
|
|
timeout,
|
|
|
|
|
};
|
|
|
|
|
let uid_store = Arc::new(UIDStore {
|
|
|
|
|
is_online: Arc::new(Mutex::new((
|
|
|
|
|
SystemTime::now(),
|
|
|
|
|
Err(Error::new("Account is uninitialised.")),
|
|
|
|
|
))),
|
|
|
|
|
..UIDStore::new(
|
|
|
|
|
account_hash,
|
|
|
|
|
account_name.into(),
|
|
|
|
|
event_consumer,
|
|
|
|
|
server_conf.timeout,
|
|
|
|
|
)
|
|
|
|
|
});
|
|
|
|
|
Ok(Self {
|
|
|
|
|
inner: ImapConnection::new_connection(
|
|
|
|
|
&server_conf,
|
|
|
|
|
#[cfg(debug_assertions)]
|
|
|
|
|
"ManageSieveConnection::new()".into(),
|
|
|
|
|
uid_store,
|
|
|
|
|
),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub async fn havespace(&mut self) -> Result<()> {
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub async fn putscript(&mut self, script_name: &[u8], script: &[u8]) -> Result<()> {
|
|
|
|
|
let mut ret = Vec::new();
|
|
|
|
|
self.inner
|
|
|
|
|
.send_literal(format!("Putscript {{{len}+}}\r\n", len = script_name.len()).as_bytes())
|
|
|
|
|
.await?;
|
|
|
|
|
self.inner.send_literal(script_name).await?;
|
|
|
|
|
self.inner
|
|
|
|
|
.send_literal(format!(" {{{len}+}}\r\n", len = script.len()).as_bytes())
|
|
|
|
|
.await?;
|
|
|
|
|
self.inner.send_literal(script).await?;
|
|
|
|
|
self.inner
|
|
|
|
|
.read_response(&mut ret, RequiredResponses::empty())
|
|
|
|
|
.await?;
|
|
|
|
|
let (_rest, response) = parser::response_oknobye(&ret)?;
|
|
|
|
|
match response {
|
|
|
|
|
ManageSieveResponse::Ok { .. } => Ok(()),
|
|
|
|
|
ManageSieveResponse::NoBye { code, message } => Err(format!(
|
|
|
|
|
"Could not upload script: {} {}",
|
|
|
|
|
code.map(String::from_utf8_lossy).unwrap_or_default(),
|
|
|
|
|
message.map(String::from_utf8_lossy).unwrap_or_default()
|
|
|
|
|
)
|
|
|
|
|
.into()),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub async fn listscripts(&mut self) -> Result<Vec<(Vec<u8>, bool)>> {
|
|
|
|
|
let mut ret = Vec::new();
|
|
|
|
|
self.inner.send_command_raw(b"Listscripts").await?;
|
|
|
|
|
self.inner
|
|
|
|
|
.read_response(&mut ret, RequiredResponses::empty())
|
|
|
|
|
.await?;
|
|
|
|
|
let (_rest, scripts) =
|
|
|
|
|
parser::terminated(parser::listscripts, parser::tag_no_case(b"OK"))(&ret)?;
|
|
|
|
|
Ok(scripts
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|(n, a)| (n.to_vec(), a))
|
|
|
|
|
.collect::<Vec<(Vec<u8>, bool)>>())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub async fn checkscript(&mut self, script: &[u8]) -> Result<()> {
|
|
|
|
|
let mut ret = Vec::new();
|
|
|
|
|
self.inner
|
|
|
|
|
.send_literal(format!("Checkscript {{{len}+}}\r\n", len = script.len()).as_bytes())
|
|
|
|
|
.await?;
|
|
|
|
|
self.inner.send_literal(script).await?;
|
|
|
|
|
self.inner
|
|
|
|
|
.read_response(&mut ret, RequiredResponses::empty())
|
|
|
|
|
.await?;
|
|
|
|
|
let (_rest, response) = parser::response_oknobye(&ret)?;
|
|
|
|
|
match response {
|
|
|
|
|
ManageSieveResponse::Ok { .. } => Ok(()),
|
|
|
|
|
ManageSieveResponse::NoBye { code, message } => Err(format!(
|
|
|
|
|
"Checkscript reply: {} {}",
|
|
|
|
|
code.map(String::from_utf8_lossy).unwrap_or_default(),
|
|
|
|
|
message.map(String::from_utf8_lossy).unwrap_or_default()
|
|
|
|
|
)
|
|
|
|
|
.into()),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub async fn setactive(&mut self, script_name: &[u8]) -> Result<()> {
|
|
|
|
|
let mut ret = Vec::new();
|
|
|
|
|
self.inner
|
|
|
|
|
.send_literal(format!("Setactive {{{len}+}}\r\n", len = script_name.len()).as_bytes())
|
|
|
|
|
.await?;
|
|
|
|
|
self.inner.send_literal(script_name).await?;
|
|
|
|
|
self.inner
|
|
|
|
|
.read_response(&mut ret, RequiredResponses::empty())
|
|
|
|
|
.await?;
|
|
|
|
|
let (_rest, response) = parser::response_oknobye(&ret)?;
|
|
|
|
|
match response {
|
|
|
|
|
ManageSieveResponse::Ok { .. } => Ok(()),
|
|
|
|
|
ManageSieveResponse::NoBye { code, message } => Err(format!(
|
|
|
|
|
"Could not set active script: {} {}",
|
|
|
|
|
code.map(String::from_utf8_lossy).unwrap_or_default(),
|
|
|
|
|
message.map(String::from_utf8_lossy).unwrap_or_default()
|
|
|
|
|
)
|
|
|
|
|
.into()),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub async fn getscript(&mut self, script_name: &[u8]) -> Result<Vec<u8>> {
|
|
|
|
|
let mut ret = Vec::new();
|
|
|
|
|
self.inner
|
|
|
|
|
.send_literal(format!("Getscript {{{len}+}}\r\n", len = script_name.len()).as_bytes())
|
|
|
|
|
.await?;
|
|
|
|
|
self.inner.send_literal(script_name).await?;
|
|
|
|
|
self.inner
|
|
|
|
|
.read_response(&mut ret, RequiredResponses::empty())
|
|
|
|
|
.await?;
|
|
|
|
|
if let Ok((_, ManageSieveResponse::NoBye { code, message })) =
|
|
|
|
|
parser::response_oknobye(&ret)
|
|
|
|
|
{
|
|
|
|
|
return Err(format!(
|
|
|
|
|
"Could not set active script: {} {}",
|
|
|
|
|
code.map(String::from_utf8_lossy).unwrap_or_default(),
|
|
|
|
|
message.map(String::from_utf8_lossy).unwrap_or_default()
|
|
|
|
|
)
|
|
|
|
|
.into());
|
|
|
|
|
}
|
|
|
|
|
let (_rest, script) =
|
|
|
|
|
parser::terminated(parser::getscript, parser::tag_no_case(b"OK"))(&ret)?;
|
|
|
|
|
Ok(script.to_vec())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub async fn deletescript(&mut self, script_name: &[u8]) -> Result<()> {
|
|
|
|
|
let mut ret = Vec::new();
|
|
|
|
|
self.inner
|
|
|
|
|
.send_literal(
|
|
|
|
|
format!("Deletescript {{{len}+}}\r\n", len = script_name.len()).as_bytes(),
|
|
|
|
|
)
|
|
|
|
|
.await?;
|
|
|
|
|
self.inner.send_literal(script_name).await?;
|
|
|
|
|
self.inner
|
|
|
|
|
.read_response(&mut ret, RequiredResponses::empty())
|
|
|
|
|
.await?;
|
|
|
|
|
let (_rest, response) = parser::response_oknobye(&ret)?;
|
|
|
|
|
match response {
|
|
|
|
|
ManageSieveResponse::Ok { .. } => Ok(()),
|
|
|
|
|
ManageSieveResponse::NoBye { code, message } => Err(format!(
|
|
|
|
|
"Could not delete script: {} {}",
|
|
|
|
|
code.map(String::from_utf8_lossy).unwrap_or_default(),
|
|
|
|
|
message.map(String::from_utf8_lossy).unwrap_or_default()
|
|
|
|
|
)
|
|
|
|
|
.into()),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub async fn renamescript(&mut self) -> Result<()> {
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|