mirror of
https://github.com/chatmail/core.git
synced 2026-04-04 06:22:16 +03:00
Compare commits
3 Commits
v1.140.0
...
link2xt/py
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a9dbf05d8d | ||
|
|
90c30879b1 | ||
|
|
0ca1318118 |
14
.github/workflows/ci.yml
vendored
14
.github/workflows/ci.yml
vendored
@@ -209,11 +209,11 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
# Currently used Rust version.
|
||||
# Currently used Python version.
|
||||
- os: ubuntu-latest
|
||||
python: 3.12
|
||||
python: 3.13
|
||||
- os: macos-latest
|
||||
python: 3.12
|
||||
python: 3.13
|
||||
|
||||
# PyPy tests
|
||||
- os: ubuntu-latest
|
||||
@@ -243,6 +243,7 @@ jobs:
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ matrix.python }}
|
||||
allow-prereleases: true
|
||||
|
||||
- name: Install tox
|
||||
run: pip install tox
|
||||
@@ -263,11 +264,11 @@ jobs:
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
python: 3.12
|
||||
python: 3.13
|
||||
- os: macos-latest
|
||||
python: 3.12
|
||||
python: 3.13
|
||||
- os: windows-latest
|
||||
python: 3.12
|
||||
python: 3.13
|
||||
|
||||
# PyPy tests
|
||||
- os: ubuntu-latest
|
||||
@@ -289,6 +290,7 @@ jobs:
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ matrix.python }}
|
||||
allow-prereleases: true
|
||||
|
||||
- name: Install tox
|
||||
run: pip install tox
|
||||
|
||||
@@ -17,6 +17,8 @@ classifiers = [
|
||||
"Programming Language :: Python :: 3.9",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
"Programming Language :: Python :: 3.13",
|
||||
"Topic :: Communications :: Chat",
|
||||
"Topic :: Communications :: Email"
|
||||
]
|
||||
|
||||
@@ -31,6 +31,6 @@ unset CHATMAIL_DOMAIN
|
||||
|
||||
# Try to build wheels for a range of interpreters, but don't fail if they are not available.
|
||||
# E.g. musllinux_1_1 does not have PyPy interpreters as of 2022-07-10
|
||||
tox --workdir "$TOXWORKDIR" -e py37,py38,py39,py310,py311,py312,pypy37,pypy38,pypy39,pypy310 --skip-missing-interpreters true
|
||||
tox --workdir "$TOXWORKDIR" -e py37,py38,py39,py310,py311,py312,py313,pypy37,pypy38,pypy39,pypy310 --skip-missing-interpreters true
|
||||
|
||||
auditwheel repair "$TOXWORKDIR"/wheelhouse/deltachat* -w "$TOXWORKDIR/wheelhouse"
|
||||
|
||||
@@ -184,7 +184,7 @@ impl Session {
|
||||
bail!("Attempt to fetch UID 0");
|
||||
}
|
||||
|
||||
self.select_folder(context, Some(folder)).await?;
|
||||
self.select_folder(context, folder).await?;
|
||||
|
||||
// we are connected, and the folder is selected
|
||||
info!(context, "Downloading message {}/{} fully...", folder, uid);
|
||||
|
||||
10
src/imap.rs
10
src/imap.rs
@@ -838,7 +838,7 @@ impl Session {
|
||||
// Collect pairs of UID and Message-ID.
|
||||
let mut msgs = BTreeMap::new();
|
||||
|
||||
self.select_folder(context, Some(folder)).await?;
|
||||
self.select_folder(context, folder).await?;
|
||||
|
||||
let mut list = self
|
||||
.uid_fetch("1:*", RFC724MID_UID)
|
||||
@@ -1039,7 +1039,7 @@ impl Session {
|
||||
// MOVE/DELETE operations. This does not result in multiple SELECT commands
|
||||
// being sent because `select_folder()` does nothing if the folder is already
|
||||
// selected.
|
||||
self.select_folder(context, Some(folder)).await?;
|
||||
self.select_folder(context, folder).await?;
|
||||
|
||||
// Empty target folder name means messages should be deleted.
|
||||
if target.is_empty() {
|
||||
@@ -1087,7 +1087,7 @@ impl Session {
|
||||
.await?;
|
||||
|
||||
for (folder, rowid_set, uid_set) in UidGrouper::from(rows) {
|
||||
self.select_folder(context, Some(&folder))
|
||||
self.select_folder(context, &folder)
|
||||
.await
|
||||
.context("failed to select folder")?;
|
||||
|
||||
@@ -1131,7 +1131,7 @@ impl Session {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
self.select_folder(context, Some(folder))
|
||||
self.select_folder(context, folder)
|
||||
.await
|
||||
.context("failed to select folder")?;
|
||||
|
||||
@@ -1563,7 +1563,7 @@ impl Session {
|
||||
) -> Result<Option<&'a str>> {
|
||||
// Close currently selected folder if needed.
|
||||
// We are going to select folders using low-level EXAMINE operations below.
|
||||
self.select_folder(context, None).await?;
|
||||
self.maybe_close_folder(context).await?;
|
||||
|
||||
for folder in folders {
|
||||
info!(context, "Looking for MVBOX-folder \"{}\"...", &folder);
|
||||
|
||||
@@ -29,7 +29,7 @@ impl Session {
|
||||
) -> Result<Self> {
|
||||
use futures::future::FutureExt;
|
||||
|
||||
self.select_folder(context, Some(folder)).await?;
|
||||
self.select_folder(context, folder).await?;
|
||||
|
||||
if self.server_sent_unsolicited_exists(context)? {
|
||||
return Ok(self);
|
||||
|
||||
@@ -55,15 +55,13 @@ impl ImapSession {
|
||||
pub(crate) async fn select_folder(
|
||||
&mut self,
|
||||
context: &Context,
|
||||
folder: Option<&str>,
|
||||
folder: &str,
|
||||
) -> Result<NewlySelected> {
|
||||
// if there is a new folder and the new folder is equal to the selected one, there's nothing to do.
|
||||
// if there is _no_ new folder, we continue as we might want to expunge below.
|
||||
if let Some(folder) = folder {
|
||||
if let Some(selected_folder) = &self.selected_folder {
|
||||
if folder == selected_folder {
|
||||
return Ok(NewlySelected::No);
|
||||
}
|
||||
if let Some(selected_folder) = &self.selected_folder {
|
||||
if folder == selected_folder {
|
||||
return Ok(NewlySelected::No);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,34 +69,30 @@ impl ImapSession {
|
||||
self.maybe_close_folder(context).await?;
|
||||
|
||||
// select new folder
|
||||
if let Some(folder) = folder {
|
||||
let res = if self.can_condstore() {
|
||||
self.select_condstore(folder).await
|
||||
} else {
|
||||
self.select(folder).await
|
||||
};
|
||||
|
||||
// <https://tools.ietf.org/html/rfc3501#section-6.3.1>
|
||||
// says that if the server reports select failure we are in
|
||||
// authenticated (not-select) state.
|
||||
|
||||
match res {
|
||||
Ok(mailbox) => {
|
||||
self.selected_folder = Some(folder.to_string());
|
||||
self.selected_mailbox = Some(mailbox);
|
||||
Ok(NewlySelected::Yes)
|
||||
}
|
||||
Err(async_imap::error::Error::ConnectionLost) => Err(Error::ConnectionLost),
|
||||
Err(async_imap::error::Error::Validate(_)) => {
|
||||
Err(Error::BadFolderName(folder.to_string()))
|
||||
}
|
||||
Err(async_imap::error::Error::No(response)) => {
|
||||
Err(Error::NoFolder(folder.to_string(), response))
|
||||
}
|
||||
Err(err) => Err(Error::Other(err.to_string())),
|
||||
}
|
||||
let res = if self.can_condstore() {
|
||||
self.select_condstore(folder).await
|
||||
} else {
|
||||
Ok(NewlySelected::No)
|
||||
self.select(folder).await
|
||||
};
|
||||
|
||||
// <https://tools.ietf.org/html/rfc3501#section-6.3.1>
|
||||
// says that if the server reports select failure we are in
|
||||
// authenticated (not-select) state.
|
||||
|
||||
match res {
|
||||
Ok(mailbox) => {
|
||||
self.selected_folder = Some(folder.to_string());
|
||||
self.selected_mailbox = Some(mailbox);
|
||||
Ok(NewlySelected::Yes)
|
||||
}
|
||||
Err(async_imap::error::Error::ConnectionLost) => Err(Error::ConnectionLost),
|
||||
Err(async_imap::error::Error::Validate(_)) => {
|
||||
Err(Error::BadFolderName(folder.to_string()))
|
||||
}
|
||||
Err(async_imap::error::Error::No(response)) => {
|
||||
Err(Error::NoFolder(folder.to_string(), response))
|
||||
}
|
||||
Err(err) => Err(Error::Other(err.to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +102,7 @@ impl ImapSession {
|
||||
context: &Context,
|
||||
folder: &str,
|
||||
) -> anyhow::Result<NewlySelected> {
|
||||
match self.select_folder(context, Some(folder)).await {
|
||||
match self.select_folder(context, folder).await {
|
||||
Ok(newly_selected) => Ok(newly_selected),
|
||||
Err(err) => match err {
|
||||
Error::NoFolder(..) => {
|
||||
@@ -118,7 +112,7 @@ impl ImapSession {
|
||||
info!(context, "Couldn't select folder, then create() failed: {err:#}.");
|
||||
// Need to recheck, could have been created in parallel.
|
||||
}
|
||||
let select_res = self.select_folder(context, Some(folder)).await.with_context(|| format!("failed to select newely created folder {folder}"));
|
||||
let select_res = self.select_folder(context, folder).await.with_context(|| format!("failed to select newely created folder {folder}"));
|
||||
if select_res.is_err() {
|
||||
create_res?;
|
||||
}
|
||||
|
||||
36
src/smtp.rs
36
src/smtp.rs
@@ -830,20 +830,26 @@ async fn send_mdn(context: &Context, smtp: &mut Smtp) -> Result<bool> {
|
||||
.await
|
||||
.context("failed to update MDN retries count")?;
|
||||
|
||||
let res = send_mdn_msg_id(context, msg_id, contact_id, smtp).await;
|
||||
if let Err(ref err) = res {
|
||||
// If there is an error, for example there is no message corresponding to the msg_id in the
|
||||
// database, do not try to send this MDN again.
|
||||
warn!(
|
||||
context,
|
||||
"Error sending MDN for {msg_id}, removing it: {err:#}."
|
||||
);
|
||||
context
|
||||
.sql
|
||||
.execute("DELETE FROM smtp_mdns WHERE msg_id = ?", (msg_id,))
|
||||
.await?;
|
||||
match send_mdn_msg_id(context, msg_id, contact_id, smtp).await {
|
||||
Err(err) => {
|
||||
// If there is an error, for example there is no message corresponding to the msg_id in the
|
||||
// database, do not try to send this MDN again.
|
||||
warn!(
|
||||
context,
|
||||
"Error sending MDN for {msg_id}, removing it: {err:#}."
|
||||
);
|
||||
context
|
||||
.sql
|
||||
.execute("DELETE FROM smtp_mdns WHERE msg_id = ?", (msg_id,))
|
||||
.await?;
|
||||
Err(err)
|
||||
}
|
||||
Ok(false) => {
|
||||
bail!("Temporary error while sending an MDN");
|
||||
}
|
||||
Ok(true) => {
|
||||
// Successfully sent MDN.
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
// If there's a temporary error, pretend there are no more MDNs to send. It's unlikely that
|
||||
// other MDNs could be sent successfully in case of connectivity problems.
|
||||
res
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user