chat: use anyhow::Result to avoid repeating , Error>

This commit is contained in:
link2xt
2021-05-01 08:38:09 +03:00
parent 0ea6f72624
commit 60b4f3f21a
2 changed files with 75 additions and 132 deletions

View File

@@ -22,7 +22,7 @@
- improve tests #2360 #2362 #2370 #2377 - improve tests #2360 #2362 #2370 #2377
- cleanup #2359 #2361 #2374 #2376 #2379 - cleanup #2359 #2361 #2374 #2376 #2379 #2388
## 1.53.0 ## 1.53.0

View File

@@ -5,7 +5,7 @@ use std::str::FromStr;
use std::time::{Duration, SystemTime}; use std::time::{Duration, SystemTime};
use anyhow::Context as _; use anyhow::Context as _;
use anyhow::{bail, ensure, format_err, Error}; use anyhow::{bail, ensure, format_err, 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;
@@ -157,11 +157,7 @@ impl ChatId {
self == DC_CHAT_ID_ALLDONE_HINT self == DC_CHAT_ID_ALLDONE_HINT
} }
pub async fn set_selfavatar_timestamp( pub async fn set_selfavatar_timestamp(self, context: &Context, timestamp: i64) -> Result<()> {
self,
context: &Context,
timestamp: i64,
) -> Result<(), Error> {
context context
.sql .sql
.execute( .execute(
@@ -201,7 +197,7 @@ impl ChatId {
self, self,
context: &Context, context: &Context,
protect: ProtectionStatus, protect: ProtectionStatus,
) -> Result<(), Error> { ) -> Result<()> {
ensure!(!self.is_special(), "Invalid chat-id."); ensure!(!self.is_special(), "Invalid chat-id.");
let chat = Chat::load_from_db(context, self).await?; let chat = Chat::load_from_db(context, self).await?;
@@ -258,7 +254,7 @@ impl ChatId {
protect: ProtectionStatus, protect: ProtectionStatus,
promote: bool, promote: bool,
from_id: u32, from_id: u32,
) -> Result<(), Error> { ) -> Result<()> {
let msg_text = context.stock_protection_msg(protect, from_id).await; let msg_text = context.stock_protection_msg(protect, from_id).await;
let cmd = match protect { let cmd = match protect {
ProtectionStatus::Protected => SystemMessage::ChatProtectionEnabled, ProtectionStatus::Protected => SystemMessage::ChatProtectionEnabled,
@@ -281,11 +277,7 @@ impl ChatId {
} }
/// Sets protection and sends or adds a message. /// Sets protection and sends or adds a message.
pub async fn set_protection( pub async fn set_protection(self, context: &Context, protect: ProtectionStatus) -> Result<()> {
self,
context: &Context,
protect: ProtectionStatus,
) -> Result<(), Error> {
ensure!(!self.is_special(), "set protection: invalid chat-id."); ensure!(!self.is_special(), "set protection: invalid chat-id.");
let chat = Chat::load_from_db(context, self).await?; let chat = Chat::load_from_db(context, self).await?;
@@ -300,11 +292,7 @@ impl ChatId {
} }
/// Archives or unarchives a chat. /// Archives or unarchives a chat.
pub async fn set_visibility( pub async fn set_visibility(self, context: &Context, visibility: ChatVisibility) -> Result<()> {
self,
context: &Context,
visibility: ChatVisibility,
) -> Result<(), Error> {
ensure!( ensure!(
!self.is_special(), !self.is_special(),
"bad chat_id, can not be special chat: {}", "bad chat_id, can not be special chat: {}",
@@ -339,7 +327,7 @@ impl ChatId {
// note that unarchive() is not the same as set_visibility(Normal) - // note that unarchive() is not the same as set_visibility(Normal) -
// eg. unarchive() does not modify pinned chats and does not send events. // eg. unarchive() does not modify pinned chats and does not send events.
pub async fn unarchive(self, context: &Context) -> Result<(), Error> { pub async fn unarchive(self, context: &Context) -> Result<()> {
context context
.sql .sql
.execute( .execute(
@@ -351,7 +339,7 @@ impl ChatId {
} }
/// Deletes a chat. /// Deletes a chat.
pub async fn delete(self, context: &Context) -> Result<(), Error> { pub async fn delete(self, context: &Context) -> Result<()> {
ensure!( ensure!(
!self.is_special(), !self.is_special(),
"bad chat_id, can not be a special chat: {}", "bad chat_id, can not be a special chat: {}",
@@ -407,11 +395,7 @@ impl ChatId {
/// Sets draft message. /// Sets draft message.
/// ///
/// Passing `None` as message just deletes the draft /// Passing `None` as message just deletes the draft
pub async fn set_draft( pub async fn set_draft(self, context: &Context, msg: Option<&mut Message>) -> Result<()> {
self,
context: &Context,
msg: Option<&mut Message>,
) -> Result<(), Error> {
if self.is_special() { if self.is_special() {
return Ok(()); return Ok(());
} }
@@ -432,7 +416,7 @@ impl ChatId {
} }
/// Similar to as dc_set_draft() but does not emit an event /// Similar to as dc_set_draft() but does not emit an event
async fn set_draft_raw(self, context: &Context, msg: &mut Message) -> Result<bool, Error> { async fn set_draft_raw(self, context: &Context, msg: &mut Message) -> Result<bool> {
let deleted = self.maybe_delete_draft(context).await?; let deleted = self.maybe_delete_draft(context).await?;
let set = self.do_set_draft(context, msg).await.is_ok(); let set = self.do_set_draft(context, msg).await.is_ok();
@@ -440,7 +424,7 @@ impl ChatId {
Ok(deleted || set) Ok(deleted || set)
} }
async fn get_draft_msg_id(self, context: &Context) -> Result<Option<MsgId>, Error> { async fn get_draft_msg_id(self, context: &Context) -> Result<Option<MsgId>> {
let msg_id: Option<MsgId> = context let msg_id: Option<MsgId> = context
.sql .sql
.query_get_value( .query_get_value(
@@ -451,7 +435,7 @@ impl ChatId {
Ok(msg_id) Ok(msg_id)
} }
pub async fn get_draft(self, context: &Context) -> Result<Option<Message>, Error> { pub async fn get_draft(self, context: &Context) -> Result<Option<Message>> {
if self.is_special() { if self.is_special() {
return Ok(None); return Ok(None);
} }
@@ -467,7 +451,7 @@ impl ChatId {
/// Delete draft message in specified chat, if there is one. /// Delete draft message in specified chat, if there is one.
/// ///
/// Returns `true`, if message was deleted, `false` otherwise. /// Returns `true`, if message was deleted, `false` otherwise.
async fn maybe_delete_draft(self, context: &Context) -> Result<bool, Error> { async fn maybe_delete_draft(self, context: &Context) -> Result<bool> {
match self.get_draft_msg_id(context).await? { match self.get_draft_msg_id(context).await? {
Some(msg_id) => Ok(msg_id.delete_from_db(context).await.is_ok()), Some(msg_id) => Ok(msg_id.delete_from_db(context).await.is_ok()),
None => Ok(false), None => Ok(false),
@@ -477,7 +461,7 @@ impl ChatId {
/// Set provided message as draft message for specified chat. /// Set provided message as draft message for specified chat.
/// ///
/// Return true on success, false on database error. /// Return true on success, false on database error.
async fn do_set_draft(self, context: &Context, msg: &mut Message) -> Result<(), Error> { async fn do_set_draft(self, context: &Context, msg: &mut Message) -> Result<()> {
match msg.viewtype { match msg.viewtype {
Viewtype::Unknown => bail!("Can not set draft of unknown type."), Viewtype::Unknown => bail!("Can not set draft of unknown type."),
Viewtype::Text => { Viewtype::Text => {
@@ -531,7 +515,7 @@ impl ChatId {
} }
/// Returns number of messages in a chat. /// Returns number of messages in a chat.
pub async fn get_msg_cnt(self, context: &Context) -> Result<usize, Error> { pub async fn get_msg_cnt(self, context: &Context) -> Result<usize> {
let count = context let count = context
.sql .sql
.count("SELECT COUNT(*) FROM msgs WHERE chat_id=?", paramsv![self]) .count("SELECT COUNT(*) FROM msgs WHERE chat_id=?", paramsv![self])
@@ -539,7 +523,7 @@ impl ChatId {
Ok(count as usize) Ok(count as usize)
} }
pub async fn get_fresh_msg_cnt(self, context: &Context) -> Result<usize, Error> { pub async fn get_fresh_msg_cnt(self, context: &Context) -> Result<usize> {
// this function is typically used to show a badge counter beside _each_ chatlist item. // this function is typically used to show a badge counter beside _each_ chatlist item.
// to make this as fast as possible, esp. on older devices, we added an combined index over the rows used for querying. // to make this as fast as possible, esp. on older devices, we added an combined index over the rows used for querying.
// so if you alter the query here, you may want to alter the index over `(state, hidden, chat_id)` in `sql.rs`. // so if you alter the query here, you may want to alter the index over `(state, hidden, chat_id)` in `sql.rs`.
@@ -564,7 +548,7 @@ impl ChatId {
Ok(count as usize) Ok(count as usize)
} }
pub(crate) async fn get_param(self, context: &Context) -> Result<Params, Error> { pub(crate) async fn get_param(self, context: &Context) -> Result<Params> {
let res: Option<String> = context let res: Option<String> = context
.sql .sql
.query_get_value("SELECT param FROM chats WHERE id=?", paramsv![self]) .query_get_value("SELECT param FROM chats WHERE id=?", paramsv![self])
@@ -575,21 +559,16 @@ impl ChatId {
} }
// Returns true if chat is a saved messages chat. // Returns true if chat is a saved messages chat.
pub async fn is_self_talk(self, context: &Context) -> Result<bool, Error> { pub async fn is_self_talk(self, context: &Context) -> Result<bool> {
Ok(self.get_param(context).await?.exists(Param::Selftalk)) Ok(self.get_param(context).await?.exists(Param::Selftalk))
} }
/// Returns true if chat is a device chat. /// Returns true if chat is a device chat.
pub async fn is_device_talk(self, context: &Context) -> Result<bool, Error> { pub async fn is_device_talk(self, context: &Context) -> Result<bool> {
Ok(self.get_param(context).await?.exists(Param::Devicetalk)) Ok(self.get_param(context).await?.exists(Param::Devicetalk))
} }
async fn parent_query<T, F>( async fn parent_query<T, F>(self, context: &Context, fields: &str, f: F) -> Result<Option<T>>
self,
context: &Context,
fields: &str,
f: F,
) -> anyhow::Result<Option<T>>
where where
F: FnOnce(&rusqlite::Row) -> rusqlite::Result<T>, F: FnOnce(&rusqlite::Row) -> rusqlite::Result<T>,
{ {
@@ -658,7 +637,7 @@ impl ChatId {
/// prefer plaintext emails. /// prefer plaintext emails.
/// ///
/// To get more verbose summary for a contact, including its key fingerprint, use [`Contact::get_encrinfo`]. /// To get more verbose summary for a contact, including its key fingerprint, use [`Contact::get_encrinfo`].
pub async fn get_encryption_info(self, context: &Context) -> Result<String, Error> { pub async fn get_encryption_info(self, context: &Context) -> Result<String> {
let mut ret = String::new(); let mut ret = String::new();
for contact_id in get_chat_contacts(context, self) for contact_id in get_chat_contacts(context, self)
@@ -764,7 +743,7 @@ pub struct Chat {
impl Chat { impl Chat {
/// Loads chat from the database by its ID. /// Loads chat from the database by its ID.
pub async fn load_from_db(context: &Context, chat_id: ChatId) -> Result<Self, Error> { pub async fn load_from_db(context: &Context, chat_id: ChatId) -> Result<Self> {
let mut chat = context let mut chat = context
.sql .sql
.query_row( .query_row(
@@ -789,7 +768,8 @@ impl Chat {
Ok(c) Ok(c)
}, },
) )
.await?; .await
.context(format!("Failed loading chat {} from database", chat_id))?;
if chat.id.is_deaddrop() { if chat.id.is_deaddrop() {
chat.name = stock_str::dead_drop(context).await; chat.name = stock_str::dead_drop(context).await;
@@ -842,7 +822,7 @@ impl Chat {
!self.id.is_special() && !self.is_device_talk() && !self.is_mailing_list() !self.id.is_special() && !self.is_device_talk() && !self.is_mailing_list()
} }
pub async fn update_param(&mut self, context: &Context) -> Result<(), Error> { pub async fn update_param(&mut self, context: &Context) -> Result<()> {
context context
.sql .sql
.execute( .execute(
@@ -868,7 +848,7 @@ impl Chat {
&self.name &self.name
} }
pub async fn get_profile_image(&self, context: &Context) -> Result<Option<PathBuf>, Error> { pub async fn get_profile_image(&self, context: &Context) -> Result<Option<PathBuf>> {
if let Some(image_rel) = self.param.get(Param::ProfileImage) { if let Some(image_rel) = self.param.get(Param::ProfileImage) {
if !image_rel.is_empty() { if !image_rel.is_empty() {
return Ok(Some(dc_get_abs_path(context, image_rel))); return Ok(Some(dc_get_abs_path(context, image_rel)));
@@ -885,11 +865,11 @@ impl Chat {
Ok(None) Ok(None)
} }
pub async fn get_gossiped_timestamp(&self, context: &Context) -> Result<i64, Error> { pub async fn get_gossiped_timestamp(&self, context: &Context) -> Result<i64> {
get_gossiped_timestamp(context, self.id).await get_gossiped_timestamp(context, self.id).await
} }
pub async fn get_color(&self, context: &Context) -> Result<u32, Error> { pub async fn get_color(&self, context: &Context) -> Result<u32> {
let mut color = 0; let mut color = 0;
if self.typ == Chattype::Single { if self.typ == Chattype::Single {
@@ -910,7 +890,7 @@ impl Chat {
/// ///
/// This is somewhat experimental, even more so than the rest of /// This is somewhat experimental, even more so than the rest of
/// deltachat, and the data returned is still subject to change. /// deltachat, and the data returned is still subject to change.
pub async fn get_info(&self, context: &Context) -> Result<ChatInfo, Error> { pub async fn get_info(&self, context: &Context) -> Result<ChatInfo> {
let draft = match self.id.get_draft(context).await? { let draft = match self.id.get_draft(context).await? {
Some(message) => message.text.unwrap_or_else(String::new), Some(message) => message.text.unwrap_or_else(String::new),
_ => String::new(), _ => String::new(),
@@ -970,7 +950,7 @@ impl Chat {
context: &Context, context: &Context,
msg: &mut Message, msg: &mut Message,
timestamp: i64, timestamp: i64,
) -> Result<MsgId, Error> { ) -> Result<MsgId> {
let mut new_references = "".into(); let mut new_references = "".into();
let mut to_id = 0; let mut to_id = 0;
let mut location_id = 0; let mut location_id = 0;
@@ -1301,7 +1281,7 @@ pub struct ChatInfo {
/// # Returns /// # Returns
/// ///
/// The "created" chat ID is returned. /// The "created" chat ID is returned.
pub async fn create_by_msg_id(context: &Context, msg_id: MsgId) -> Result<ChatId, Error> { pub async fn create_by_msg_id(context: &Context, msg_id: MsgId) -> Result<ChatId> {
let msg = Message::load_from_db(context, msg_id).await?; let msg = Message::load_from_db(context, msg_id).await?;
let chat = Chat::load_from_db(context, msg.chat_id).await?; let chat = Chat::load_from_db(context, msg.chat_id).await?;
ensure!( ensure!(
@@ -1332,7 +1312,7 @@ pub async fn create_by_msg_id(context: &Context, msg_id: MsgId) -> Result<ChatId
/// If a chat already exists, this ID is returned, otherwise a new chat is created; /// If a chat already exists, this ID is returned, otherwise a new chat is created;
/// this new chat may already contain messages, eg. from the deaddrop, to get the /// this new chat may already contain messages, eg. from the deaddrop, to get the
/// chat messages, use dc_get_chat_msgs(). /// chat messages, use dc_get_chat_msgs().
pub async fn create_by_contact_id(context: &Context, contact_id: u32) -> Result<ChatId, Error> { pub async fn create_by_contact_id(context: &Context, contact_id: u32) -> Result<ChatId> {
let chat_id = match lookup_by_contact_id(context, contact_id).await { let chat_id = match lookup_by_contact_id(context, contact_id).await {
Ok((chat_id, chat_blocked)) => { Ok((chat_id, chat_blocked)) => {
if chat_blocked != Blocked::Not { if chat_blocked != Blocked::Not {
@@ -1367,7 +1347,7 @@ pub async fn create_by_contact_id(context: &Context, contact_id: u32) -> Result<
Ok(chat_id) Ok(chat_id)
} }
pub(crate) async fn update_saved_messages_icon(context: &Context) -> Result<(), Error> { pub(crate) async fn update_saved_messages_icon(context: &Context) -> Result<()> {
// if there is no saved-messages chat, there is nothing to update. this is no error. // if there is no saved-messages chat, there is nothing to update. this is no error.
if let Ok((chat_id, _)) = lookup_by_contact_id(context, DC_CONTACT_ID_SELF).await { if let Ok((chat_id, _)) = lookup_by_contact_id(context, DC_CONTACT_ID_SELF).await {
let icon = include_bytes!("../assets/icon-saved-messages.png"); let icon = include_bytes!("../assets/icon-saved-messages.png");
@@ -1381,7 +1361,7 @@ pub(crate) async fn update_saved_messages_icon(context: &Context) -> Result<(),
Ok(()) Ok(())
} }
pub(crate) async fn update_device_icon(context: &Context) -> Result<(), Error> { pub(crate) async fn update_device_icon(context: &Context) -> Result<()> {
// if there is no device-chat, there is nothing to update. this is no error. // if there is no device-chat, there is nothing to update. this is no error.
if let Ok((chat_id, _)) = lookup_by_contact_id(context, DC_CONTACT_ID_DEVICE).await { if let Ok((chat_id, _)) = lookup_by_contact_id(context, DC_CONTACT_ID_DEVICE).await {
let icon = include_bytes!("../assets/icon-device.png"); let icon = include_bytes!("../assets/icon-device.png");
@@ -1399,11 +1379,7 @@ pub(crate) async fn update_device_icon(context: &Context) -> Result<(), Error> {
Ok(()) Ok(())
} }
async fn update_special_chat_name( async fn update_special_chat_name(context: &Context, contact_id: u32, name: String) -> Result<()> {
context: &Context,
contact_id: u32,
name: String,
) -> Result<(), Error> {
if let Ok((chat_id, _)) = lookup_by_contact_id(context, contact_id).await { if let Ok((chat_id, _)) = lookup_by_contact_id(context, contact_id).await {
// the `!= name` condition avoids unneeded writes // the `!= name` condition avoids unneeded writes
context context
@@ -1417,7 +1393,7 @@ async fn update_special_chat_name(
Ok(()) Ok(())
} }
pub(crate) async fn update_special_chat_names(context: &Context) -> Result<(), Error> { pub(crate) async fn update_special_chat_names(context: &Context) -> Result<()> {
update_special_chat_name( update_special_chat_name(
context, context,
DC_CONTACT_ID_DEVICE, DC_CONTACT_ID_DEVICE,
@@ -1437,7 +1413,7 @@ pub(crate) async fn create_or_lookup_by_contact_id(
context: &Context, context: &Context,
contact_id: u32, contact_id: u32,
create_blocked: Blocked, create_blocked: Blocked,
) -> Result<(ChatId, Blocked), Error> { ) -> Result<(ChatId, Blocked)> {
ensure!(context.sql.is_open().await, "Database not available"); ensure!(context.sql.is_open().await, "Database not available");
ensure!(contact_id > 0, "Invalid contact id requested"); ensure!(contact_id > 0, "Invalid contact id requested");
@@ -1492,7 +1468,7 @@ pub(crate) async fn create_or_lookup_by_contact_id(
pub(crate) async fn lookup_by_contact_id( pub(crate) async fn lookup_by_contact_id(
context: &Context, context: &Context,
contact_id: u32, contact_id: u32,
) -> Result<(ChatId, Blocked), Error> { ) -> Result<(ChatId, Blocked)> {
ensure!(context.sql.is_open().await, "Database not available"); ensure!(context.sql.is_open().await, "Database not available");
let row = context let row = context
@@ -1517,18 +1493,14 @@ pub(crate) async fn lookup_by_contact_id(
Ok(row) Ok(row)
} }
pub async fn get_by_contact_id(context: &Context, contact_id: u32) -> Result<ChatId, Error> { pub async fn get_by_contact_id(context: &Context, contact_id: u32) -> Result<ChatId> {
let (chat_id, blocked) = lookup_by_contact_id(context, contact_id).await?; let (chat_id, blocked) = lookup_by_contact_id(context, contact_id).await?;
ensure_eq!(blocked, Blocked::Not, "Requested contact is blocked"); ensure_eq!(blocked, Blocked::Not, "Requested contact is blocked");
Ok(chat_id) Ok(chat_id)
} }
pub async fn prepare_msg( pub async fn prepare_msg(context: &Context, chat_id: ChatId, msg: &mut Message) -> Result<MsgId> {
context: &Context,
chat_id: ChatId,
msg: &mut Message,
) -> Result<MsgId, Error> {
ensure!( ensure!(
!chat_id.is_special(), !chat_id.is_special(),
"Cannot prepare message for special chat" "Cannot prepare message for special chat"
@@ -1559,7 +1531,7 @@ pub(crate) fn msgtype_has_file(msgtype: Viewtype) -> bool {
} }
} }
async fn prepare_msg_blob(context: &Context, msg: &mut Message) -> Result<(), Error> { async fn prepare_msg_blob(context: &Context, msg: &mut Message) -> Result<()> {
if msg.viewtype == Viewtype::Text || msg.viewtype == Viewtype::VideochatInvitation { if msg.viewtype == Viewtype::Text || msg.viewtype == Viewtype::VideochatInvitation {
// the caller should check if the message text is empty // the caller should check if the message text is empty
} else if msgtype_has_file(msg.viewtype) { } else if msgtype_has_file(msg.viewtype) {
@@ -1614,7 +1586,7 @@ async fn prepare_msg_common(
context: &Context, context: &Context,
chat_id: ChatId, chat_id: ChatId,
msg: &mut Message, msg: &mut Message,
) -> Result<MsgId, Error> { ) -> Result<MsgId> {
msg.id = MsgId::new_unset(); msg.id = MsgId::new_unset();
prepare_msg_blob(context, msg).await?; prepare_msg_blob(context, msg).await?;
chat_id.unarchive(context).await?; chat_id.unarchive(context).await?;
@@ -1664,11 +1636,7 @@ pub async fn is_contact_in_chat(context: &Context, chat_id: ChatId, contact_id:
// TODO: Do not allow ChatId to be 0, if prepare_msg had been called // TODO: Do not allow ChatId to be 0, if prepare_msg had been called
// the caller can get it from msg.chat_id. Forwards would need to // the caller can get it from msg.chat_id. Forwards would need to
// be fixed for this somehow too. // be fixed for this somehow too.
pub async fn send_msg( pub async fn send_msg(context: &Context, chat_id: ChatId, msg: &mut Message) -> Result<MsgId> {
context: &Context,
chat_id: ChatId,
msg: &mut Message,
) -> Result<MsgId, Error> {
if chat_id.is_unset() { if chat_id.is_unset() {
let forwards = msg.param.get(Param::PrepForwards); let forwards = msg.param.get(Param::PrepForwards);
if let Some(forwards) = forwards { if let Some(forwards) = forwards {
@@ -1697,11 +1665,7 @@ pub async fn send_msg(
/// Directly opens an smtp /// Directly opens an smtp
/// connection and sends the message, bypassing the job system. If this fails, it writes a send job to /// connection and sends the message, bypassing the job system. If this fails, it writes a send job to
/// the database. /// the database.
pub async fn send_msg_sync( pub async fn send_msg_sync(context: &Context, chat_id: ChatId, msg: &mut Message) -> Result<MsgId> {
context: &Context,
chat_id: ChatId,
msg: &mut Message,
) -> Result<MsgId, Error> {
if let Some(mut job) = prepare_send_msg(context, chat_id, msg).await? { if let Some(mut job) = prepare_send_msg(context, chat_id, msg).await? {
let mut smtp = crate::smtp::Smtp::new(); let mut smtp = crate::smtp::Smtp::new();
@@ -1729,11 +1693,7 @@ pub async fn send_msg_sync(
} }
} }
async fn send_msg_inner( async fn send_msg_inner(context: &Context, chat_id: ChatId, msg: &mut Message) -> Result<MsgId> {
context: &Context,
chat_id: ChatId,
msg: &mut Message,
) -> Result<MsgId, Error> {
if let Some(send_job) = prepare_send_msg(context, chat_id, msg).await? { if let Some(send_job) = prepare_send_msg(context, chat_id, msg).await? {
job::add(context, send_job).await; job::add(context, send_job).await;
@@ -1754,7 +1714,7 @@ async fn prepare_send_msg(
context: &Context, context: &Context,
chat_id: ChatId, chat_id: ChatId,
msg: &mut Message, msg: &mut Message,
) -> Result<Option<crate::job::Job>, Error> { ) -> Result<Option<crate::job::Job>> {
// dc_prepare_msg() leaves the message state to OutPreparing, we // dc_prepare_msg() leaves the message state to OutPreparing, we
// only have to change the state to OutPending in this case. // only have to change the state to OutPending in this case.
// Otherwise we still have to prepare the message, which will set // Otherwise we still have to prepare the message, which will set
@@ -1779,7 +1739,7 @@ pub async fn send_text_msg(
context: &Context, context: &Context,
chat_id: ChatId, chat_id: ChatId,
text_to_send: String, text_to_send: String,
) -> Result<MsgId, Error> { ) -> Result<MsgId> {
ensure!( ensure!(
!chat_id.is_special(), !chat_id.is_special(),
"bad chat_id, can not be a special chat: {}", "bad chat_id, can not be a special chat: {}",
@@ -1791,7 +1751,7 @@ pub async fn send_text_msg(
send_msg(context, chat_id, &mut msg).await send_msg(context, chat_id, &mut msg).await
} }
pub async fn send_videochat_invitation(context: &Context, chat_id: ChatId) -> Result<MsgId, Error> { pub async fn send_videochat_invitation(context: &Context, chat_id: ChatId) -> Result<MsgId> {
ensure!( ensure!(
!chat_id.is_special(), !chat_id.is_special(),
"video chat invitation cannot be sent to special chat: {}", "video chat invitation cannot be sent to special chat: {}",
@@ -1824,7 +1784,7 @@ pub async fn get_chat_msgs(
chat_id: ChatId, chat_id: ChatId,
flags: u32, flags: u32,
marker1before: Option<MsgId>, marker1before: Option<MsgId>,
) -> Result<Vec<ChatItem>, Error> { ) -> Result<Vec<ChatItem>> {
match delete_expired_messages(context).await { match delete_expired_messages(context).await {
Err(err) => warn!(context, "Failed to delete expired messages: {}", err), Err(err) => warn!(context, "Failed to delete expired messages: {}", err),
Ok(messages_deleted) => { Ok(messages_deleted) => {
@@ -1970,7 +1930,7 @@ pub(crate) async fn marknoticed_chat_if_older_than(
context: &Context, context: &Context,
chat_id: ChatId, chat_id: ChatId,
timestamp: i64, timestamp: i64,
) -> Result<(), Error> { ) -> Result<()> {
if let Some(chat_timestamp) = context if let Some(chat_timestamp) = context
.sql .sql
.query_get_value( .query_get_value(
@@ -1986,7 +1946,7 @@ pub(crate) async fn marknoticed_chat_if_older_than(
Ok(()) Ok(())
} }
pub async fn marknoticed_chat(context: &Context, chat_id: ChatId) -> Result<(), Error> { pub async fn marknoticed_chat(context: &Context, chat_id: ChatId) -> Result<()> {
// for the virtual deaddrop chat-id, // for the virtual deaddrop chat-id,
// mark all messages that will appear in the deaddrop as noticed // mark all messages that will appear in the deaddrop as noticed
if chat_id.is_deaddrop() { if chat_id.is_deaddrop() {
@@ -2048,7 +2008,7 @@ pub async fn get_chat_media(
msg_type: Viewtype, msg_type: Viewtype,
msg_type2: Viewtype, msg_type2: Viewtype,
msg_type3: Viewtype, msg_type3: Viewtype,
) -> Result<Vec<MsgId>, Error> { ) -> Result<Vec<MsgId>> {
// TODO This query could/should be converted to `AND type IN (?, ?, ?)`. // TODO This query could/should be converted to `AND type IN (?, ?, ?)`.
let list = context let list = context
.sql .sql
@@ -2102,7 +2062,7 @@ pub async fn get_next_media(
msg_type: Viewtype, msg_type: Viewtype,
msg_type2: Viewtype, msg_type2: Viewtype,
msg_type3: Viewtype, msg_type3: Viewtype,
) -> Result<Option<MsgId>, Error> { ) -> Result<Option<MsgId>> {
let mut ret: Option<MsgId> = None; let mut ret: Option<MsgId> = None;
if let Ok(msg) = Message::load_from_db(context, curr_msg_id).await { if let Ok(msg) = Message::load_from_db(context, curr_msg_id).await {
@@ -2139,7 +2099,7 @@ pub async fn get_next_media(
Ok(ret) Ok(ret)
} }
pub async fn get_chat_contacts(context: &Context, chat_id: ChatId) -> Result<Vec<u32>, Error> { pub async fn get_chat_contacts(context: &Context, chat_id: ChatId) -> Result<Vec<u32>> {
// Normal chats do not include SELF. Group chats do (as it may happen that one is deleted from a // Normal chats do not include SELF. Group chats do (as it may happen that one is deleted from a
// groupchat but the chats stays visible, moreover, this makes displaying lists easier) // groupchat but the chats stays visible, moreover, this makes displaying lists easier)
@@ -2172,7 +2132,7 @@ pub async fn create_group_chat(
context: &Context, context: &Context,
protect: ProtectionStatus, protect: ProtectionStatus,
chat_name: impl AsRef<str>, chat_name: impl AsRef<str>,
) -> Result<ChatId, Error> { ) -> Result<ChatId> {
let chat_name = improve_single_line_input(chat_name); let chat_name = improve_single_line_input(chat_name);
ensure!(!chat_name.is_empty(), "Invalid chat name"); ensure!(!chat_name.is_empty(), "Invalid chat name");
@@ -2278,7 +2238,7 @@ pub(crate) async fn add_contact_to_chat_ex(
chat_id: ChatId, chat_id: ChatId,
contact_id: u32, contact_id: u32,
from_handshake: bool, from_handshake: bool,
) -> Result<bool, Error> { ) -> Result<bool> {
ensure!(!chat_id.is_special(), "can not add member to special chats"); ensure!(!chat_id.is_special(), "can not add member to special chats");
let contact = Contact::get_by_id(context, contact_id).await?; let contact = Contact::get_by_id(context, contact_id).await?;
let mut msg = Message::default(); let mut msg = Message::default();
@@ -2361,16 +2321,13 @@ pub(crate) async fn add_contact_to_chat_ex(
Ok(true) Ok(true)
} }
pub(crate) async fn reset_gossiped_timestamp( pub(crate) async fn reset_gossiped_timestamp(context: &Context, chat_id: ChatId) -> Result<()> {
context: &Context,
chat_id: ChatId,
) -> Result<(), Error> {
set_gossiped_timestamp(context, chat_id, 0).await set_gossiped_timestamp(context, chat_id, 0).await
} }
/// Get timestamp of the last gossip sent in the chat. /// Get timestamp of the last gossip sent in the chat.
/// Zero return value means that gossip was never sent. /// Zero return value means that gossip was never sent.
pub async fn get_gossiped_timestamp(context: &Context, chat_id: ChatId) -> Result<i64, Error> { pub async fn get_gossiped_timestamp(context: &Context, chat_id: ChatId) -> Result<i64> {
let timestamp: Option<i64> = context let timestamp: Option<i64> = context
.sql .sql
.query_get_value( .query_get_value(
@@ -2385,7 +2342,7 @@ pub(crate) async fn set_gossiped_timestamp(
context: &Context, context: &Context,
chat_id: ChatId, chat_id: ChatId,
timestamp: i64, timestamp: i64,
) -> Result<(), Error> { ) -> Result<()> {
ensure!(!chat_id.is_special(), "can not add member to special chats"); ensure!(!chat_id.is_special(), "can not add member to special chats");
info!( info!(
context, context,
@@ -2403,10 +2360,7 @@ pub(crate) async fn set_gossiped_timestamp(
Ok(()) Ok(())
} }
pub(crate) async fn shall_attach_selfavatar( pub(crate) async fn shall_attach_selfavatar(context: &Context, chat_id: ChatId) -> Result<bool> {
context: &Context,
chat_id: ChatId,
) -> Result<bool, Error> {
// versions before 12/2019 already allowed to set selfavatar, however, it was never sent to others. // versions before 12/2019 already allowed to set selfavatar, however, it was never sent to others.
// to avoid sending out previously set selfavatars unexpectedly we added this additional check. // to avoid sending out previously set selfavatars unexpectedly we added this additional check.
// it can be removed after some time. // it can be removed after some time.
@@ -2482,11 +2436,7 @@ impl rusqlite::types::FromSql for MuteDuration {
} }
} }
pub async fn set_muted( pub async fn set_muted(context: &Context, chat_id: ChatId, duration: MuteDuration) -> Result<()> {
context: &Context,
chat_id: ChatId,
duration: MuteDuration,
) -> Result<(), Error> {
ensure!(!chat_id.is_special(), "Invalid chat ID"); ensure!(!chat_id.is_special(), "Invalid chat ID");
if context if context
.sql .sql
@@ -2508,7 +2458,7 @@ pub async fn remove_contact_from_chat(
context: &Context, context: &Context,
chat_id: ChatId, chat_id: ChatId,
contact_id: u32, contact_id: u32,
) -> Result<(), Error> { ) -> Result<()> {
ensure!( ensure!(
!chat_id.is_special(), !chat_id.is_special(),
"bad chat_id, can not be special chat: {}", "bad chat_id, can not be special chat: {}",
@@ -2580,7 +2530,7 @@ pub async fn remove_contact_from_chat(
Ok(()) Ok(())
} }
async fn set_group_explicitly_left(context: &Context, grpid: impl AsRef<str>) -> Result<(), Error> { async fn set_group_explicitly_left(context: &Context, grpid: impl AsRef<str>) -> Result<()> {
if !is_group_explicitly_left(context, grpid.as_ref()).await? { if !is_group_explicitly_left(context, grpid.as_ref()).await? {
context context
.sql .sql
@@ -2597,7 +2547,7 @@ async fn set_group_explicitly_left(context: &Context, grpid: impl AsRef<str>) ->
pub(crate) async fn is_group_explicitly_left( pub(crate) async fn is_group_explicitly_left(
context: &Context, context: &Context,
grpid: impl AsRef<str>, grpid: impl AsRef<str>,
) -> Result<bool, Error> { ) -> Result<bool> {
let exists = context let exists = context
.sql .sql
.exists( .exists(
@@ -2612,7 +2562,7 @@ pub async fn set_chat_name(
context: &Context, context: &Context,
chat_id: ChatId, chat_id: ChatId,
new_name: impl AsRef<str>, new_name: impl AsRef<str>,
) -> Result<(), Error> { ) -> Result<()> {
let new_name = improve_single_line_input(new_name); let new_name = improve_single_line_input(new_name);
/* the function only sets the names of group chats; normal chats get their names from the contacts */ /* the function only sets the names of group chats; normal chats get their names from the contacts */
let mut success = false; let mut success = false;
@@ -2685,7 +2635,7 @@ pub async fn set_chat_profile_image(
context: &Context, context: &Context,
chat_id: ChatId, chat_id: ChatId,
new_image: impl AsRef<str>, // XXX use PathBuf new_image: impl AsRef<str>, // XXX use PathBuf
) -> Result<(), Error> { ) -> Result<()> {
ensure!(!chat_id.is_special(), "Invalid chat ID"); ensure!(!chat_id.is_special(), "Invalid chat ID");
let mut chat = Chat::load_from_db(context, chat_id).await?; let mut chat = Chat::load_from_db(context, chat_id).await?;
ensure!( ensure!(
@@ -2739,11 +2689,7 @@ pub async fn set_chat_profile_image(
Ok(()) Ok(())
} }
pub async fn forward_msgs( pub async fn forward_msgs(context: &Context, msg_ids: &[MsgId], chat_id: ChatId) -> Result<()> {
context: &Context,
msg_ids: &[MsgId],
chat_id: ChatId,
) -> Result<(), Error> {
ensure!(!msg_ids.is_empty(), "empty msgs_ids: nothing to forward"); ensure!(!msg_ids.is_empty(), "empty msgs_ids: nothing to forward");
ensure!(!chat_id.is_special(), "can not forward to special chat"); ensure!(!chat_id.is_special(), "can not forward to special chat");
@@ -2831,10 +2777,7 @@ pub async fn forward_msgs(
Ok(()) Ok(())
} }
pub(crate) async fn get_chat_contact_cnt( pub(crate) async fn get_chat_contact_cnt(context: &Context, chat_id: ChatId) -> Result<usize> {
context: &Context,
chat_id: ChatId,
) -> Result<usize, Error> {
let count = context let count = context
.sql .sql
.count( .count(
@@ -2845,7 +2788,7 @@ pub(crate) async fn get_chat_contact_cnt(
Ok(count as usize) Ok(count as usize)
} }
pub(crate) async fn get_chat_cnt(context: &Context) -> Result<usize, Error> { pub(crate) async fn get_chat_cnt(context: &Context) -> Result<usize> {
if context.sql.is_open().await { if context.sql.is_open().await {
// no database, no chats - this is no error (needed eg. for information) // no database, no chats - this is no error (needed eg. for information)
let count = context let count = context
@@ -2893,7 +2836,7 @@ pub async fn add_device_msg_with_importance(
label: Option<&str>, label: Option<&str>,
msg: Option<&mut Message>, msg: Option<&mut Message>,
important: bool, important: bool,
) -> Result<MsgId, Error> { ) -> Result<MsgId> {
ensure!( ensure!(
label.is_some() || msg.is_some(), label.is_some() || msg.is_some(),
"device-messages need label, msg or both" "device-messages need label, msg or both"
@@ -2995,11 +2938,11 @@ pub async fn add_device_msg(
context: &Context, context: &Context,
label: Option<&str>, label: Option<&str>,
msg: Option<&mut Message>, msg: Option<&mut Message>,
) -> Result<MsgId, Error> { ) -> Result<MsgId> {
add_device_msg_with_importance(context, label, msg, false).await add_device_msg_with_importance(context, label, msg, false).await
} }
pub async fn was_device_msg_ever_added(context: &Context, label: &str) -> Result<bool, Error> { pub async fn was_device_msg_ever_added(context: &Context, label: &str) -> Result<bool> {
ensure!(!label.is_empty(), "empty label"); ensure!(!label.is_empty(), "empty label");
let exists = context let exists = context
.sql .sql
@@ -3017,7 +2960,7 @@ pub async fn was_device_msg_ever_added(context: &Context, label: &str) -> Result
// no wrong information are shown in the device chat // no wrong information are shown in the device chat
// - deletion in `devmsglabels` makes sure, // - deletion in `devmsglabels` makes sure,
// deleted messages are resetted and useful messages can be added again // deleted messages are resetted and useful messages can be added again
pub(crate) async fn delete_and_reset_all_device_msgs(context: &Context) -> Result<(), Error> { pub(crate) async fn delete_and_reset_all_device_msgs(context: &Context) -> Result<()> {
context context
.sql .sql
.execute( .execute(
@@ -3040,7 +2983,7 @@ pub(crate) async fn add_info_msg_with_cmd(
chat_id: ChatId, chat_id: ChatId,
text: impl AsRef<str>, text: impl AsRef<str>,
cmd: SystemMessage, cmd: SystemMessage,
) -> Result<MsgId, Error> { ) -> Result<MsgId> {
let rfc724_mid = dc_create_outgoing_rfc724_mid(None, "@device"); let rfc724_mid = dc_create_outgoing_rfc724_mid(None, "@device");
let ephemeral_timer = chat_id.get_ephemeral_timer(context).await?; let ephemeral_timer = chat_id.get_ephemeral_timer(context).await?;