Introduce a ChatId newtype

This doesn't try and change the way ChatId is used.  It still allows
creating them with 0 and lets some function use a ChatId(0) as error
return.
This commit is contained in:
Floris Bruynooghe
2020-01-07 00:04:51 +01:00
committed by Floris Bruynooghe
parent d8454d9da5
commit 186f5553b8
16 changed files with 696 additions and 494 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -36,7 +36,7 @@ use crate::stock::StockMessage;
#[derive(Debug)]
pub struct Chatlist {
/// Stores pairs of `chat_id, message_id`
ids: Vec<(u32, MsgId)>,
ids: Vec<(ChatId, MsgId)>,
}
impl Chatlist {
@@ -91,7 +91,7 @@ impl Chatlist {
let mut add_archived_link_item = false;
let process_row = |row: &rusqlite::Row| {
let chat_id: u32 = row.get(0)?;
let chat_id: ChatId = row.get(0)?;
let msg_id: MsgId = row.get(1).unwrap_or_default();
Ok((chat_id, msg_id))
};
@@ -211,7 +211,10 @@ impl Chatlist {
)?;
if 0 == listflags & DC_GCL_NO_SPECIALS {
if let Some(last_deaddrop_fresh_msg_id) = get_last_deaddrop_fresh_msg(context) {
ids.insert(0, (DC_CHAT_ID_DEADDROP, last_deaddrop_fresh_msg_id));
ids.insert(
0,
(ChatId::new(DC_CHAT_ID_DEADDROP), last_deaddrop_fresh_msg_id),
);
}
add_archived_link_item = true;
}
@@ -220,9 +223,9 @@ impl Chatlist {
if add_archived_link_item && dc_get_archived_cnt(context) > 0 {
if ids.is_empty() && 0 != listflags & DC_GCL_ADD_ALLDONE_HINT {
ids.push((DC_CHAT_ID_ALLDONE_HINT, MsgId::new(0)));
ids.push((ChatId::new(DC_CHAT_ID_ALLDONE_HINT), MsgId::new(0)));
}
ids.push((DC_CHAT_ID_ARCHIVED_LINK, MsgId::new(0)));
ids.push((ChatId::new(DC_CHAT_ID_ARCHIVED_LINK), MsgId::new(0)));
}
Ok(Chatlist { ids })
@@ -241,9 +244,9 @@ impl Chatlist {
/// Get a single chat ID of a chatlist.
///
/// To get the message object from the message ID, use dc_get_chat().
pub fn get_chat_id(&self, index: usize) -> u32 {
pub fn get_chat_id(&self, index: usize) -> ChatId {
if index >= self.ids.len() {
return 0;
return ChatId::new(0);
}
self.ids[index].0
}
@@ -307,7 +310,7 @@ impl Chatlist {
None
};
if chat.id == DC_CHAT_ID_ARCHIVED_LINK {
if chat.id.is_archived_link() {
ret.text2 = None;
} else if lastmsg.is_none() || lastmsg.as_ref().unwrap().from_id == DC_CONTACT_ID_UNDEFINED
{

View File

@@ -49,6 +49,8 @@ pub const DC_HANDSHAKE_CONTINUE_NORMAL_PROCESSING: i32 = 0x01;
pub const DC_HANDSHAKE_STOP_NORMAL_PROCESSING: i32 = 0x02;
pub const DC_HANDSHAKE_ADD_DELETE_JOB: i32 = 0x04;
pub(crate) const DC_FROM_HANDSHAKE: i32 = 0x01;
pub const DC_GCL_ARCHIVED_ONLY: usize = 0x01;
pub const DC_GCL_NO_SPECIALS: usize = 0x02;
pub const DC_GCL_ADD_ALLDONE_HINT: usize = 0x04;

View File

@@ -7,6 +7,7 @@ use itertools::Itertools;
use rusqlite;
use crate::aheader::EncryptPreference;
use crate::chat::ChatId;
use crate::config::Config;
use crate::constants::*;
use crate::context::Context;
@@ -262,7 +263,7 @@ impl Contact {
.is_ok()
{
context.call_cb(Event::MsgsChanged {
chat_id: 0,
chat_id: ChatId::new(0),
msg_id: MsgId::new(0),
});
}

View File

@@ -50,7 +50,7 @@ pub struct Context {
#[debug_stub = "Callback"]
cb: Box<ContextCallback>,
pub os_name: Option<String>,
pub cmdline_sel_chat_id: Arc<RwLock<u32>>,
pub cmdline_sel_chat_id: Arc<RwLock<ChatId>>,
pub bob: Arc<RwLock<BobStatus>>,
pub last_smeared_timestamp: RwLock<i64>,
pub running_state: Arc<RwLock<RunningState>>,
@@ -116,7 +116,7 @@ impl Context {
oauth2_critical: Arc::new(Mutex::new(())),
bob: Arc::new(RwLock::new(Default::default())),
last_smeared_timestamp: RwLock::new(0),
cmdline_sel_chat_id: Arc::new(RwLock::new(0)),
cmdline_sel_chat_id: Arc::new(RwLock::new(ChatId::new(0))),
inbox_thread: Arc::new(RwLock::new(JobThread::new(
"INBOX",
"configured_inbox_folder",
@@ -345,7 +345,7 @@ impl Context {
}
#[allow(non_snake_case)]
pub fn search_msgs(&self, chat_id: u32, query: impl AsRef<str>) -> Vec<MsgId> {
pub fn search_msgs(&self, chat_id: ChatId, query: impl AsRef<str>) -> Vec<MsgId> {
let real_query = query.as_ref().trim();
if real_query.is_empty() {
return Vec::new();
@@ -353,7 +353,7 @@ impl Context {
let strLikeInText = format!("%{}%", real_query);
let strLikeBeg = format!("{}%", real_query);
let query = if 0 != chat_id {
let query = if !chat_id.is_unset() {
concat!(
"SELECT m.id AS id, m.timestamp AS timestamp",
" FROM msgs m",
@@ -385,7 +385,7 @@ impl Context {
self.sql
.query_map(
query,
params![chat_id as i32, &strLikeInText, &strLikeBeg],
params![chat_id, &strLikeInText, &strLikeBeg],
|row| row.get::<_, MsgId>("id"),
|rows| {
let mut ret = Vec::new();

View File

@@ -3,7 +3,7 @@ use sha2::{Digest, Sha256};
use num_traits::FromPrimitive;
use crate::chat::{self, Chat};
use crate::chat::{self, Chat, ChatId};
use crate::config::Config;
use crate::constants::*;
use crate::contact::*;
@@ -61,7 +61,7 @@ pub fn dc_receive_imf(
ensure!(mime_parser.has_headers(), "No Headers Found");
// the function returns the number of created messages in the database
let mut chat_id = 0;
let mut chat_id = ChatId::new(0);
let mut hidden = false;
let mut needs_delete_job = false;
@@ -74,17 +74,17 @@ pub fn dc_receive_imf(
// helper method to handle early exit and memory cleanup
let cleanup = |context: &Context,
create_event_to_send: &Option<CreateEvent>,
created_db_entries: &Vec<(usize, MsgId)>| {
created_db_entries: &Vec<(ChatId, MsgId)>| {
if let Some(create_event_to_send) = create_event_to_send {
for (chat_id, msg_id) in created_db_entries {
let event = match create_event_to_send {
CreateEvent::MsgsChanged => Event::MsgsChanged {
msg_id: *msg_id,
chat_id: *chat_id as u32,
chat_id: *chat_id,
},
CreateEvent::IncomingMsg => Event::IncomingMsg {
msg_id: *msg_id,
chat_id: *chat_id as u32,
chat_id: *chat_id,
},
};
context.call_cb(event);
@@ -263,11 +263,11 @@ fn add_parts(
from_id: u32,
from_id_blocked: bool,
hidden: &mut bool,
chat_id: &mut u32,
chat_id: &mut ChatId,
flags: u32,
needs_delete_job: &mut bool,
insert_msg_id: &mut MsgId,
created_db_entries: &mut Vec<(usize, MsgId)>,
created_db_entries: &mut Vec<(ChatId, MsgId)>,
create_event_to_send: &mut Option<CreateEvent>,
) -> Result<()> {
let mut state: MessageState;
@@ -308,7 +308,7 @@ fn add_parts(
{
// this message is a classic email not a chat-message nor a reply to one
if show_emails == ShowEmails::Off {
*chat_id = DC_CHAT_ID_TRASH;
*chat_id = ChatId::new(DC_CHAT_ID_TRASH);
allow_creation = false
} else if show_emails == ShowEmails::AcceptedContacts {
allow_creation = false
@@ -334,7 +334,7 @@ fn add_parts(
if mime_parser.get(HeaderDef::SecureJoin).is_some() {
// avoid discarding by show_emails setting
msgrmsg = MessengerMessage::Yes;
*chat_id = 0;
*chat_id = ChatId::new(0);
allow_creation = true;
match handle_securejoin_handshake(context, mime_parser, from_id) {
Ok(securejoin::HandshakeMessage::Done) => {
@@ -364,12 +364,12 @@ fn add_parts(
// get the chat_id - a chat_id here is no indicator that the chat is displayed in the normal list,
// it might also be blocked and displayed in the deaddrop as a result
if *chat_id == 0 {
if chat_id.is_unset() {
// try to create a group
// (groups appear automatically only if the _sender_ is known, see core issue #54)
let create_blocked =
if 0 != test_normal_chat_id && test_normal_chat_id_blocked == Blocked::Not {
if !test_normal_chat_id.is_unset() && test_normal_chat_id_blocked == Blocked::Not {
Blocked::Not
} else {
Blocked::Deaddrop
@@ -385,21 +385,24 @@ fn add_parts(
)?;
*chat_id = new_chat_id;
chat_id_blocked = new_chat_id_blocked;
if *chat_id != 0 && chat_id_blocked != Blocked::Not && create_blocked == Blocked::Not {
if !chat_id.is_unset()
&& chat_id_blocked != Blocked::Not
&& create_blocked == Blocked::Not
{
chat::unblock(context, new_chat_id);
chat_id_blocked = Blocked::Not;
}
}
if *chat_id == 0 {
if chat_id.is_unset() {
// check if the message belongs to a mailing list
if mime_parser.is_mailinglist_message() {
*chat_id = DC_CHAT_ID_TRASH;
*chat_id = ChatId::new(DC_CHAT_ID_TRASH);
info!(context, "Message belongs to a mailing list and is ignored.",);
}
}
if *chat_id == 0 {
if chat_id.is_unset() {
// try to create a normal chat
let create_blocked = if from_id == to_id {
Blocked::Not
@@ -407,7 +410,7 @@ fn add_parts(
Blocked::Deaddrop
};
if 0 != test_normal_chat_id {
if !test_normal_chat_id.is_unset() {
*chat_id = test_normal_chat_id;
chat_id_blocked = test_normal_chat_id_blocked;
} else if allow_creation {
@@ -417,7 +420,7 @@ fn add_parts(
*chat_id = id;
chat_id_blocked = bl;
}
if 0 != *chat_id && Blocked::Not != chat_id_blocked {
if !chat_id.is_unset() && Blocked::Not != chat_id_blocked {
if Blocked::Not == create_blocked {
chat::unblock(context, *chat_id);
chat_id_blocked = Blocked::Not;
@@ -435,9 +438,9 @@ fn add_parts(
}
}
}
if *chat_id == 0 {
if chat_id.is_unset() {
// maybe from_id is null or sth. else is suspicious, move message to trash
*chat_id = DC_CHAT_ID_TRASH;
*chat_id = ChatId::new(DC_CHAT_ID_TRASH);
}
// if the chat_id is blocked,
@@ -459,7 +462,7 @@ fn add_parts(
state = MessageState::OutDelivered;
to_id = to_ids.get_index(0).cloned().unwrap_or_default();
if !to_ids.is_empty() {
if *chat_id == 0 {
if chat_id.is_unset() {
let (new_chat_id, new_chat_id_blocked) = create_or_lookup_group(
context,
&mut mime_parser,
@@ -471,12 +474,12 @@ fn add_parts(
*chat_id = new_chat_id;
chat_id_blocked = new_chat_id_blocked;
// automatically unblock chat when the user sends a message
if *chat_id != 0 && chat_id_blocked != Blocked::Not {
if !chat_id.is_unset() && chat_id_blocked != Blocked::Not {
chat::unblock(context, new_chat_id);
chat_id_blocked = Blocked::Not;
}
}
if *chat_id == 0 && allow_creation {
if chat_id.is_unset() && allow_creation {
let create_blocked = if MessengerMessage::No != msgrmsg
&& !Contact::is_blocked_load(context, to_id)
{
@@ -489,7 +492,7 @@ fn add_parts(
*chat_id = id;
chat_id_blocked = bl;
if 0 != *chat_id
if !chat_id.is_unset()
&& Blocked::Not != chat_id_blocked
&& Blocked::Not == create_blocked
{
@@ -502,7 +505,7 @@ fn add_parts(
&& to_ids.len() == 1
&& to_ids.contains(&DC_CONTACT_ID_SELF);
if *chat_id == 0 && self_sent {
if chat_id.is_unset() && self_sent {
// from_id==to_id==DC_CONTACT_ID_SELF - this is a self-sent messages,
// maybe an Autocrypt Setup Messag
let (id, bl) =
@@ -511,13 +514,13 @@ fn add_parts(
*chat_id = id;
chat_id_blocked = bl;
if 0 != *chat_id && Blocked::Not != chat_id_blocked {
if !chat_id.is_unset() && Blocked::Not != chat_id_blocked {
chat::unblock(context, *chat_id);
chat_id_blocked = Blocked::Not;
}
}
if *chat_id == 0 {
*chat_id = DC_CHAT_ID_TRASH;
if chat_id.is_unset() {
*chat_id = ChatId::new(DC_CHAT_ID_TRASH);
}
}
// correct message_timestamp, it should not be used before,
@@ -588,7 +591,7 @@ fn add_parts(
rfc724_mid,
server_folder.as_ref(),
server_uid as i32,
*chat_id as i32,
*chat_id,
from_id as i32,
to_id as i32,
sort_timestamp,
@@ -616,7 +619,7 @@ fn add_parts(
let row_id =
sql::get_rowid_with_conn(context, conn, "msgs", "rfc724_mid", &rfc724_mid);
*insert_msg_id = MsgId::new(row_id);
created_db_entries.push((*chat_id as usize, *insert_msg_id));
created_db_entries.push((*chat_id, *insert_msg_id));
}
Ok(())
},
@@ -628,7 +631,7 @@ fn add_parts(
);
// check event to send
if *chat_id == DC_CHAT_ID_TRASH {
if chat_id.is_trash() {
*create_event_to_send = None;
} else if incoming && state == MessageState::InFresh {
if from_id_blocked {
@@ -646,12 +649,12 @@ fn add_parts(
fn save_locations(
context: &Context,
mime_parser: &MimeMessage,
chat_id: u32,
chat_id: ChatId,
from_id: u32,
insert_msg_id: MsgId,
hidden: bool,
) {
if chat_id <= DC_CHAT_ID_LAST_SPECIAL {
if chat_id.is_special() {
return;
}
let mut location_id_written = false;
@@ -699,7 +702,7 @@ fn save_locations(
fn calc_timestamps(
context: &Context,
chat_id: u32,
chat_id: ChatId,
from_id: u32,
message_timestamp: i64,
is_fresh_msg: bool,
@@ -717,7 +720,7 @@ fn calc_timestamps(
let last_msg_time: Option<i64> = context.sql.query_get_value(
context,
"SELECT MAX(timestamp) FROM msgs WHERE chat_id=? and from_id!=? AND timestamp>=?",
params![chat_id as i32, from_id as i32, *sort_timestamp],
params![chat_id, from_id as i32, *sort_timestamp],
);
if let Some(last_msg_time) = last_msg_time {
if last_msg_time > 0 && *sort_timestamp <= last_msg_time {
@@ -749,7 +752,7 @@ fn create_or_lookup_group(
create_blocked: Blocked,
from_id: u32,
to_ids: &ContactIds,
) -> Result<(u32, Blocked)> {
) -> Result<(ChatId, Blocked)> {
let mut chat_id_blocked = Blocked::Not;
let mut recreate_member_list = false;
let mut send_EVENT_CHAT_MODIFIED = false;
@@ -867,9 +870,9 @@ fn create_or_lookup_group(
set_better_msg(mime_parser, &better_msg);
// check, if we have a chat with this group ID
let (mut chat_id, chat_id_verified, _blocked) =
chat::get_chat_id_by_grpid(context, &grpid).unwrap_or((0, false, Blocked::Not));
if chat_id != 0 {
let (mut chat_id, chat_id_verified, _blocked) = chat::get_chat_id_by_grpid(context, &grpid)
.unwrap_or((ChatId::new(0), false, Blocked::Not));
if !chat_id.is_error() {
if chat_id_verified {
if let Err(err) =
check_verified_properties(context, mime_parser, from_id as u32, to_ids)
@@ -897,7 +900,7 @@ fn create_or_lookup_group(
.get_config(Config::ConfiguredAddr)
.unwrap_or_default();
if chat_id == 0
if chat_id.is_error()
&& !mime_parser.is_mailinglist_message()
&& !grpid.is_empty()
&& grpname.is_some()
@@ -923,7 +926,7 @@ fn create_or_lookup_group(
if !allow_creation {
info!(context, "creating group forbidden by caller");
return Ok((0, Blocked::Not));
return Ok((ChatId::new(0), Blocked::Not));
}
chat_id = create_group_record(
@@ -938,9 +941,9 @@ fn create_or_lookup_group(
}
// again, check chat_id
if chat_id <= DC_CHAT_ID_LAST_SPECIAL {
if chat_id.is_special() {
return if group_explicitly_left {
Ok((DC_CHAT_ID_TRASH, chat_id_blocked))
Ok((ChatId::new(DC_CHAT_ID_TRASH), chat_id_blocked))
} else {
create_or_lookup_adhoc_group(
context,
@@ -980,7 +983,7 @@ fn create_or_lookup_group(
context,
&context.sql,
"UPDATE chats SET name=? WHERE id=?;",
params![grpname, chat_id as i32],
params![grpname, chat_id],
)
.is_ok()
{
@@ -1018,7 +1021,7 @@ fn create_or_lookup_group(
context,
&context.sql,
"DELETE FROM chats_contacts WHERE chat_id=?;",
params![chat_id as i32],
params![chat_id],
)
.ok();
if skip.is_none() || !addr_cmp(&self_addr, skip.unwrap()) {
@@ -1066,7 +1069,7 @@ fn create_or_lookup_adhoc_group(
create_blocked: Blocked,
from_id: u32,
to_ids: &ContactIds,
) -> Result<(u32, Blocked)> {
) -> Result<(ChatId, Blocked)> {
// if we're here, no grpid was found, check if there is an existing
// ad-hoc group matching the to-list or if we should and can create one
// (we do not want to heuristically look at the likely mangled Subject)
@@ -1078,7 +1081,7 @@ fn create_or_lookup_adhoc_group(
context,
"not creating ad-hoc group for mailing list message"
);
return Ok((0, Blocked::Not));
return Ok((ChatId::new(0), Blocked::Not));
}
let mut member_ids: Vec<u32> = to_ids.iter().copied().collect();
@@ -1091,7 +1094,7 @@ fn create_or_lookup_adhoc_group(
if member_ids.len() < 3 {
info!(context, "not creating ad-hoc group: too few contacts");
return Ok((0, Blocked::Not));
return Ok((ChatId::new(0), Blocked::Not));
}
let chat_ids = search_chat_ids_by_contact_ids(context, &member_ids)?;
@@ -1099,25 +1102,35 @@ fn create_or_lookup_adhoc_group(
let chat_ids_str = join(chat_ids.iter().map(|x| x.to_string()), ",");
let res = context.sql.query_row(
format!(
"SELECT c.id, c.blocked FROM chats c \
LEFT JOIN msgs m ON m.chat_id=c.id WHERE c.id IN({}) ORDER BY m.timestamp DESC, m.id DESC LIMIT 1;",
"SELECT c.id,
c.blocked
FROM chats c
LEFT JOIN msgs m
ON m.chat_id=c.id
WHERE c.id IN({})
ORDER BY m.timestamp DESC,
m.id DESC
LIMIT 1;",
chat_ids_str
),
params![],
|row| {
Ok((row.get::<_, i32>(0)?, row.get::<_, Option<Blocked>>(1)?.unwrap_or_default()))
}
Ok((
row.get::<_, ChatId>(0)?,
row.get::<_, Option<Blocked>>(1)?.unwrap_or_default(),
))
},
);
if let Ok((id, id_blocked)) = res {
/* success, chat found */
return Ok((id as u32, id_blocked));
return Ok((id, id_blocked));
}
}
if !allow_creation {
info!(context, "creating ad-hoc group prevented from caller");
return Ok((0, Blocked::Not));
return Ok((ChatId::new(0), Blocked::Not));
}
// we do not check if the message is a reply to another group, this may result in
@@ -1131,7 +1144,7 @@ fn create_or_lookup_adhoc_group(
context,
"failed to create ad-hoc grpid for {:?}", member_ids
);
return Ok((0, Blocked::Not));
return Ok((ChatId::new(0), Blocked::Not));
}
// use subject as initial chat name
let grpname = mime_parser.get_subject().unwrap_or_else(|| {
@@ -1139,7 +1152,7 @@ fn create_or_lookup_adhoc_group(
});
// create group record
let new_chat_id = create_group_record(
let new_chat_id: ChatId = create_group_record(
context,
&grpid,
grpname,
@@ -1161,7 +1174,7 @@ fn create_group_record(
grpname: impl AsRef<str>,
create_blocked: Blocked,
create_verified: VerifiedStatus,
) -> u32 {
) -> ChatId {
if sql::execute(
context,
&context.sql,
@@ -1186,12 +1199,13 @@ fn create_group_record(
grpname.as_ref(),
grpid.as_ref()
);
return 0;
return ChatId::new(0);
}
let chat_id = sql::get_rowid(context, &context.sql, "chats", "grpid", grpid.as_ref());
let row_id = sql::get_rowid(context, &context.sql, "chats", "grpid", grpid.as_ref());
let chat_id = ChatId::new(row_id);
info!(
context,
"Created group '{}' grpid={} as chat #{}",
"Created group '{}' grpid={} as {}",
grpname.as_ref(),
grpid.as_ref(),
chat_id
@@ -1246,7 +1260,7 @@ fn hex_hash(s: impl AsRef<str>) -> String {
fn search_chat_ids_by_contact_ids(
context: &Context,
unsorted_contact_ids: &[u32],
) -> Result<Vec<u32>> {
) -> Result<Vec<ChatId>> {
/* searches chat_id's by the given contact IDs, may return zero, one or more chat_id's */
let mut contact_ids = Vec::with_capacity(23);
let mut chat_ids = Vec::with_capacity(23);
@@ -1263,19 +1277,19 @@ fn search_chat_ids_by_contact_ids(
let contact_ids_str = join(contact_ids.iter().map(|x| x.to_string()), ",");
context.sql.query_map(
format!(
"SELECT DISTINCT cc.chat_id, cc.contact_id \
FROM chats_contacts cc \
LEFT JOIN chats c ON c.id=cc.chat_id \
WHERE cc.chat_id IN(SELECT chat_id FROM chats_contacts WHERE contact_id IN({})) \
AND c.type=120 \
AND cc.contact_id!=1 \
ORDER BY cc.chat_id, cc.contact_id;", // 1=DC_CONTACT_ID_SELF
"SELECT DISTINCT cc.chat_id, cc.contact_id
FROM chats_contacts cc
LEFT JOIN chats c ON c.id=cc.chat_id
WHERE cc.chat_id IN(SELECT chat_id FROM chats_contacts WHERE contact_id IN({}))
AND c.type=120
AND cc.contact_id!=1
ORDER BY cc.chat_id, cc.contact_id;", // 1=DC_CONTACT_ID_SELF
contact_ids_str
),
params![],
|row| Ok((row.get::<_, u32>(0)?, row.get::<_, u32>(1)?)),
|row| Ok((row.get::<_, ChatId>(0)?, row.get::<_, u32>(1)?)),
|rows| {
let mut last_chat_id = 0;
let mut last_chat_id = ChatId::new(0);
let mut matches = 0;
let mut mismatches = 0;

View File

@@ -4,6 +4,7 @@ use std::path::PathBuf;
use strum::EnumProperty;
use crate::chat::ChatId;
use crate::message::MsgId;
impl Event {
@@ -107,36 +108,36 @@ pub enum Event {
/// - Chats created, deleted or archived
/// - A draft has been set
#[strum(props(id = "2000"))]
MsgsChanged { chat_id: u32, msg_id: MsgId },
MsgsChanged { chat_id: ChatId, msg_id: MsgId },
/// There is a fresh message. Typically, the user will show an notification
/// when receiving this message.
///
/// There is no extra #DC_EVENT_MSGS_CHANGED event send together with this event.
#[strum(props(id = "2005"))]
IncomingMsg { chat_id: u32, msg_id: MsgId },
IncomingMsg { chat_id: ChatId, msg_id: MsgId },
/// A single message is sent successfully. State changed from DC_STATE_OUT_PENDING to
/// DC_STATE_OUT_DELIVERED, see dc_msg_get_state().
#[strum(props(id = "2010"))]
MsgDelivered { chat_id: u32, msg_id: MsgId },
MsgDelivered { chat_id: ChatId, msg_id: MsgId },
/// A single message could not be sent. State changed from DC_STATE_OUT_PENDING or DC_STATE_OUT_DELIVERED to
/// DC_STATE_OUT_FAILED, see dc_msg_get_state().
#[strum(props(id = "2012"))]
MsgFailed { chat_id: u32, msg_id: MsgId },
MsgFailed { chat_id: ChatId, msg_id: MsgId },
/// A single message is read by the receiver. State changed from DC_STATE_OUT_DELIVERED to
/// DC_STATE_OUT_MDN_RCVD, see dc_msg_get_state().
#[strum(props(id = "2015"))]
MsgRead { chat_id: u32, msg_id: MsgId },
MsgRead { chat_id: ChatId, msg_id: MsgId },
/// Chat changed. The name or the image of a chat group was changed or members were added or removed.
/// Or the verify state of a chat has changed.
/// See dc_set_chat_name(), dc_set_chat_profile_image(), dc_add_contact_to_chat()
/// and dc_remove_contact_from_chat().
#[strum(props(id = "2020"))]
ChatModified(u32),
ChatModified(ChatId),
/// Contact(s) created, renamed, blocked or deleted.
///
@@ -205,5 +206,5 @@ pub enum Event {
/// @param data1 (int) chat_id
/// @param data2 (int) contact_id
#[strum(props(id = "2062"))]
SecurejoinMemberAdded { chat_id: u32, contact_id: u32 },
SecurejoinMemberAdded { chat_id: ChatId, contact_id: u32 },
}

View File

@@ -12,7 +12,7 @@ use rand::{thread_rng, Rng};
use async_std::task;
use crate::blob::BlobObject;
use crate::chat;
use crate::chat::{self, ChatId};
use crate::config::Config;
use crate::configure::*;
use crate::constants::*;
@@ -764,7 +764,7 @@ pub fn job_action_exists(context: &Context, action: Action) -> bool {
fn set_delivered(context: &Context, msg_id: MsgId) {
message::update_msg_state(context, msg_id, MessageState::OutDelivered);
let chat_id: i32 = context
let chat_id: ChatId = context
.sql
.query_get_value(
context,
@@ -772,10 +772,7 @@ fn set_delivered(context: &Context, msg_id: MsgId) {
params![msg_id],
)
.unwrap_or_default();
context.call_cb(Event::MsgDelivered {
chat_id: chat_id as u32,
msg_id,
});
context.call_cb(Event::MsgDelivered { chat_id, msg_id });
}
/* special case for DC_JOB_SEND_MSG_TO_SMTP */

View File

@@ -4,7 +4,7 @@ use bitflags::bitflags;
use quick_xml;
use quick_xml::events::{BytesEnd, BytesStart, BytesText};
use crate::chat;
use crate::chat::{self, ChatId};
use crate::config::Config;
use crate::constants::*;
use crate::context::*;
@@ -28,7 +28,7 @@ pub struct Location {
pub timestamp: i64,
pub contact_id: u32,
pub msg_id: u32,
pub chat_id: u32,
pub chat_id: ChatId,
pub marker: Option<String>,
pub independent: u32,
}
@@ -193,9 +193,9 @@ impl Kml {
}
// location streaming
pub fn send_locations_to_chat(context: &Context, chat_id: u32, seconds: i64) {
pub fn send_locations_to_chat(context: &Context, chat_id: ChatId, seconds: i64) {
let now = time();
if !(seconds < 0 || chat_id <= DC_CHAT_ID_LAST_SPECIAL) {
if !(seconds < 0 || chat_id.is_special()) {
let is_sending_locations_before = is_sending_locations_to_chat(context, chat_id);
if sql::execute(
context,
@@ -207,7 +207,7 @@ pub fn send_locations_to_chat(context: &Context, chat_id: u32, seconds: i64) {
params![
if 0 != seconds { now } else { 0 },
if 0 != seconds { now + seconds } else { 0 },
chat_id as i32,
chat_id,
],
)
.is_ok()
@@ -229,7 +229,7 @@ pub fn send_locations_to_chat(context: &Context, chat_id: u32, seconds: i64) {
job_add(
context,
job::Action::MaybeSendLocationsEnded,
chat_id as i32,
chat_id.to_u32() as i32,
Params::new(),
seconds + 1,
);
@@ -251,12 +251,12 @@ fn schedule_MAYBE_SEND_LOCATIONS(context: &Context, force_schedule: bool) {
};
}
pub fn is_sending_locations_to_chat(context: &Context, chat_id: u32) -> bool {
pub fn is_sending_locations_to_chat(context: &Context, chat_id: ChatId) -> bool {
context
.sql
.exists(
"SELECT id FROM chats WHERE (? OR id=?) AND locations_send_until>?;",
params![if chat_id == 0 { 1 } else { 0 }, chat_id as i32, time()],
params![if chat_id.is_unset() { 1 } else { 0 }, chat_id, time()],
)
.unwrap_or_default()
}
@@ -302,7 +302,7 @@ pub fn set(context: &Context, latitude: f64, longitude: f64, accuracy: f64) -> b
pub fn get_range(
context: &Context,
chat_id: u32,
chat_id: ChatId,
contact_id: u32,
timestamp_from: i64,
mut timestamp_to: i64,
@@ -320,8 +320,8 @@ pub fn get_range(
AND (l.independent=1 OR (l.timestamp>=? AND l.timestamp<=?)) \
ORDER BY l.timestamp DESC, l.id DESC, msg_id DESC;",
params![
if chat_id == 0 { 1 } else { 0 },
chat_id as i32,
if chat_id.is_unset() { 1 } else { 0 },
chat_id,
if contact_id == 0 { 1 } else { 0 },
contact_id as i32,
timestamp_from,
@@ -371,7 +371,7 @@ pub fn delete_all(context: &Context) -> Result<(), Error> {
Ok(())
}
pub fn get_kml(context: &Context, chat_id: u32) -> Result<(String, u32), Error> {
pub fn get_kml(context: &Context, chat_id: ChatId) -> Result<(String, u32), Error> {
let mut last_added_location_id = 0;
let self_addr = context
@@ -380,7 +380,7 @@ pub fn get_kml(context: &Context, chat_id: u32) -> Result<(String, u32), Error>
let (locations_send_begin, locations_send_until, locations_last_sent) = context.sql.query_row(
"SELECT locations_send_begin, locations_send_until, locations_last_sent FROM chats WHERE id=?;",
params![chat_id as i32], |row| {
params![chat_id], |row| {
let send_begin: i64 = row.get(0)?;
let send_until: i64 = row.get(1)?;
let last_sent: i64 = row.get(2)?;
@@ -465,14 +465,14 @@ pub fn get_message_kml(timestamp: i64, latitude: f64, longitude: f64) -> String
pub fn set_kml_sent_timestamp(
context: &Context,
chat_id: u32,
chat_id: ChatId,
timestamp: i64,
) -> Result<(), Error> {
sql::execute(
context,
&context.sql,
"UPDATE chats SET locations_last_sent=? WHERE id=?;",
params![timestamp, chat_id as i32],
params![timestamp, chat_id],
)?;
Ok(())
@@ -495,12 +495,12 @@ pub fn set_msg_location_id(
pub fn save(
context: &Context,
chat_id: u32,
chat_id: ChatId,
contact_id: u32,
locations: &[Location],
independent: bool,
) -> Result<u32, Error> {
ensure!(chat_id > DC_CHAT_ID_LAST_SPECIAL, "Invalid chat id");
ensure!(!chat_id.is_special(), "Invalid chat id");
context
.sql
.prepare2(
@@ -520,7 +520,7 @@ pub fn save(
stmt_insert.execute(params![
location.timestamp,
contact_id as i32,
chat_id as i32,
chat_id,
location.latitude,
location.longitude,
location.accuracy,
@@ -562,7 +562,7 @@ pub fn JobMaybeSendLocations(context: &Context, _job: &Job) -> job::Status {
WHERE locations_send_until>?;",
params![now],
|row| {
let chat_id: i32 = row.get(0)?;
let chat_id: ChatId = row.get(0)?;
let locations_send_begin: i64 = row.get(1)?;
let locations_last_sent: i64 = row.get(2)?;
continue_streaming = true;
@@ -629,7 +629,7 @@ pub fn JobMaybeSendLocations(context: &Context, _job: &Job) -> job::Status {
for (chat_id, mut msg) in msgs.into_iter() {
// TODO: better error handling
chat::send_msg(context, chat_id as u32, &mut msg).unwrap_or_default();
chat::send_msg(context, chat_id, &mut msg).unwrap_or_default();
}
}
if continue_streaming {
@@ -644,11 +644,11 @@ pub fn JobMaybeSendLocationsEnded(context: &Context, job: &mut Job) -> job::Stat
// the function checks, if location-streaming is really ended;
// if so, a device-message is added if not yet done.
let chat_id = job.foreign_id;
let chat_id = ChatId::new(job.foreign_id);
let (send_begin, send_until) = job_try!(context.sql.query_row(
"SELECT locations_send_begin, locations_send_until FROM chats WHERE id=?",
params![chat_id as i32],
params![chat_id],
|row| Ok((row.get::<_, i64>(0)?, row.get::<_, i64>(1)?)),
));
@@ -660,7 +660,7 @@ pub fn JobMaybeSendLocationsEnded(context: &Context, job: &mut Job) -> job::Stat
// not streaming, device-message already sent
job_try!(context.sql.execute(
"UPDATE chats SET locations_send_begin=0, locations_send_until=0 WHERE id=?",
params![chat_id as i32],
params![chat_id],
));
let stock_str = context.stock_system_msg(StockMessage::MsgLocationDisabled, "", "", 0);

View File

@@ -5,7 +5,7 @@ use std::path::{Path, PathBuf};
use deltachat_derive::{FromSql, ToSql};
use failure::Fail;
use crate::chat::{self, Chat};
use crate::chat::{self, Chat, ChatId};
use crate::constants::*;
use crate::contact::*;
use crate::context::*;
@@ -176,7 +176,7 @@ pub struct Message {
pub(crate) id: MsgId,
pub(crate) from_id: u32,
pub(crate) to_id: u32,
pub(crate) chat_id: u32,
pub(crate) chat_id: ChatId,
pub(crate) viewtype: Viewtype,
pub(crate) state: MessageState,
pub(crate) hidden: bool,
@@ -400,9 +400,9 @@ impl Message {
self.from_id
}
pub fn get_chat_id(&self) -> u32 {
pub fn get_chat_id(&self) -> ChatId {
if self.chat_blocked != Blocked::Not {
1
ChatId::new(DC_CHAT_ID_DEADDROP)
} else {
self.chat_id
}
@@ -737,7 +737,7 @@ impl Lot {
self.text1 = None;
self.text1_meaning = Meaning::None;
} else {
if chat.id == DC_CHAT_ID_DEADDROP {
if chat.id.is_deaddrop() {
if let Some(contact) = contact {
self.text1 = Some(contact.get_display_name().into());
} else {
@@ -929,7 +929,7 @@ pub fn delete_msgs(context: &Context, msg_ids: &[MsgId]) {
delete_poi_location(context, msg.location_id);
}
}
update_msg_chat_id(context, *msg_id, DC_CHAT_ID_TRASH);
update_msg_chat_id(context, *msg_id, ChatId::new(DC_CHAT_ID_TRASH));
job_add(
context,
Action::DeleteMsgOnImap,
@@ -941,7 +941,7 @@ pub fn delete_msgs(context: &Context, msg_ids: &[MsgId]) {
if !msg_ids.is_empty() {
context.call_cb(Event::MsgsChanged {
chat_id: 0,
chat_id: ChatId::new(0),
msg_id: MsgId::new(0),
});
job_kill_action(context, Action::Housekeeping);
@@ -949,12 +949,12 @@ pub fn delete_msgs(context: &Context, msg_ids: &[MsgId]) {
};
}
fn update_msg_chat_id(context: &Context, msg_id: MsgId, chat_id: u32) -> bool {
fn update_msg_chat_id(context: &Context, msg_id: MsgId, chat_id: ChatId) -> bool {
sql::execute(
context,
&context.sql,
"UPDATE msgs SET chat_id=? WHERE id=?;",
params![chat_id as i32, msg_id],
params![chat_id, msg_id],
)
.is_ok()
}
@@ -1033,7 +1033,7 @@ pub fn markseen_msgs(context: &Context, msg_ids: &[MsgId]) -> bool {
if send_event {
context.call_cb(Event::MsgsChanged {
chat_id: 0,
chat_id: ChatId::new(0),
msg_id: MsgId::new(0),
});
}
@@ -1144,14 +1144,14 @@ pub fn exists(context: &Context, msg_id: MsgId) -> bool {
return false;
}
let chat_id: Option<u32> = context.sql.query_get_value(
let chat_id: Option<ChatId> = context.sql.query_get_value(
context,
"SELECT chat_id FROM msgs WHERE id=?;",
params![msg_id],
);
if let Some(chat_id) = chat_id {
chat_id != DC_CHAT_ID_TRASH
!chat_id.is_trash()
} else {
false
}
@@ -1189,7 +1189,7 @@ pub fn mdn_from_ext(
from_id: u32,
rfc724_mid: &str,
timestamp_sent: i64,
) -> Option<(u32, MsgId)> {
) -> Option<(ChatId, MsgId)> {
if from_id <= DC_MSG_ID_LAST_SPECIAL || rfc724_mid.is_empty() {
return None;
}
@@ -1209,7 +1209,7 @@ pub fn mdn_from_ext(
|row| {
Ok((
row.get::<_, MsgId>("msg_id")?,
row.get::<_, u32>("chat_id")?,
row.get::<_, ChatId>("chat_id")?,
row.get::<_, Chattype>("type")?,
row.get::<_, MessageState>("state")?,
))

View File

@@ -83,7 +83,7 @@ impl<'a, 'b> MimeFactory<'a, 'b> {
FROM chats_contacts cc \
LEFT JOIN contacts c ON cc.contact_id=c.id \
WHERE cc.chat_id=? AND cc.contact_id>9;",
params![msg.chat_id as i32],
params![msg.chat_id],
|row| {
let authname: String = row.get(0)?;
let addr: String = row.get(1)?;
@@ -163,7 +163,7 @@ impl<'a, 'b> MimeFactory<'a, 'b> {
msg: &'b Message,
additional_msg_ids: Vec<String>,
) -> Result<Self, Error> {
ensure!(msg.chat_id > DC_CHAT_ID_LAST_SPECIAL, "Invalid chat id");
ensure!(!msg.chat_id.is_special(), "Invalid chat id");
let contact = Contact::load_from_db(context, msg.from_id)?;
@@ -613,7 +613,9 @@ impl<'a, 'b> MimeFactory<'a, 'b> {
email_to_add.into(),
));
}
if 0 != self.msg.param.get_int(Param::Arg2).unwrap_or_default() & 0x1 {
if 0 != self.msg.param.get_int(Param::Arg2).unwrap_or_default()
& DC_FROM_HANDSHAKE
{
info!(
context,
"sending secure-join message \'{}\' >>>>>>>>>>>>>>>>>>>>>>>>>",

View File

@@ -3,7 +3,7 @@
use percent_encoding::{utf8_percent_encode, AsciiSet, NON_ALPHANUMERIC};
use crate::aheader::EncryptPreference;
use crate::chat::{self, Chat};
use crate::chat::{self, Chat, ChatId};
use crate::config::*;
use crate::constants::*;
use crate::contact::*;
@@ -65,7 +65,7 @@ macro_rules! get_qr_attr {
};
}
pub fn dc_get_securejoin_qr(context: &Context, group_chat_id: u32) -> Option<String> {
pub fn dc_get_securejoin_qr(context: &Context, group_chat_id: ChatId) -> Option<String> {
/*=======================================================
==== Alice - the inviter side ====
==== Step 1 in "Setup verified contact" protocol ====
@@ -101,7 +101,7 @@ pub fn dc_get_securejoin_qr(context: &Context, group_chat_id: u32) -> Option<Str
let self_name_urlencoded =
utf8_percent_encode(&self_name, NON_ALPHANUMERIC_WITHOUT_DOT).to_string();
let qr = if 0 != group_chat_id {
let qr = if !group_chat_id.is_unset() {
// parameters used: a=g=x=i=s=
if let Ok(chat) = Chat::load_from_db(context, group_chat_id) {
let group_name = chat.get_name();
@@ -143,31 +143,31 @@ fn get_self_fingerprint(context: &Context) -> Option<String> {
None
}
pub fn dc_join_securejoin(context: &Context, qr: &str) -> u32 {
pub fn dc_join_securejoin(context: &Context, qr: &str) -> ChatId {
let cleanup =
|context: &Context, contact_chat_id: u32, ongoing_allocated: bool, join_vg: bool| {
|context: &Context, contact_chat_id: ChatId, ongoing_allocated: bool, join_vg: bool| {
let mut bob = context.bob.write().unwrap();
bob.expects = 0;
let ret_chat_id = if bob.status == DC_BOB_SUCCESS {
let ret_chat_id: ChatId = if bob.status == DC_BOB_SUCCESS {
if join_vg {
chat::get_chat_id_by_grpid(
context,
bob.qr_scan.as_ref().unwrap().text2.as_ref().unwrap(),
)
.unwrap_or((0, false, Blocked::Not))
.unwrap_or((ChatId::new(0), false, Blocked::Not))
.0
} else {
contact_chat_id
}
} else {
0
ChatId::new(0)
};
bob.qr_scan = None;
if ongoing_allocated {
context.free_ongoing();
}
ret_chat_id as u32
ret_chat_id
};
/*========================================================
@@ -175,7 +175,7 @@ pub fn dc_join_securejoin(context: &Context, qr: &str) -> u32 {
==== Step 2 in "Setup verified contact" protocol =====
========================================================*/
let mut contact_chat_id: u32 = 0;
let mut contact_chat_id = ChatId::new(0);
let mut join_vg: bool = false;
info!(context, "Requesting secure-join ...",);
@@ -189,11 +189,13 @@ pub fn dc_join_securejoin(context: &Context, qr: &str) -> u32 {
error!(context, "Unknown QR code.",);
return cleanup(&context, contact_chat_id, true, join_vg);
}
contact_chat_id = chat::create_by_contact_id(context, qr_scan.id).unwrap_or_default();
if contact_chat_id == 0 {
error!(context, "Unknown contact.",);
return cleanup(&context, contact_chat_id, true, join_vg);
}
contact_chat_id = match chat::create_by_contact_id(context, qr_scan.id) {
Ok(chat_id) => chat_id,
Err(_) => {
error!(context, "Unknown contact.");
return cleanup(&context, contact_chat_id, true, join_vg);
}
};
if context.shall_stop_ongoing() {
return cleanup(&context, contact_chat_id, true, join_vg);
}
@@ -264,7 +266,7 @@ pub fn dc_join_securejoin(context: &Context, qr: &str) -> u32 {
fn send_handshake_msg(
context: &Context,
contact_chat_id: u32,
contact_chat_id: ChatId,
step: &str,
param2: impl AsRef<str>,
fingerprint: Option<String>,
@@ -301,7 +303,7 @@ fn send_handshake_msg(
chat::send_msg(context, contact_chat_id, &mut msg).unwrap_or_default();
}
fn chat_id_2_contact_id(context: &Context, contact_chat_id: u32) -> u32 {
fn chat_id_2_contact_id(context: &Context, contact_chat_id: ChatId) -> u32 {
let contacts = chat::get_chat_contacts(context, contact_chat_id);
if contacts.len() == 1 {
contacts[0]
@@ -313,7 +315,7 @@ fn chat_id_2_contact_id(context: &Context, contact_chat_id: u32) -> u32 {
fn fingerprint_equals_sender(
context: &Context,
fingerprint: impl AsRef<str>,
contact_chat_id: u32,
contact_chat_id: ChatId,
) -> bool {
let contacts = chat::get_chat_contacts(context, contact_chat_id);
@@ -648,7 +650,7 @@ pub(crate) fn handle_securejoin_handshake(
// only after we have returned. It does not impact
// the security invariants of secure-join however.
let (_, is_verified_group, _) = chat::get_chat_id_by_grpid(context, &group_id)
.unwrap_or((0, false, Blocked::Not));
.unwrap_or((ChatId::new(0), false, Blocked::Not));
// when joining a non-verified group
// the vg-member-added message may be unencrypted
// when not all group members have keys or prefer encryption.
@@ -750,7 +752,7 @@ pub(crate) fn handle_securejoin_handshake(
}
}
fn secure_connection_established(context: &Context, contact_chat_id: u32) {
fn secure_connection_established(context: &Context, contact_chat_id: ChatId) {
let contact_id: u32 = chat_id_2_contact_id(context, contact_chat_id);
let contact = Contact::get_by_id(context, contact_id);
let addr = if let Ok(ref contact) = contact {
@@ -763,7 +765,11 @@ fn secure_connection_established(context: &Context, contact_chat_id: u32) {
emit_event!(context, Event::ChatModified(contact_chat_id));
}
fn could_not_establish_secure_connection(context: &Context, contact_chat_id: u32, details: &str) {
fn could_not_establish_secure_connection(
context: &Context,
contact_chat_id: ChatId,
details: &str,
) {
let contact_id = chat_id_2_contact_id(context, contact_chat_id);
let contact = Contact::get_by_id(context, contact_id);
let msg = context.stock_string_repl_str(

View File

@@ -6,6 +6,7 @@
use deltachat_derive::*;
use crate::chat::ChatId;
use crate::context::Context;
use crate::dc_tools::*;
use crate::sql;
@@ -27,28 +28,28 @@ impl Default for Namespace {
/// Creates a new token and saves it into the database.
/// Returns created token.
pub fn save(context: &Context, namespace: Namespace, foreign_id: u32) -> String {
pub fn save(context: &Context, namespace: Namespace, foreign_id: ChatId) -> String {
// foreign_id may be 0
let token = dc_create_id();
sql::execute(
context,
&context.sql,
"INSERT INTO tokens (namespc, foreign_id, token, timestamp) VALUES (?, ?, ?, ?);",
params![namespace, foreign_id as i32, &token, time()],
params![namespace, foreign_id, &token, time()],
)
.ok();
token
}
pub fn lookup(context: &Context, namespace: Namespace, foreign_id: u32) -> Option<String> {
pub fn lookup(context: &Context, namespace: Namespace, foreign_id: ChatId) -> Option<String> {
context.sql.query_get_value::<_, String>(
context,
"SELECT token FROM tokens WHERE namespc=? AND foreign_id=?;",
params![namespace, foreign_id as i32],
params![namespace, foreign_id],
)
}
pub fn lookup_or_new(context: &Context, namespace: Namespace, foreign_id: u32) -> String {
pub fn lookup_or_new(context: &Context, namespace: Namespace, foreign_id: ChatId) -> String {
lookup(context, namespace, foreign_id).unwrap_or_else(|| save(context, namespace, foreign_id))
}