|
|
|
|
@@ -47,11 +47,6 @@ pub fn dc_receive_imf(
|
|
|
|
|
server_uid,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Parse the imf to mailimf_message. normally, this is done by mailimf_message_parse(),
|
|
|
|
|
// however, as we also need the MIME data,
|
|
|
|
|
// we use mailmime_parse() through dc_mimeparser (both call mailimf_struct_multiple_parse()
|
|
|
|
|
// somewhen, I did not found out anything that speaks against this approach yet)
|
|
|
|
|
|
|
|
|
|
let mime_parser = MimeParser::from_bytes(context, imf_raw);
|
|
|
|
|
let mut mime_parser = if let Err(err) = mime_parser {
|
|
|
|
|
warn!(context, "dc_receive_imf parse error: {}", err);
|
|
|
|
|
@@ -210,7 +205,7 @@ pub fn dc_receive_imf(
|
|
|
|
|
&mut created_db_entries,
|
|
|
|
|
&mut create_event_to_send,
|
|
|
|
|
) {
|
|
|
|
|
warn!(context, "{}", err);
|
|
|
|
|
warn!(context, "add_parts error: {:?}", err);
|
|
|
|
|
|
|
|
|
|
cleanup(
|
|
|
|
|
context,
|
|
|
|
|
@@ -414,18 +409,18 @@ fn add_parts(
|
|
|
|
|
Blocked::Deaddrop
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
create_or_lookup_group(
|
|
|
|
|
let (new_chat_id, new_chat_id_blocked) = create_or_lookup_group(
|
|
|
|
|
context,
|
|
|
|
|
&mut mime_parser,
|
|
|
|
|
allow_creation,
|
|
|
|
|
create_blocked,
|
|
|
|
|
*from_id,
|
|
|
|
|
to_ids,
|
|
|
|
|
chat_id,
|
|
|
|
|
&mut chat_id_blocked,
|
|
|
|
|
)?;
|
|
|
|
|
if 0 != *chat_id && Blocked::Not != chat_id_blocked && create_blocked == Blocked::Not {
|
|
|
|
|
chat::unblock(context, *chat_id);
|
|
|
|
|
*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 {
|
|
|
|
|
chat::unblock(context, new_chat_id);
|
|
|
|
|
chat_id_blocked = Blocked::Not;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -507,18 +502,19 @@ fn add_parts(
|
|
|
|
|
if !to_ids.is_empty() {
|
|
|
|
|
*to_id = to_ids[0];
|
|
|
|
|
if *chat_id == 0 {
|
|
|
|
|
create_or_lookup_group(
|
|
|
|
|
let (new_chat_id, new_chat_id_blocked) = create_or_lookup_group(
|
|
|
|
|
context,
|
|
|
|
|
&mut mime_parser,
|
|
|
|
|
allow_creation,
|
|
|
|
|
Blocked::Not,
|
|
|
|
|
*from_id,
|
|
|
|
|
to_ids,
|
|
|
|
|
chat_id,
|
|
|
|
|
&mut chat_id_blocked,
|
|
|
|
|
)?;
|
|
|
|
|
if 0 != *chat_id && Blocked::Not != chat_id_blocked {
|
|
|
|
|
chat::unblock(context, *chat_id);
|
|
|
|
|
*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 {
|
|
|
|
|
chat::unblock(context, new_chat_id);
|
|
|
|
|
chat_id_blocked = Blocked::Not;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -789,7 +785,7 @@ fn calc_timestamps(
|
|
|
|
|
/// - is there a group with the same recipients? if so, use this (if there are multiple, use the most recent one)
|
|
|
|
|
/// - create an ad-hoc group based on the recipient list
|
|
|
|
|
///
|
|
|
|
|
/// So when the function returns, the caller has the group id matching the current state of the group.
|
|
|
|
|
/// on success the function returns the found/created (chat_id, chat_blocked) tuple .
|
|
|
|
|
#[allow(non_snake_case)]
|
|
|
|
|
fn create_or_lookup_group(
|
|
|
|
|
context: &Context,
|
|
|
|
|
@@ -797,12 +793,8 @@ fn create_or_lookup_group(
|
|
|
|
|
allow_creation: i32,
|
|
|
|
|
create_blocked: Blocked,
|
|
|
|
|
from_id: u32,
|
|
|
|
|
to_ids: &mut Vec<u32>,
|
|
|
|
|
ret_chat_id: *mut u32,
|
|
|
|
|
ret_chat_id_blocked: &mut Blocked,
|
|
|
|
|
) -> Result<()> {
|
|
|
|
|
let group_explicitly_left: bool;
|
|
|
|
|
let mut chat_id = 0;
|
|
|
|
|
to_ids: &[u32],
|
|
|
|
|
) -> Result<(u32, Blocked)> {
|
|
|
|
|
let mut chat_id_blocked = Blocked::Not;
|
|
|
|
|
let mut grpid = "".to_string();
|
|
|
|
|
let mut grpname = None;
|
|
|
|
|
@@ -815,20 +807,6 @@ fn create_or_lookup_group(
|
|
|
|
|
let mut X_MrGrpImageChanged = "".to_string();
|
|
|
|
|
let mut better_msg: String = From::from("");
|
|
|
|
|
|
|
|
|
|
let cleanup = |ret_chat_id: *mut u32,
|
|
|
|
|
ret_chat_id_blocked: &mut Blocked,
|
|
|
|
|
chat_id: u32,
|
|
|
|
|
chat_id_blocked: Blocked| {
|
|
|
|
|
if !ret_chat_id.is_null() {
|
|
|
|
|
unsafe { *ret_chat_id = chat_id };
|
|
|
|
|
}
|
|
|
|
|
*ret_chat_id_blocked = if 0 != chat_id {
|
|
|
|
|
chat_id_blocked
|
|
|
|
|
} else {
|
|
|
|
|
Blocked::Not
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if mime_parser.is_system_message == SystemMessage::LocationStreamingEnabled {
|
|
|
|
|
better_msg =
|
|
|
|
|
context.stock_system_msg(StockMessage::MsgLocationEnabled, "", "", from_id as u32)
|
|
|
|
|
@@ -857,18 +835,18 @@ fn create_or_lookup_group(
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if grpid.is_empty() {
|
|
|
|
|
create_or_lookup_adhoc_group(
|
|
|
|
|
return create_or_lookup_adhoc_group(
|
|
|
|
|
context,
|
|
|
|
|
mime_parser,
|
|
|
|
|
allow_creation,
|
|
|
|
|
create_blocked,
|
|
|
|
|
from_id,
|
|
|
|
|
to_ids,
|
|
|
|
|
&mut chat_id,
|
|
|
|
|
&mut chat_id_blocked,
|
|
|
|
|
)?;
|
|
|
|
|
cleanup(ret_chat_id, ret_chat_id_blocked, chat_id, chat_id_blocked);
|
|
|
|
|
return Ok(());
|
|
|
|
|
)
|
|
|
|
|
.map_err(|err| {
|
|
|
|
|
info!(context, "could not create adhoc-group: {:?}", err);
|
|
|
|
|
err
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -948,26 +926,29 @@ fn create_or_lookup_group(
|
|
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
if chat_id != 0 && chat_id_verified {
|
|
|
|
|
if let Err(err) = check_verified_properties(context, mime_parser, from_id as u32, to_ids) {
|
|
|
|
|
warn!(context, "verification problem: {}", err);
|
|
|
|
|
let s = format!("{}. See 'Info' for more details", err);
|
|
|
|
|
mime_parser.repl_msg_by_error(s);
|
|
|
|
|
if chat_id != 0 {
|
|
|
|
|
if chat_id_verified {
|
|
|
|
|
if let Err(err) =
|
|
|
|
|
check_verified_properties(context, mime_parser, from_id as u32, to_ids)
|
|
|
|
|
{
|
|
|
|
|
warn!(context, "verification problem: {}", err);
|
|
|
|
|
let s = format!("{}. See 'Info' for more details", err);
|
|
|
|
|
mime_parser.repl_msg_by_error(s);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// check if the sender is a member of the existing group -
|
|
|
|
|
// if not, we'll recreate the group list
|
|
|
|
|
if !chat::is_contact_in_chat(context, chat_id, from_id as u32) {
|
|
|
|
|
recreate_member_list = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// check if the sender is a member of the existing group -
|
|
|
|
|
// if not, we'll recreate the group list
|
|
|
|
|
if chat_id != 0 && !chat::is_contact_in_chat(context, chat_id, from_id as u32) {
|
|
|
|
|
recreate_member_list = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// check if the group does not exist but should be created
|
|
|
|
|
group_explicitly_left = chat::is_group_explicitly_left(context, &grpid).unwrap_or_default();
|
|
|
|
|
|
|
|
|
|
let group_explicitly_left = chat::is_group_explicitly_left(context, &grpid).unwrap_or_default();
|
|
|
|
|
let self_addr = context
|
|
|
|
|
.get_config(Config::ConfiguredAddr)
|
|
|
|
|
.unwrap_or_default();
|
|
|
|
|
|
|
|
|
|
if chat_id == 0
|
|
|
|
|
&& !mime_parser.is_mailinglist_message()
|
|
|
|
|
&& !grpid.is_empty()
|
|
|
|
|
@@ -978,10 +959,8 @@ fn create_or_lookup_group(
|
|
|
|
|
&& (!group_explicitly_left
|
|
|
|
|
|| X_MrAddToGrp.is_some() && addr_cmp(&self_addr, X_MrAddToGrp.as_ref().unwrap()))
|
|
|
|
|
{
|
|
|
|
|
let mut create_verified = VerifiedStatus::Unverified;
|
|
|
|
|
if mime_parser.lookup_field("Chat-Verified").is_some() {
|
|
|
|
|
create_verified = VerifiedStatus::Verified;
|
|
|
|
|
|
|
|
|
|
// group does not exist but should be created
|
|
|
|
|
let create_verified = if mime_parser.lookup_field("Chat-Verified").is_some() {
|
|
|
|
|
if let Err(err) =
|
|
|
|
|
check_verified_properties(context, mime_parser, from_id as u32, to_ids)
|
|
|
|
|
{
|
|
|
|
|
@@ -989,11 +968,16 @@ fn create_or_lookup_group(
|
|
|
|
|
let s = format!("{}. See 'Info' for more details", err);
|
|
|
|
|
mime_parser.repl_msg_by_error(&s);
|
|
|
|
|
}
|
|
|
|
|
VerifiedStatus::Verified
|
|
|
|
|
} else {
|
|
|
|
|
VerifiedStatus::Unverified
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if allow_creation == 0 {
|
|
|
|
|
info!(context, "creating group forbidden by caller");
|
|
|
|
|
return Ok((0, Blocked::Not));
|
|
|
|
|
}
|
|
|
|
|
if 0 == allow_creation {
|
|
|
|
|
cleanup(ret_chat_id, ret_chat_id_blocked, chat_id, chat_id_blocked);
|
|
|
|
|
return Ok(());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
chat_id = create_group_record(
|
|
|
|
|
context,
|
|
|
|
|
&grpid,
|
|
|
|
|
@@ -1007,9 +991,8 @@ fn create_or_lookup_group(
|
|
|
|
|
|
|
|
|
|
// again, check chat_id
|
|
|
|
|
if chat_id <= DC_CHAT_ID_LAST_SPECIAL {
|
|
|
|
|
chat_id = 0;
|
|
|
|
|
if group_explicitly_left {
|
|
|
|
|
chat_id = DC_CHAT_ID_TRASH;
|
|
|
|
|
return if group_explicitly_left {
|
|
|
|
|
Ok((DC_CHAT_ID_TRASH, chat_id_blocked))
|
|
|
|
|
} else {
|
|
|
|
|
create_or_lookup_adhoc_group(
|
|
|
|
|
context,
|
|
|
|
|
@@ -1018,12 +1001,12 @@ fn create_or_lookup_group(
|
|
|
|
|
create_blocked,
|
|
|
|
|
from_id,
|
|
|
|
|
to_ids,
|
|
|
|
|
&mut chat_id,
|
|
|
|
|
&mut chat_id_blocked,
|
|
|
|
|
)?;
|
|
|
|
|
}
|
|
|
|
|
cleanup(ret_chat_id, ret_chat_id_blocked, chat_id, chat_id_blocked);
|
|
|
|
|
return Ok(());
|
|
|
|
|
)
|
|
|
|
|
.map_err(|err| {
|
|
|
|
|
warn!(context, "failed to create ad-hoc group: {:?}", err);
|
|
|
|
|
err
|
|
|
|
|
})
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// execute group commands
|
|
|
|
|
@@ -1128,74 +1111,64 @@ fn create_or_lookup_group(
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// check the number of receivers -
|
|
|
|
|
// the only critical situation is if the user hits "Reply" instead of "Reply all" in a non-messenger-client */
|
|
|
|
|
if to_ids_cnt == 1 && !mime_parser.is_send_by_messenger {
|
|
|
|
|
let is_contact_cnt = chat::get_chat_contact_cnt(context, chat_id);
|
|
|
|
|
if is_contact_cnt > 3 {
|
|
|
|
|
// to_ids_cnt==1 may be "From: A, To: B, SELF" as SELF is not counted in to_ids_cnt.
|
|
|
|
|
// So everything up to 3 is no error.
|
|
|
|
|
chat_id = 0;
|
|
|
|
|
create_or_lookup_adhoc_group(
|
|
|
|
|
context,
|
|
|
|
|
mime_parser,
|
|
|
|
|
allow_creation,
|
|
|
|
|
create_blocked,
|
|
|
|
|
from_id,
|
|
|
|
|
to_ids,
|
|
|
|
|
&mut chat_id,
|
|
|
|
|
&mut chat_id_blocked,
|
|
|
|
|
)?;
|
|
|
|
|
}
|
|
|
|
|
// the only critical situation is if the user hits "Reply" instead
|
|
|
|
|
// of "Reply all" in a non-messenger-client */
|
|
|
|
|
if to_ids_cnt == 1
|
|
|
|
|
&& !mime_parser.is_send_by_messenger
|
|
|
|
|
&& chat::get_chat_contact_cnt(context, chat_id) > 3
|
|
|
|
|
{
|
|
|
|
|
// to_ids_cnt==1 may be "From: A, To: B, SELF" as SELF is not counted in to_ids_cnt.
|
|
|
|
|
// So everything up to 3 is no error.
|
|
|
|
|
create_or_lookup_adhoc_group(
|
|
|
|
|
context,
|
|
|
|
|
mime_parser,
|
|
|
|
|
allow_creation,
|
|
|
|
|
create_blocked,
|
|
|
|
|
from_id,
|
|
|
|
|
to_ids,
|
|
|
|
|
)
|
|
|
|
|
.map_err(|err| {
|
|
|
|
|
warn!(context, "could not create ad-hoc group: {:?}", err);
|
|
|
|
|
err
|
|
|
|
|
})?;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cleanup(ret_chat_id, ret_chat_id_blocked, chat_id, chat_id_blocked);
|
|
|
|
|
Ok(())
|
|
|
|
|
Ok((chat_id, chat_id_blocked))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Handle groups for received messages
|
|
|
|
|
/// Handle groups for received messages, return chat_id/Blocked status on success
|
|
|
|
|
fn create_or_lookup_adhoc_group(
|
|
|
|
|
context: &Context,
|
|
|
|
|
mime_parser: &MimeParser,
|
|
|
|
|
allow_creation: i32,
|
|
|
|
|
create_blocked: Blocked,
|
|
|
|
|
from_id: u32,
|
|
|
|
|
to_ids: &mut Vec<u32>,
|
|
|
|
|
ret_chat_id: *mut u32,
|
|
|
|
|
ret_chat_id_blocked: &mut Blocked,
|
|
|
|
|
) -> Result<()> {
|
|
|
|
|
// if we're here, no grpid was found, check there is an existing ad-hoc
|
|
|
|
|
// group matching the to-list or if we can create one
|
|
|
|
|
let mut chat_id = 0;
|
|
|
|
|
let mut chat_id_blocked = Blocked::Not;
|
|
|
|
|
to_ids: &[u32],
|
|
|
|
|
) -> Result<(u32, 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)
|
|
|
|
|
|
|
|
|
|
let cleanup = |ret_chat_id: *mut u32,
|
|
|
|
|
ret_chat_id_blocked: &mut Blocked,
|
|
|
|
|
chat_id: u32,
|
|
|
|
|
chat_id_blocked: Blocked| {
|
|
|
|
|
if !ret_chat_id.is_null() {
|
|
|
|
|
unsafe { *ret_chat_id = chat_id };
|
|
|
|
|
}
|
|
|
|
|
*ret_chat_id_blocked = chat_id_blocked;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// build member list from the given ids
|
|
|
|
|
if to_ids.is_empty() || mime_parser.is_mailinglist_message() {
|
|
|
|
|
// too few contacts or a mailinglist
|
|
|
|
|
cleanup(ret_chat_id, ret_chat_id_blocked, chat_id, chat_id_blocked);
|
|
|
|
|
return Ok(());
|
|
|
|
|
if mime_parser.is_mailinglist_message() {
|
|
|
|
|
// XXX we could parse List-* headers and actually create and
|
|
|
|
|
// manage a mailing list group, eventually
|
|
|
|
|
info!(
|
|
|
|
|
context,
|
|
|
|
|
"not creating ad-hoc group for mailing list message"
|
|
|
|
|
);
|
|
|
|
|
return Ok((0, Blocked::Not));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let mut member_ids = to_ids.clone();
|
|
|
|
|
let mut member_ids = to_ids.to_vec();
|
|
|
|
|
if !member_ids.contains(&from_id) {
|
|
|
|
|
member_ids.push(from_id);
|
|
|
|
|
}
|
|
|
|
|
if !member_ids.contains(&DC_CONTACT_ID_SELF) {
|
|
|
|
|
member_ids.push(DC_CONTACT_ID_SELF);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if member_ids.len() < 3 {
|
|
|
|
|
// too few contacts given
|
|
|
|
|
cleanup(ret_chat_id, ret_chat_id_blocked, chat_id, chat_id_blocked);
|
|
|
|
|
return Ok(());
|
|
|
|
|
info!(context, "not creating ad-hoc group: too few contacts");
|
|
|
|
|
return Ok((0, Blocked::Not));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let chat_ids = search_chat_ids_by_contact_ids(context, &member_ids)?;
|
|
|
|
|
@@ -1214,18 +1187,16 @@ fn create_or_lookup_adhoc_group(
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if let Ok((id, id_blocked)) = res {
|
|
|
|
|
chat_id = id as u32;
|
|
|
|
|
chat_id_blocked = id_blocked;
|
|
|
|
|
/* success, chat found */
|
|
|
|
|
cleanup(ret_chat_id, ret_chat_id_blocked, chat_id, chat_id_blocked);
|
|
|
|
|
return Ok(());
|
|
|
|
|
return Ok((id as u32, id_blocked));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if 0 == allow_creation {
|
|
|
|
|
cleanup(ret_chat_id, ret_chat_id_blocked, chat_id, chat_id_blocked);
|
|
|
|
|
return Ok(());
|
|
|
|
|
if allow_creation == 0 {
|
|
|
|
|
info!(context, "creating ad-hoc group prevented from caller");
|
|
|
|
|
return Ok((0, Blocked::Not));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// we do not check if the message is a reply to another group, this may result in
|
|
|
|
|
// chats with unclear member list. instead we create a new group in the following lines ...
|
|
|
|
|
|
|
|
|
|
@@ -1233,10 +1204,12 @@ fn create_or_lookup_adhoc_group(
|
|
|
|
|
// - there is no need to check if this group exists; otherwise we would have caught it above
|
|
|
|
|
let grpid = create_adhoc_grp_id(context, &member_ids);
|
|
|
|
|
if grpid.is_empty() {
|
|
|
|
|
cleanup(ret_chat_id, ret_chat_id_blocked, chat_id, chat_id_blocked);
|
|
|
|
|
return Ok(());
|
|
|
|
|
warn!(
|
|
|
|
|
context,
|
|
|
|
|
"failed to create ad-hoc grpid for {:?}", member_ids
|
|
|
|
|
);
|
|
|
|
|
return Ok((0, Blocked::Not));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// use subject as initial chat name
|
|
|
|
|
let grpname = if let Some(subject) = mime_parser.subject.as_ref().filter(|s| !s.is_empty()) {
|
|
|
|
|
subject.to_string()
|
|
|
|
|
@@ -1245,22 +1218,20 @@ fn create_or_lookup_adhoc_group(
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// create group record
|
|
|
|
|
chat_id = create_group_record(
|
|
|
|
|
let new_chat_id = create_group_record(
|
|
|
|
|
context,
|
|
|
|
|
&grpid,
|
|
|
|
|
grpname,
|
|
|
|
|
create_blocked,
|
|
|
|
|
VerifiedStatus::Unverified,
|
|
|
|
|
);
|
|
|
|
|
chat_id_blocked = create_blocked;
|
|
|
|
|
for &member_id in &member_ids {
|
|
|
|
|
chat::add_to_chat_contacts_table(context, chat_id, member_id);
|
|
|
|
|
chat::add_to_chat_contacts_table(context, new_chat_id, member_id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
context.call_cb(Event::ChatModified(chat_id));
|
|
|
|
|
context.call_cb(Event::ChatModified(new_chat_id));
|
|
|
|
|
|
|
|
|
|
cleanup(ret_chat_id, ret_chat_id_blocked, chat_id, chat_id_blocked);
|
|
|
|
|
Ok(())
|
|
|
|
|
Ok((new_chat_id, create_blocked))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn create_group_record(
|
|
|
|
|
|