mirror of
https://github.com/chatmail/core.git
synced 2026-04-17 21:46:35 +03:00
Resultification
This commit is contained in:
@@ -1570,6 +1570,8 @@ pub unsafe extern "C" fn dc_delete_msgs(
|
|||||||
let msg_ids = convert_and_prune_message_ids(msg_ids, msg_cnt);
|
let msg_ids = convert_and_prune_message_ids(msg_ids, msg_cnt);
|
||||||
|
|
||||||
block_on(message::delete_msgs(ctx, &msg_ids))
|
block_on(message::delete_msgs(ctx, &msg_ids))
|
||||||
|
.log_err(ctx, "failed dc_delete_msgs() call")
|
||||||
|
.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@@ -2047,7 +2049,9 @@ pub unsafe extern "C" fn dc_send_locations_to_chat(
|
|||||||
ctx,
|
ctx,
|
||||||
ChatId::new(chat_id),
|
ChatId::new(chat_id),
|
||||||
seconds as i64,
|
seconds as i64,
|
||||||
));
|
))
|
||||||
|
.log_err(ctx, "Failed dc_send_locations_to_chat()")
|
||||||
|
.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@@ -2066,7 +2070,8 @@ pub unsafe extern "C" fn dc_is_sending_locations_to_chat(
|
|||||||
Some(ChatId::new(chat_id))
|
Some(ChatId::new(chat_id))
|
||||||
};
|
};
|
||||||
|
|
||||||
block_on(location::is_sending_locations_to_chat(ctx, chat_id)) as libc::c_int
|
block_on(location::is_sending_locations_to_chat(ctx, chat_id))
|
||||||
|
.unwrap_or_log_default(ctx, "Failed dc_is_sending_locations_to_chat()") as libc::c_int
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
|||||||
@@ -602,7 +602,7 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if location::is_sending_locations_to_chat(&context, None).await {
|
if location::is_sending_locations_to_chat(&context, None).await? {
|
||||||
println!("Location streaming enabled.");
|
println!("Location streaming enabled.");
|
||||||
}
|
}
|
||||||
println!("{} chats", cnt);
|
println!("{} chats", cnt);
|
||||||
@@ -773,7 +773,7 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu
|
|||||||
&context,
|
&context,
|
||||||
Some(sel_chat.as_ref().unwrap().get_id())
|
Some(sel_chat.as_ref().unwrap().get_id())
|
||||||
)
|
)
|
||||||
.await,
|
.await?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
"getlocations" => {
|
"getlocations" => {
|
||||||
@@ -818,7 +818,7 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu
|
|||||||
sel_chat.as_ref().unwrap().get_id(),
|
sel_chat.as_ref().unwrap().get_id(),
|
||||||
seconds,
|
seconds,
|
||||||
)
|
)
|
||||||
.await;
|
.await?;
|
||||||
println!(
|
println!(
|
||||||
"Locations will be sent to Chat#{} for {} seconds. Use 'setlocation <lat> <lng>' to play around.",
|
"Locations will be sent to Chat#{} for {} seconds. Use 'setlocation <lat> <lng>' to play around.",
|
||||||
sel_chat.as_ref().unwrap().get_id(),
|
sel_chat.as_ref().unwrap().get_id(),
|
||||||
@@ -1067,7 +1067,7 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu
|
|||||||
ensure!(!arg1.is_empty(), "Argument <msg-id> missing.");
|
ensure!(!arg1.is_empty(), "Argument <msg-id> missing.");
|
||||||
let mut ids = [MsgId::new(0); 1];
|
let mut ids = [MsgId::new(0); 1];
|
||||||
ids[0] = MsgId::new(arg1.parse()?);
|
ids[0] = MsgId::new(arg1.parse()?);
|
||||||
message::delete_msgs(&context, &ids).await;
|
message::delete_msgs(&context, &ids).await?;
|
||||||
}
|
}
|
||||||
"listcontacts" | "contacts" | "listverified" => {
|
"listcontacts" | "contacts" | "listverified" => {
|
||||||
let contacts = Contact::get_all(
|
let contacts = Contact::get_all(
|
||||||
|
|||||||
20
src/chat.rs
20
src/chat.rs
@@ -183,7 +183,7 @@ impl ChatId {
|
|||||||
|| contact_id == DC_CONTACT_ID_SELF
|
|| contact_id == DC_CONTACT_ID_SELF
|
||||||
{
|
{
|
||||||
let chat_id = ChatId::get_for_contact(context, contact_id).await?;
|
let chat_id = ChatId::get_for_contact(context, contact_id).await?;
|
||||||
Contact::scaleup_origin_by_id(context, contact_id, Origin::CreateChat).await;
|
Contact::scaleup_origin_by_id(context, contact_id, Origin::CreateChat).await?;
|
||||||
chat_id
|
chat_id
|
||||||
} else {
|
} else {
|
||||||
warn!(
|
warn!(
|
||||||
@@ -284,7 +284,7 @@ impl ChatId {
|
|||||||
for contact_id in get_chat_contacts(context, self).await? {
|
for contact_id in get_chat_contacts(context, self).await? {
|
||||||
if contact_id != DC_CONTACT_ID_SELF {
|
if contact_id != DC_CONTACT_ID_SELF {
|
||||||
Contact::scaleup_origin_by_id(context, contact_id, Origin::CreateChat)
|
Contact::scaleup_origin_by_id(context, contact_id, Origin::CreateChat)
|
||||||
.await;
|
.await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -497,7 +497,7 @@ impl ChatId {
|
|||||||
chat_id: ChatId::new(0),
|
chat_id: ChatId::new(0),
|
||||||
});
|
});
|
||||||
|
|
||||||
job::kill_action(context, Action::Housekeeping).await;
|
job::kill_action(context, Action::Housekeeping).await?;
|
||||||
let j = job::Job::new(Action::Housekeeping, 0, Params::new(), 10);
|
let j = job::Job::new(Action::Housekeeping, 0, Params::new(), 10);
|
||||||
job::add(context, j).await;
|
job::add(context, j).await;
|
||||||
|
|
||||||
@@ -2450,19 +2450,15 @@ impl rusqlite::types::FromSql for MuteDuration {
|
|||||||
|
|
||||||
pub async fn set_muted(context: &Context, chat_id: ChatId, duration: MuteDuration) -> Result<()> {
|
pub async fn set_muted(context: &Context, chat_id: ChatId, duration: MuteDuration) -> Result<()> {
|
||||||
ensure!(!chat_id.is_special(), "Invalid chat ID");
|
ensure!(!chat_id.is_special(), "Invalid chat ID");
|
||||||
if context
|
context
|
||||||
.sql
|
.sql
|
||||||
.execute(
|
.execute(
|
||||||
"UPDATE chats SET muted_until=? WHERE id=?;",
|
"UPDATE chats SET muted_until=? WHERE id=?;",
|
||||||
paramsv![duration, chat_id],
|
paramsv![duration, chat_id],
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.is_ok()
|
.context(format!("Failed to set mute duration for {}", chat_id))?;
|
||||||
{
|
context.emit_event(EventType::ChatModified(chat_id));
|
||||||
context.emit_event(EventType::ChatModified(chat_id));
|
|
||||||
} else {
|
|
||||||
bail!("Failed to set mute duration, chat might not exist -");
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3252,7 +3248,9 @@ mod tests {
|
|||||||
assert!(chat.get_profile_image(&t).await.unwrap().is_some());
|
assert!(chat.get_profile_image(&t).await.unwrap().is_some());
|
||||||
|
|
||||||
// delete device message, make sure it is not added again
|
// delete device message, make sure it is not added again
|
||||||
message::delete_msgs(&t, &[*msg1_id.as_ref().unwrap()]).await;
|
message::delete_msgs(&t, &[*msg1_id.as_ref().unwrap()])
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
let msg1 = message::Message::load_from_db(&t, *msg1_id.as_ref().unwrap()).await;
|
let msg1 = message::Message::load_from_db(&t, *msg1_id.as_ref().unwrap()).await;
|
||||||
assert!(msg1.is_err() || msg1.unwrap().chat_id.is_trash());
|
assert!(msg1.is_err() || msg1.unwrap().chat_id.is_trash());
|
||||||
let msg3_id = add_device_msg(&t, Some("any-label"), Some(&mut msg2)).await;
|
let msg3_id = add_device_msg(&t, Some("any-label"), Some(&mut msg2)).await;
|
||||||
|
|||||||
@@ -317,7 +317,7 @@ impl Context {
|
|||||||
.set_raw_config(key, value)
|
.set_raw_config(key, value)
|
||||||
.await
|
.await
|
||||||
.map_err(Into::into);
|
.map_err(Into::into);
|
||||||
job::schedule_resync(self).await;
|
job::schedule_resync(self).await?;
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
|||||||
@@ -1109,15 +1109,19 @@ impl Contact {
|
|||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn scaleup_origin_by_id(context: &Context, contact_id: u32, origin: Origin) -> bool {
|
pub async fn scaleup_origin_by_id(
|
||||||
|
context: &Context,
|
||||||
|
contact_id: u32,
|
||||||
|
origin: Origin,
|
||||||
|
) -> Result<()> {
|
||||||
context
|
context
|
||||||
.sql
|
.sql
|
||||||
.execute(
|
.execute(
|
||||||
"UPDATE contacts SET origin=? WHERE id=? AND origin<?;",
|
"UPDATE contacts SET origin=? WHERE id=? AND origin<?;",
|
||||||
paramsv![origin, contact_id as i32, origin],
|
paramsv![origin, contact_id as i32, origin],
|
||||||
)
|
)
|
||||||
.await
|
.await?;
|
||||||
.is_ok()
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -618,7 +618,7 @@ async fn add_parts(
|
|||||||
// we do not want any chat to be created implicitly. Because of the origin-scale-up,
|
// we do not want any chat to be created implicitly. Because of the origin-scale-up,
|
||||||
// the contact requests will pop up and this should be just fine.
|
// the contact requests will pop up and this should be just fine.
|
||||||
Contact::scaleup_origin_by_id(context, from_id, Origin::IncomingReplyTo)
|
Contact::scaleup_origin_by_id(context, from_id, Origin::IncomingReplyTo)
|
||||||
.await;
|
.await?;
|
||||||
info!(
|
info!(
|
||||||
context,
|
context,
|
||||||
"Message is a reply to a known message, mark sender as known.",
|
"Message is a reply to a known message, mark sender as known.",
|
||||||
|
|||||||
@@ -583,7 +583,7 @@ impl Imap {
|
|||||||
folder, old_uid_next, uid_next, new_uid_validity,
|
folder, old_uid_next, uid_next, new_uid_validity,
|
||||||
);
|
);
|
||||||
set_uid_next(context, folder, uid_next).await?;
|
set_uid_next(context, folder, uid_next).await?;
|
||||||
job::schedule_resync(context).await;
|
job::schedule_resync(context).await?;
|
||||||
}
|
}
|
||||||
uid_next != old_uid_next // If uid_next changed, there are new emails
|
uid_next != old_uid_next // If uid_next changed, there are new emails
|
||||||
} else {
|
} else {
|
||||||
@@ -636,7 +636,7 @@ impl Imap {
|
|||||||
set_uid_next(context, folder, new_uid_next).await?;
|
set_uid_next(context, folder, new_uid_next).await?;
|
||||||
set_uidvalidity(context, folder, new_uid_validity).await?;
|
set_uidvalidity(context, folder, new_uid_validity).await?;
|
||||||
if old_uid_validity != 0 || old_uid_next != 0 {
|
if old_uid_validity != 0 || old_uid_next != 0 {
|
||||||
job::schedule_resync(context).await;
|
job::schedule_resync(context).await?;
|
||||||
}
|
}
|
||||||
info!(
|
info!(
|
||||||
context,
|
context,
|
||||||
|
|||||||
96
src/job.rs
96
src/job.rs
@@ -2,12 +2,11 @@
|
|||||||
//!
|
//!
|
||||||
//! This module implements a job queue maintained in the SQLite database
|
//! This module implements a job queue maintained in the SQLite database
|
||||||
//! and job types.
|
//! and job types.
|
||||||
|
use std::fmt;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::{fmt, time::Duration};
|
|
||||||
|
|
||||||
use anyhow::{bail, ensure, format_err, Context as _, Error, Result};
|
use anyhow::{bail, ensure, format_err, Context as _, Error, Result};
|
||||||
use async_smtp::smtp::response::{Category, Code, Detail};
|
use async_smtp::smtp::response::{Category, Code, Detail};
|
||||||
use async_std::task::sleep;
|
|
||||||
use deltachat_derive::{FromSql, ToSql};
|
use deltachat_derive::{FromSql, ToSql};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use rand::{thread_rng, Rng};
|
use rand::{thread_rng, Rng};
|
||||||
@@ -815,12 +814,12 @@ impl Job {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Delete all pending jobs with the given action.
|
/// Delete all pending jobs with the given action.
|
||||||
pub async fn kill_action(context: &Context, action: Action) -> bool {
|
pub async fn kill_action(context: &Context, action: Action) -> Result<()> {
|
||||||
context
|
context
|
||||||
.sql
|
.sql
|
||||||
.execute("DELETE FROM jobs WHERE action=?;", paramsv![action])
|
.execute("DELETE FROM jobs WHERE action=?;", paramsv![action])
|
||||||
.await
|
.await?;
|
||||||
.is_ok()
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove jobs with specified IDs.
|
/// Remove jobs with specified IDs.
|
||||||
@@ -1183,13 +1182,14 @@ async fn send_mdn(context: &Context, msg: &Message) -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn schedule_resync(context: &Context) {
|
pub(crate) async fn schedule_resync(context: &Context) -> Result<()> {
|
||||||
kill_action(context, Action::ResyncFolders).await;
|
kill_action(context, Action::ResyncFolders).await?;
|
||||||
add(
|
add(
|
||||||
context,
|
context,
|
||||||
Job::new(Action::ResyncFolders, 0, Params::new(), 0),
|
Job::new(Action::ResyncFolders, 0, Params::new(), 0),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a job.
|
/// Creates a job.
|
||||||
@@ -1238,21 +1238,15 @@ pub async fn add(context: &Context, job: Job) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn load_housekeeping_job(context: &Context) -> Option<Job> {
|
async fn load_housekeeping_job(context: &Context) -> Result<Option<Job>> {
|
||||||
let last_time = match context.get_config_i64(Config::LastHousekeeping).await {
|
let last_time = context.get_config_i64(Config::LastHousekeeping).await?;
|
||||||
Ok(last_time) => last_time,
|
|
||||||
Err(err) => {
|
|
||||||
warn!(context, "failed to load housekeeping config: {:?}", err);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let next_time = last_time + (60 * 60 * 24);
|
let next_time = last_time + (60 * 60 * 24);
|
||||||
if next_time <= time() {
|
if next_time <= time() {
|
||||||
kill_action(context, Action::Housekeeping).await;
|
kill_action(context, Action::Housekeeping).await?;
|
||||||
Some(Job::new(Action::Housekeeping, 0, Params::new(), 0))
|
Ok(Some(Job::new(Action::Housekeeping, 0, Params::new(), 0)))
|
||||||
} else {
|
} else {
|
||||||
None
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1266,20 +1260,9 @@ pub(crate) async fn load_next(
|
|||||||
context: &Context,
|
context: &Context,
|
||||||
thread: Thread,
|
thread: Thread,
|
||||||
info: &InterruptInfo,
|
info: &InterruptInfo,
|
||||||
) -> Option<Job> {
|
) -> Result<Option<Job>> {
|
||||||
info!(context, "loading job for {}-thread", thread);
|
info!(context, "loading job for {}-thread", thread);
|
||||||
|
|
||||||
while !context.sql.is_open().await {
|
|
||||||
// The db is closed, which means that this thread should not be running.
|
|
||||||
// Wait until the db is re-opened (if we returned None, this thread might do further damage)
|
|
||||||
warn!(
|
|
||||||
context,
|
|
||||||
"{}: load_next() was called but the db was not opened, THIS SHOULD NOT HAPPEN. Waiting...",
|
|
||||||
thread
|
|
||||||
);
|
|
||||||
sleep(Duration::from_millis(500)).await;
|
|
||||||
}
|
|
||||||
|
|
||||||
let query;
|
let query;
|
||||||
let params;
|
let params;
|
||||||
let t = time();
|
let t = time();
|
||||||
@@ -1346,51 +1329,38 @@ LIMIT 1;
|
|||||||
info!(context, "cleaning up job, because of {}", err);
|
info!(context, "cleaning up job, because of {}", err);
|
||||||
|
|
||||||
// TODO: improve by only doing a single query
|
// TODO: improve by only doing a single query
|
||||||
match context
|
let id = context
|
||||||
.sql
|
.sql
|
||||||
.query_row(query, params.clone(), |row| row.get::<_, i32>(0))
|
.query_row(query, params.clone(), |row| row.get::<_, i32>(0))
|
||||||
.await
|
.await
|
||||||
{
|
.context("Failed to retrieve invalid job ID from the database")?;
|
||||||
Ok(id) => {
|
context
|
||||||
if let Err(err) = context
|
.sql
|
||||||
.sql
|
.execute("DELETE FROM jobs WHERE id=?;", paramsv![id])
|
||||||
.execute("DELETE FROM jobs WHERE id=?;", paramsv![id])
|
.await
|
||||||
.await
|
.with_context(|| format!("Failed to delete invalid job {}", id))?;
|
||||||
{
|
|
||||||
warn!(context, "failed to delete job {}: {:?}", id, err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
error!(context, "failed to retrieve invalid job from DB: {}", err);
|
|
||||||
break None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match thread {
|
match thread {
|
||||||
Thread::Unknown => {
|
Thread::Unknown => {
|
||||||
error!(context, "unknown thread for job");
|
bail!("unknown thread for job")
|
||||||
None
|
|
||||||
}
|
}
|
||||||
Thread::Imap => {
|
Thread::Imap => {
|
||||||
if let Some(job) = job {
|
if let Some(job) = job {
|
||||||
if job.action < Action::DeleteMsgOnImap {
|
if job.action < Action::DeleteMsgOnImap {
|
||||||
load_imap_deletion_job(context)
|
Ok(load_imap_deletion_job(context).await?.or(Some(job)))
|
||||||
.await
|
|
||||||
.unwrap_or_default()
|
|
||||||
.or(Some(job))
|
|
||||||
} else {
|
} else {
|
||||||
Some(job)
|
Ok(Some(job))
|
||||||
}
|
}
|
||||||
} else if let Some(job) = load_imap_deletion_job(context).await.unwrap_or_default() {
|
} else if let Some(job) = load_imap_deletion_job(context).await? {
|
||||||
Some(job)
|
Ok(Some(job))
|
||||||
} else {
|
} else {
|
||||||
load_housekeeping_job(context).await
|
Ok(load_housekeeping_job(context).await?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Thread::Smtp => job,
|
Thread::Smtp => Ok(job),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1422,7 +1392,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[async_std::test]
|
#[async_std::test]
|
||||||
async fn test_load_next_job_two() {
|
async fn test_load_next_job_two() -> Result<()> {
|
||||||
// We want to ensure that loading jobs skips over jobs which
|
// We want to ensure that loading jobs skips over jobs which
|
||||||
// fails to load from the database instead of failing to load
|
// fails to load from the database instead of failing to load
|
||||||
// all jobs.
|
// all jobs.
|
||||||
@@ -1433,7 +1403,7 @@ mod tests {
|
|||||||
Thread::from(Action::MoveMsg),
|
Thread::from(Action::MoveMsg),
|
||||||
&InterruptInfo::new(false, None),
|
&InterruptInfo::new(false, None),
|
||||||
)
|
)
|
||||||
.await;
|
.await?;
|
||||||
// The housekeeping job should be loaded as we didn't run housekeeping in the last day:
|
// The housekeeping job should be loaded as we didn't run housekeeping in the last day:
|
||||||
assert_eq!(jobs.unwrap().action, Action::Housekeeping);
|
assert_eq!(jobs.unwrap().action, Action::Housekeeping);
|
||||||
|
|
||||||
@@ -1443,12 +1413,13 @@ mod tests {
|
|||||||
Thread::from(Action::MoveMsg),
|
Thread::from(Action::MoveMsg),
|
||||||
&InterruptInfo::new(false, None),
|
&InterruptInfo::new(false, None),
|
||||||
)
|
)
|
||||||
.await;
|
.await?;
|
||||||
assert!(jobs.is_some());
|
assert!(jobs.is_some());
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_std::test]
|
#[async_std::test]
|
||||||
async fn test_load_next_job_one() {
|
async fn test_load_next_job_one() -> Result<()> {
|
||||||
let t = TestContext::new().await;
|
let t = TestContext::new().await;
|
||||||
|
|
||||||
insert_job(&t, 1, true).await;
|
insert_job(&t, 1, true).await;
|
||||||
@@ -1458,7 +1429,8 @@ mod tests {
|
|||||||
Thread::from(Action::MoveMsg),
|
Thread::from(Action::MoveMsg),
|
||||||
&InterruptInfo::new(false, None),
|
&InterruptInfo::new(false, None),
|
||||||
)
|
)
|
||||||
.await;
|
.await?;
|
||||||
assert!(jobs.is_some());
|
assert!(jobs.is_some());
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
163
src/location.rs
163
src/location.rs
@@ -1,7 +1,7 @@
|
|||||||
//! Location handling.
|
//! Location handling.
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
use anyhow::{ensure, Error};
|
use anyhow::{ensure, Result};
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use quick_xml::events::{BytesEnd, BytesStart, BytesText};
|
use quick_xml::events::{BytesEnd, BytesStart, BytesText};
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ impl Kml {
|
|||||||
Default::default()
|
Default::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse(context: &Context, to_parse: &[u8]) -> Result<Self, Error> {
|
pub fn parse(context: &Context, to_parse: &[u8]) -> Result<Self> {
|
||||||
ensure!(to_parse.len() <= 1024 * 1024, "kml-file is too large");
|
ensure!(to_parse.len() <= 1024 * 1024, "kml-file is too large");
|
||||||
|
|
||||||
let mut reader = quick_xml::Reader::from_reader(to_parse);
|
let mut reader = quick_xml::Reader::from_reader(to_parse);
|
||||||
@@ -191,54 +191,55 @@ impl Kml {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Enables location streaming in chat identified by `chat_id` for `seconds` seconds.
|
/// Enables location streaming in chat identified by `chat_id` for `seconds` seconds.
|
||||||
pub async fn send_locations_to_chat(context: &Context, chat_id: ChatId, seconds: i64) {
|
pub async fn send_locations_to_chat(
|
||||||
|
context: &Context,
|
||||||
|
chat_id: ChatId,
|
||||||
|
seconds: i64,
|
||||||
|
) -> Result<()> {
|
||||||
|
ensure!(seconds >= 0);
|
||||||
|
ensure!(!chat_id.is_special());
|
||||||
let now = time();
|
let now = time();
|
||||||
if !(seconds < 0 || chat_id.is_special()) {
|
let is_sending_locations_before = is_sending_locations_to_chat(context, Some(chat_id)).await?;
|
||||||
let is_sending_locations_before =
|
context
|
||||||
is_sending_locations_to_chat(context, Some(chat_id)).await;
|
.sql
|
||||||
if context
|
.execute(
|
||||||
.sql
|
"UPDATE chats \
|
||||||
.execute(
|
SET locations_send_begin=?, \
|
||||||
"UPDATE chats \
|
locations_send_until=? \
|
||||||
SET locations_send_begin=?, \
|
WHERE id=?",
|
||||||
locations_send_until=? \
|
paramsv![
|
||||||
WHERE id=?",
|
if 0 != seconds { now } else { 0 },
|
||||||
paramsv![
|
if 0 != seconds { now + seconds } else { 0 },
|
||||||
if 0 != seconds { now } else { 0 },
|
chat_id,
|
||||||
if 0 != seconds { now + seconds } else { 0 },
|
],
|
||||||
chat_id,
|
)
|
||||||
],
|
.await?;
|
||||||
)
|
if 0 != seconds && !is_sending_locations_before {
|
||||||
|
let mut msg = Message::new(Viewtype::Text);
|
||||||
|
msg.text = Some(stock_str::msg_location_enabled(context).await);
|
||||||
|
msg.param.set_cmd(SystemMessage::LocationStreamingEnabled);
|
||||||
|
chat::send_msg(context, chat_id, &mut msg)
|
||||||
.await
|
.await
|
||||||
.is_ok()
|
.unwrap_or_default();
|
||||||
{
|
} else if 0 == seconds && is_sending_locations_before {
|
||||||
if 0 != seconds && !is_sending_locations_before {
|
let stock_str = stock_str::msg_location_disabled(context).await;
|
||||||
let mut msg = Message::new(Viewtype::Text);
|
chat::add_info_msg(context, chat_id, stock_str, now).await;
|
||||||
msg.text = Some(stock_str::msg_location_enabled(context).await);
|
|
||||||
msg.param.set_cmd(SystemMessage::LocationStreamingEnabled);
|
|
||||||
chat::send_msg(context, chat_id, &mut msg)
|
|
||||||
.await
|
|
||||||
.unwrap_or_default();
|
|
||||||
} else if 0 == seconds && is_sending_locations_before {
|
|
||||||
let stock_str = stock_str::msg_location_disabled(context).await;
|
|
||||||
chat::add_info_msg(context, chat_id, stock_str, now).await;
|
|
||||||
}
|
|
||||||
context.emit_event(EventType::ChatModified(chat_id));
|
|
||||||
if 0 != seconds {
|
|
||||||
schedule_maybe_send_locations(context, false).await;
|
|
||||||
job::add(
|
|
||||||
context,
|
|
||||||
job::Job::new(
|
|
||||||
job::Action::MaybeSendLocationsEnded,
|
|
||||||
chat_id.to_u32(),
|
|
||||||
Params::new(),
|
|
||||||
seconds + 1,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
context.emit_event(EventType::ChatModified(chat_id));
|
||||||
|
if 0 != seconds {
|
||||||
|
schedule_maybe_send_locations(context, false).await;
|
||||||
|
job::add(
|
||||||
|
context,
|
||||||
|
job::Job::new(
|
||||||
|
job::Action::MaybeSendLocationsEnded,
|
||||||
|
chat_id.to_u32(),
|
||||||
|
Params::new(),
|
||||||
|
seconds + 1,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn schedule_maybe_send_locations(context: &Context, force_schedule: bool) {
|
async fn schedule_maybe_send_locations(context: &Context, force_schedule: bool) {
|
||||||
@@ -255,25 +256,31 @@ async fn schedule_maybe_send_locations(context: &Context, force_schedule: bool)
|
|||||||
///
|
///
|
||||||
/// If `chat_id` is `Some` only that chat is checked, otherwise returns `true` if any chat
|
/// If `chat_id` is `Some` only that chat is checked, otherwise returns `true` if any chat
|
||||||
/// is sending locations.
|
/// is sending locations.
|
||||||
pub async fn is_sending_locations_to_chat(context: &Context, chat_id: Option<ChatId>) -> bool {
|
pub async fn is_sending_locations_to_chat(
|
||||||
match chat_id {
|
context: &Context,
|
||||||
Some(chat_id) => context
|
chat_id: Option<ChatId>,
|
||||||
.sql
|
) -> Result<bool> {
|
||||||
.exists(
|
let exists = match chat_id {
|
||||||
"SELECT COUNT(id) FROM chats WHERE id=? AND locations_send_until>?;",
|
Some(chat_id) => {
|
||||||
paramsv![chat_id, time()],
|
context
|
||||||
)
|
.sql
|
||||||
.await
|
.exists(
|
||||||
.unwrap_or_default(),
|
"SELECT COUNT(id) FROM chats WHERE id=? AND locations_send_until>?;",
|
||||||
None => context
|
paramsv![chat_id, time()],
|
||||||
.sql
|
)
|
||||||
.exists(
|
.await?
|
||||||
"SELECT COUNT(id) FROM chats WHERE locations_send_until>?;",
|
}
|
||||||
paramsv![time()],
|
None => {
|
||||||
)
|
context
|
||||||
.await
|
.sql
|
||||||
.unwrap_or_default(),
|
.exists(
|
||||||
}
|
"SELECT COUNT(id) FROM chats WHERE locations_send_until>?;",
|
||||||
|
paramsv![time()],
|
||||||
|
)
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(exists)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn set(context: &Context, latitude: f64, longitude: f64, accuracy: f64) -> bool {
|
pub async fn set(context: &Context, latitude: f64, longitude: f64, accuracy: f64) -> bool {
|
||||||
@@ -288,7 +295,11 @@ pub async fn set(context: &Context, latitude: f64, longitude: f64, accuracy: f64
|
|||||||
"SELECT id FROM chats WHERE locations_send_until>?;",
|
"SELECT id FROM chats WHERE locations_send_until>?;",
|
||||||
paramsv![time()],
|
paramsv![time()],
|
||||||
|row| row.get::<_, i32>(0),
|
|row| row.get::<_, i32>(0),
|
||||||
|chats| chats.collect::<Result<Vec<_>, _>>().map_err(Into::into),
|
|chats| {
|
||||||
|
chats
|
||||||
|
.collect::<std::result::Result<Vec<_>, _>>()
|
||||||
|
.map_err(Into::into)
|
||||||
|
},
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
@@ -325,7 +336,7 @@ pub async fn get_range(
|
|||||||
contact_id: Option<u32>,
|
contact_id: Option<u32>,
|
||||||
timestamp_from: i64,
|
timestamp_from: i64,
|
||||||
mut timestamp_to: i64,
|
mut timestamp_to: i64,
|
||||||
) -> Result<Vec<Location>, Error> {
|
) -> Result<Vec<Location>> {
|
||||||
if timestamp_to == 0 {
|
if timestamp_to == 0 {
|
||||||
timestamp_to = time() + 10;
|
timestamp_to = time() + 10;
|
||||||
}
|
}
|
||||||
@@ -400,7 +411,7 @@ fn is_marker(txt: &str) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Deletes all locations from the database.
|
/// Deletes all locations from the database.
|
||||||
pub async fn delete_all(context: &Context) -> Result<(), Error> {
|
pub async fn delete_all(context: &Context) -> Result<()> {
|
||||||
context
|
context
|
||||||
.sql
|
.sql
|
||||||
.execute("DELETE FROM locations;", paramsv![])
|
.execute("DELETE FROM locations;", paramsv![])
|
||||||
@@ -409,7 +420,7 @@ pub async fn delete_all(context: &Context) -> Result<(), Error> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_kml(context: &Context, chat_id: ChatId) -> Result<(String, u32), Error> {
|
pub async fn get_kml(context: &Context, chat_id: ChatId) -> Result<(String, u32)> {
|
||||||
let mut last_added_location_id = 0;
|
let mut last_added_location_id = 0;
|
||||||
|
|
||||||
let self_addr = context
|
let self_addr = context
|
||||||
@@ -517,7 +528,7 @@ pub async fn set_kml_sent_timestamp(
|
|||||||
context: &Context,
|
context: &Context,
|
||||||
chat_id: ChatId,
|
chat_id: ChatId,
|
||||||
timestamp: i64,
|
timestamp: i64,
|
||||||
) -> Result<(), Error> {
|
) -> Result<()> {
|
||||||
context
|
context
|
||||||
.sql
|
.sql
|
||||||
.execute(
|
.execute(
|
||||||
@@ -528,11 +539,7 @@ pub async fn set_kml_sent_timestamp(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn set_msg_location_id(
|
pub async fn set_msg_location_id(context: &Context, msg_id: MsgId, location_id: u32) -> Result<()> {
|
||||||
context: &Context,
|
|
||||||
msg_id: MsgId,
|
|
||||||
location_id: u32,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
context
|
context
|
||||||
.sql
|
.sql
|
||||||
.execute(
|
.execute(
|
||||||
@@ -550,7 +557,7 @@ pub async fn save(
|
|||||||
contact_id: u32,
|
contact_id: u32,
|
||||||
locations: &[Location],
|
locations: &[Location],
|
||||||
independent: bool,
|
independent: bool,
|
||||||
) -> Result<u32, Error> {
|
) -> Result<u32> {
|
||||||
ensure!(!chat_id.is_special(), "Invalid chat id");
|
ensure!(!chat_id.is_special(), "Invalid chat id");
|
||||||
|
|
||||||
let mut newest_timestamp = 0;
|
let mut newest_timestamp = 0;
|
||||||
@@ -630,7 +637,7 @@ pub(crate) async fn job_maybe_send_locations(context: &Context, _job: &Job) -> j
|
|||||||
},
|
},
|
||||||
|rows| {
|
|rows| {
|
||||||
rows.filter_map(|v| v.transpose())
|
rows.filter_map(|v| v.transpose())
|
||||||
.collect::<Result<Vec<_>, _>>()
|
.collect::<std::result::Result<Vec<_>, _>>()
|
||||||
.map_err(Into::into)
|
.map_err(Into::into)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
|
|
||||||
use anyhow::{ensure, format_err, Result};
|
use anyhow::{ensure, format_err, Context as _, Result};
|
||||||
use async_std::path::{Path, PathBuf};
|
use async_std::path::{Path, PathBuf};
|
||||||
use deltachat_derive::{FromSql, ToSql};
|
use deltachat_derive::{FromSql, ToSql};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
@@ -1366,16 +1366,16 @@ pub async fn get_mime_headers(context: &Context, msg_id: MsgId) -> Result<Vec<u8
|
|||||||
Ok(headers)
|
Ok(headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn delete_msgs(context: &Context, msg_ids: &[MsgId]) {
|
pub async fn delete_msgs(context: &Context, msg_ids: &[MsgId]) -> Result<()> {
|
||||||
for msg_id in msg_ids.iter() {
|
for msg_id in msg_ids.iter() {
|
||||||
if let Ok(msg) = Message::load_from_db(context, *msg_id).await {
|
let msg = Message::load_from_db(context, *msg_id).await?;
|
||||||
if msg.location_id > 0 {
|
if msg.location_id > 0 {
|
||||||
delete_poi_location(context, msg.location_id).await;
|
delete_poi_location(context, msg.location_id).await;
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Err(err) = msg_id.trash(context).await {
|
|
||||||
error!(context, "Unable to trash message {}: {}", msg_id, err);
|
|
||||||
}
|
}
|
||||||
|
msg_id
|
||||||
|
.trash(context)
|
||||||
|
.await
|
||||||
|
.with_context(|| format!("Unable to trash message {}", msg_id))?;
|
||||||
job::add(
|
job::add(
|
||||||
context,
|
context,
|
||||||
job::Job::new(Action::DeleteMsgOnImap, msg_id.to_u32(), Params::new(), 0),
|
job::Job::new(Action::DeleteMsgOnImap, msg_id.to_u32(), Params::new(), 0),
|
||||||
@@ -1388,13 +1388,14 @@ pub async fn delete_msgs(context: &Context, msg_ids: &[MsgId]) {
|
|||||||
chat_id: ChatId::new(0),
|
chat_id: ChatId::new(0),
|
||||||
msg_id: MsgId::new(0),
|
msg_id: MsgId::new(0),
|
||||||
});
|
});
|
||||||
job::kill_action(context, Action::Housekeeping).await;
|
job::kill_action(context, Action::Housekeeping).await?;
|
||||||
job::add(
|
job::add(
|
||||||
context,
|
context,
|
||||||
job::Job::new(Action::Housekeeping, 0, Params::new(), 10),
|
job::Job::new(Action::Housekeeping, 0, Params::new(), 10),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn delete_poi_location(context: &Context, location_id: u32) -> bool {
|
async fn delete_poi_location(context: &Context, location_id: u32) -> bool {
|
||||||
|
|||||||
@@ -1084,7 +1084,7 @@ impl<'a> MimeFactory<'a> {
|
|||||||
parts.push(msg_kml_part);
|
parts.push(msg_kml_part);
|
||||||
}
|
}
|
||||||
|
|
||||||
if location::is_sending_locations_to_chat(context, Some(self.msg.chat_id)).await {
|
if location::is_sending_locations_to_chat(context, Some(self.msg.chat_id)).await? {
|
||||||
match self.get_location_kml_part(context).await {
|
match self.get_location_kml_part(context).await {
|
||||||
Ok(part) => parts.push(part),
|
Ok(part) => parts.push(part),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|||||||
@@ -98,13 +98,14 @@ fn get_highest_usage<'t>(
|
|||||||
|
|
||||||
impl Context {
|
impl Context {
|
||||||
// Adds a job to update `quota.recent`
|
// Adds a job to update `quota.recent`
|
||||||
pub(crate) async fn schedule_quota_update(&self) {
|
pub(crate) async fn schedule_quota_update(&self) -> Result<()> {
|
||||||
job::kill_action(self, Action::UpdateRecentQuota).await;
|
job::kill_action(self, Action::UpdateRecentQuota).await?;
|
||||||
job::add(
|
job::add(
|
||||||
self,
|
self,
|
||||||
job::Job::new(Action::UpdateRecentQuota, 0, Params::new(), 0),
|
job::Job::new(Action::UpdateRecentQuota, 0, Params::new(), 0),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates `quota.recent`, sets `quota.modified` to the current time
|
/// Updates `quota.recent`, sets `quota.modified` to the current time
|
||||||
|
|||||||
@@ -82,7 +82,11 @@ async fn inbox_loop(ctx: Context, started: Sender<()>, inbox_handlers: ImapConne
|
|||||||
let mut jobs_loaded = 0;
|
let mut jobs_loaded = 0;
|
||||||
let mut info = InterruptInfo::default();
|
let mut info = InterruptInfo::default();
|
||||||
loop {
|
loop {
|
||||||
match job::load_next(&ctx, Thread::Imap, &info).await {
|
match job::load_next(&ctx, Thread::Imap, &info)
|
||||||
|
.await
|
||||||
|
.ok()
|
||||||
|
.flatten()
|
||||||
|
{
|
||||||
Some(job) if jobs_loaded <= 20 => {
|
Some(job) if jobs_loaded <= 20 => {
|
||||||
jobs_loaded += 1;
|
jobs_loaded += 1;
|
||||||
job::perform_job(&ctx, job::Connection::Inbox(&mut connection), job).await;
|
job::perform_job(&ctx, job::Connection::Inbox(&mut connection), job).await;
|
||||||
@@ -289,7 +293,11 @@ async fn smtp_loop(ctx: Context, started: Sender<()>, smtp_handlers: SmtpConnect
|
|||||||
|
|
||||||
let mut interrupt_info = Default::default();
|
let mut interrupt_info = Default::default();
|
||||||
loop {
|
loop {
|
||||||
match job::load_next(&ctx, Thread::Smtp, &interrupt_info).await {
|
match job::load_next(&ctx, Thread::Smtp, &interrupt_info)
|
||||||
|
.await
|
||||||
|
.ok()
|
||||||
|
.flatten()
|
||||||
|
{
|
||||||
Some(job) => {
|
Some(job) => {
|
||||||
info!(ctx, "executing smtp job");
|
info!(ctx, "executing smtp job");
|
||||||
job::perform_job(&ctx, job::Connection::Smtp(&mut connection), job).await;
|
job::perform_job(&ctx, job::Connection::Smtp(&mut connection), job).await;
|
||||||
|
|||||||
@@ -504,11 +504,11 @@ impl Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if quota.modified + QUOTA_MAX_AGE_SECONDS < time() {
|
if quota.modified + QUOTA_MAX_AGE_SECONDS < time() {
|
||||||
self.schedule_quota_update().await;
|
self.schedule_quota_update().await?;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ret += "<li>One moment...</li>";
|
ret += "<li>One moment...</li>";
|
||||||
self.schedule_quota_update().await;
|
self.schedule_quota_update().await?;
|
||||||
}
|
}
|
||||||
ret += "</ul>";
|
ret += "</ul>";
|
||||||
|
|
||||||
|
|||||||
@@ -635,7 +635,7 @@ pub(crate) async fn handle_securejoin_handshake(
|
|||||||
.await?;
|
.await?;
|
||||||
return Ok(HandshakeMessage::Ignore);
|
return Ok(HandshakeMessage::Ignore);
|
||||||
}
|
}
|
||||||
Contact::scaleup_origin_by_id(context, contact_id, Origin::SecurejoinInvited).await;
|
Contact::scaleup_origin_by_id(context, contact_id, Origin::SecurejoinInvited).await?;
|
||||||
info!(context, "Auth verified.",);
|
info!(context, "Auth verified.",);
|
||||||
secure_connection_established(context, contact_chat_id).await?;
|
secure_connection_established(context, contact_chat_id).await?;
|
||||||
emit_event!(context, EventType::ContactsChanged(Some(contact_id)));
|
emit_event!(context, EventType::ContactsChanged(Some(contact_id)));
|
||||||
|
|||||||
@@ -357,7 +357,7 @@ impl BobState {
|
|||||||
}
|
}
|
||||||
mark_peer_as_verified(context, self.invite.fingerprint()).await?;
|
mark_peer_as_verified(context, self.invite.fingerprint()).await?;
|
||||||
Contact::scaleup_origin_by_id(context, self.invite.contact_id(), Origin::SecurejoinJoined)
|
Contact::scaleup_origin_by_id(context, self.invite.contact_id(), Origin::SecurejoinJoined)
|
||||||
.await;
|
.await?;
|
||||||
emit_event!(context, EventType::ContactsChanged(None));
|
emit_event!(context, EventType::ContactsChanged(None));
|
||||||
|
|
||||||
if let QrInvite::Group { .. } = self.invite {
|
if let QrInvite::Group { .. } = self.invite {
|
||||||
|
|||||||
@@ -598,7 +598,7 @@ pub async fn housekeeping(context: &Context) -> Result<()> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
context.schedule_quota_update().await;
|
context.schedule_quota_update().await?;
|
||||||
|
|
||||||
if let Err(e) = context
|
if let Err(e) = context
|
||||||
.set_config(Config::LastHousekeeping, Some(&time().to_string()))
|
.set_config(Config::LastHousekeeping, Some(&time().to_string()))
|
||||||
|
|||||||
Reference in New Issue
Block a user