Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion deltachat-ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1748,7 +1748,7 @@ pub unsafe extern "C" fn dc_create_group_chat(
}
let ctx = &*context;

block_on(chat::create_group_chat(ctx, &to_string_lossy(name)))
block_on(chat::create_group(ctx, &to_string_lossy(name)))
.context("Failed to create group chat")
.log_err(ctx)
.map(|id| id.to_u32())
Expand Down
6 changes: 2 additions & 4 deletions deltachat-jsonrpc/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -969,9 +969,7 @@ impl CommandApi {
/// This may be useful if you want to show some help for just created groups.
async fn create_group_chat(&self, account_id: u32, name: String) -> Result<u32> {
let ctx = self.get_context(account_id).await?;
chat::create_group_chat(&ctx, &name)
.await
.map(|id| id.to_u32())
chat::create_group(&ctx, &name).await.map(|id| id.to_u32())
}

/// Create a new unencrypted group chat.
Expand All @@ -980,7 +978,7 @@ impl CommandApi {
/// address-contacts.
async fn create_group_chat_unencrypted(&self, account_id: u32, name: String) -> Result<u32> {
let ctx = self.get_context(account_id).await?;
chat::create_group_chat_unencrypted(&ctx, &name)
chat::create_group_unencrypted(&ctx, &name)
.await
.map(|id| id.to_u32())
}
Expand Down
2 changes: 1 addition & 1 deletion deltachat-repl/src/cmdline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -737,7 +737,7 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu
}
"creategroup" => {
ensure!(!arg1.is_empty(), "Argument <name> missing.");
let chat_id = chat::create_group_chat(&context, arg1).await?;
let chat_id = chat::create_group(&context, arg1).await?;

println!("Group#{chat_id} created successfully.");
}
Expand Down
74 changes: 42 additions & 32 deletions src/chat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ use crate::debug_logging::maybe_set_logging_xdc;
use crate::download::DownloadState;
use crate::ephemeral::{Timer as EphemeralTimer, start_chat_ephemeral_timers};
use crate::events::EventType;
use crate::key::self_fingerprint;
use crate::location;
use crate::log::{LogExt, error, info, warn};
use crate::logged_debug_assert;
Expand Down Expand Up @@ -2008,17 +2009,21 @@ impl Chat {
/// Sends a `SyncAction` synchronising chat contacts to other devices.
pub(crate) async fn sync_contacts(&self, context: &Context) -> Result<()> {
if self.is_encrypted(context).await? {
let self_fp = self_fingerprint(context).await?;
let fingerprint_addrs = context
.sql
.query_map(
"SELECT c.fingerprint, c.addr
"SELECT c.id, c.fingerprint, c.addr
FROM contacts c INNER JOIN chats_contacts cc
ON c.id=cc.contact_id
WHERE cc.chat_id=? AND cc.add_timestamp >= cc.remove_timestamp",
(self.id,),
|row| {
let fingerprint = row.get(0)?;
let addr = row.get(1)?;
if row.get::<_, ContactId>(0)? == ContactId::SELF {
return Ok((self_fp.to_string(), String::new()));
}
let fingerprint = row.get(1)?;
let addr = row.get(2)?;
Ok((fingerprint, addr))
},
|addrs| addrs.collect::<Result<Vec<_>, _>>().map_err(Into::into),
Expand Down Expand Up @@ -3433,25 +3438,28 @@ pub async fn get_past_chat_contacts(context: &Context, chat_id: ChatId) -> Resul
Ok(list)
}

/// Creates a group chat with a given `name`.
pub async fn create_group_chat(context: &Context, name: &str) -> Result<ChatId> {
let is_encrypted = true;
create_group_ex(context, is_encrypted, name).await
/// Creates an encrypted group chat.
pub async fn create_group(context: &Context, name: &str) -> Result<ChatId> {
let encryption = Some(create_id());
create_group_ex(context, Sync, encryption, name).await
}

/// Creates a new unencrypted group chat.
pub async fn create_group_chat_unencrypted(context: &Context, name: &str) -> Result<ChatId> {
let is_encrypted = false;
create_group_ex(context, is_encrypted, name).await
/// Creates an unencrypted group chat.
pub async fn create_group_unencrypted(context: &Context, name: &str) -> Result<ChatId> {
let encryption = None;
create_group_ex(context, Sync, encryption, name).await
}

/// Creates a group chat.
///
/// * `is_encrypted` - If true, the chat is encrypted (with key-contacts).
/// * `sync` - Whether a multi-device synchronization message should be sent. Ignored for
/// unencrypted chats currently.
/// * `encryption` - If `Some(grpid)`, the chat is encrypted (with key-contacts).
/// * `name` - Chat name.
pub(crate) async fn create_group_ex(
context: &Context,
is_encrypted: bool,
sync: sync::Sync,
encryption: Option<String>,
name: &str,
) -> Result<ChatId> {
let mut chat_name = sanitize_single_line(name);
Expand All @@ -3462,20 +3470,15 @@ pub(crate) async fn create_group_ex(
chat_name = "…".to_string();
}

let grpid = if is_encrypted {
create_id()
} else {
String::new()
};

let grpid = encryption.unwrap_or_default();
let timestamp = create_smeared_timestamp(context);
let row_id = context
.sql
.insert(
"INSERT INTO chats
(type, name, grpid, param, created_timestamp)
VALUES(?, ?, ?, \'U=1\', ?);",
(Chattype::Group, chat_name, grpid, timestamp),
(Chattype::Group, &chat_name, &grpid, timestamp),
)
.await?;

Expand All @@ -3486,7 +3489,7 @@ pub(crate) async fn create_group_ex(
chatlist_events::emit_chatlist_changed(context);
chatlist_events::emit_chatlist_item_changed(context, chat_id);

if is_encrypted {
if !grpid.is_empty() {
// Add "Messages are end-to-end encrypted." message.
chat_id.add_encrypted_msg(context, timestamp).await?;
}
Expand All @@ -3497,7 +3500,11 @@ pub(crate) async fn create_group_ex(
let text = stock_str::new_group_send_first_message(context).await;
add_info_msg(context, chat_id, &text, create_smeared_timestamp(context)).await?;
}

if let (true, true) = (sync.into(), !grpid.is_empty()) {
let id = SyncId::Grpid(grpid);
let action = SyncAction::CreateGroupEncrypted(chat_name);
self::sync(context, id, action).await.log_err(context).ok();
}
Ok(chat_id)
}

Expand All @@ -3513,7 +3520,7 @@ pub(crate) async fn create_group_ex(
/// which would make it hard to grep for it.
///
/// After creation, the chat contains no recipients and is in _unpromoted_ state;
/// see [`create_group_chat`] for more information on the unpromoted state.
/// see [`create_group`] for more information on the unpromoted state.
///
/// Returns the created chat's id.
pub async fn create_broadcast(context: &Context, chat_name: String) -> Result<ChatId> {
Expand Down Expand Up @@ -4706,16 +4713,14 @@ async fn set_contacts_by_fingerprints(
"Cannot add key-contacts to unencrypted chat {id}"
);
ensure!(
chat.typ == Chattype::OutBroadcast,
"{id} is not a broadcast list",
matches!(chat.typ, Chattype::Group | Chattype::OutBroadcast),
"{id} is not a group or broadcast",
);
let mut contacts = HashSet::new();
for (fingerprint, addr) in fingerprint_addrs {
let contact_addr = ContactAddress::new(addr)?;
let contact =
Contact::add_or_lookup_ex(context, "", &contact_addr, fingerprint, Origin::Hidden)
.await?
.0;
let contact = Contact::add_or_lookup_ex(context, "", addr, fingerprint, Origin::Hidden)
.await?
.0;
contacts.insert(contact);
}
let contacts_old = HashSet::<ContactId>::from_iter(get_chat_contacts(context, id).await?);
Expand Down Expand Up @@ -4754,7 +4759,7 @@ pub(crate) enum SyncId {
/// "Message-ID"-s, from oldest to latest. Used for ad-hoc groups.
Msgids(Vec<String>),

// Special id for device chat.
/// Special id for device chat.
Device,
}

Expand All @@ -4768,6 +4773,8 @@ pub(crate) enum SyncAction {
SetMuted(MuteDuration),
/// Create broadcast channel with the given name.
CreateBroadcast(String),
/// Create encrypted group chat with the given name.
CreateGroupEncrypted(String),
Rename(String),
/// Set chat contacts by their addresses.
SetContacts(Vec<String>),
Expand Down Expand Up @@ -4833,6 +4840,9 @@ impl Context {
if let SyncAction::CreateBroadcast(name) = action {
create_broadcast_ex(self, Nosync, grpid.clone(), name.clone()).await?;
return Ok(());
} else if let SyncAction::CreateGroupEncrypted(name) = action {
create_group_ex(self, Nosync, Some(grpid.clone()), name).await?;
return Ok(());
}
get_chat_id_by_grpid(self, grpid)
.await?
Expand All @@ -4854,7 +4864,7 @@ impl Context {
SyncAction::Accept => chat_id.accept_ex(self, Nosync).await,
SyncAction::SetVisibility(v) => chat_id.set_visibility_ex(self, Nosync, *v).await,
SyncAction::SetMuted(duration) => set_muted_ex(self, Nosync, chat_id, *duration).await,
SyncAction::CreateBroadcast(_) => {
SyncAction::CreateBroadcast(_) | SyncAction::CreateGroupEncrypted(..) => {
Err(anyhow!("sync_alter_chat({id:?}, {action:?}): Bad request."))
}
SyncAction::Rename(to) => rename_ex(self, Nosync, chat_id, to).await,
Expand Down
Loading
Loading