Compare commits

..

2 Commits

Author SHA1 Message Date
holger krekel
3a602ee313 fix ffi 2019-09-09 18:43:03 +02:00
Alexander Krotov
e0c1b91a7a Make dc_msg_get_filemime safe 2019-09-09 18:34:25 +03:00
13 changed files with 224 additions and 269 deletions

View File

@@ -898,15 +898,9 @@ pub unsafe extern "C" fn dc_set_chat_profile_image(
let context = &*context;
chat::set_chat_profile_image(context, chat_id, {
if image.is_null() {
""
} else {
as_str(image)
}
})
.map(|_| 1)
.unwrap_or_log_default(context, "Failed to set profile image")
chat::set_chat_profile_image(context, chat_id, as_str(image))
.map(|_| 1)
.unwrap_or_log_default(context, "Failed to set profile image")
}
#[no_mangle]
@@ -1786,7 +1780,7 @@ pub unsafe extern "C" fn dc_chat_get_profile_image(chat: *mut dc_chat_t) -> *mut
let chat = &*chat;
match chat.get_profile_image() {
Some(p) => p.to_str().unwrap().to_string().strdup(),
Some(i) => i.strdup(),
None => ptr::null_mut(),
}
}
@@ -2403,7 +2397,7 @@ pub unsafe extern "C" fn dc_contact_get_profile_image(
contact
.get_profile_image()
.map(|p| p.to_str().unwrap().to_string().strdup())
.map(|s| s.strdup())
.unwrap_or_else(|| std::ptr::null_mut())
}

View File

@@ -483,10 +483,6 @@ class EventLogger:
def set_timeout(self, timeout):
self._timeout = timeout
def consume_events(self, check_error=True):
while not self._event_queue.empty():
self.get()
def get(self, timeout=None, check_error=True):
timeout = timeout or self._timeout
ev = self._event_queue.get(timeout=timeout)

View File

@@ -1,7 +1,6 @@
""" chatting related objects: Contact, Chat, Message. """
import mimetypes
import os
from . import props
from .cutil import as_dc_charpointer, from_dc_charpointer, iter_array
from .capi import lib, ffi
@@ -316,46 +315,3 @@ class Chat(object):
return list(iter_array(
dc_array, lambda id: Contact(self._dc_context, id))
)
def set_profile_image(self, img_path):
"""Set group profile image.
If the group is already promoted (any message was sent to the group),
all group members are informed by a special status message that is sent
automatically by this function.
:params img_path: path to image object
:raises ValueError: if profile image could not be set
:returns: None
"""
assert os.path.exists(img_path), img_path
p = as_dc_charpointer(img_path)
res = lib.dc_set_chat_profile_image(self._dc_context, self.id, p)
if res != 1:
raise ValueError("Setting Profile Image {!r} failed".format(p))
def remove_profile_image(self):
"""remove group profile image.
If the group is already promoted (any message was sent to the group),
all group members are informed by a special status message that is sent
automatically by this function.
:raises ValueError: if profile image could not be reset
:returns: None
"""
res = lib.dc_set_chat_profile_image(self._dc_context, self.id, ffi.NULL)
if res != 1:
raise ValueError("Removing Profile Image failed")
def get_profile_image(self):
"""Get group profile image.
For groups, this is the image set by any group member using
set_chat_profile_image(). For normal chats, this is the image
set by each remote user on their own using dc_set_config(context,
"selfavatar", image).
:returns: path to profile image, None if no profile image exists.
"""
dc_res = lib.dc_chat_get_profile_image(self._dc_chat)
if dc_res == ffi.NULL:
return None
return from_dc_charpointer(dc_res)

View File

@@ -147,15 +147,6 @@ class TestOfflineChat:
qr = chat.get_join_qr()
assert ac2.check_qr(qr).is_ask_verifygroup
def test_get_set_profile_image_simple(self, ac1, data):
chat = ac1.create_group_chat(name="title1")
p = data.get_path("d.png")
chat.set_profile_image(p)
p2 = chat.get_profile_image()
assert open(p, "rb").read() == open(p2, "rb").read()
chat.remove_profile_image()
assert chat.get_profile_image() is None
def test_delete_and_send_fails(self, ac1, chat1):
chat1.delete()
ac1._evlogger.get_matching("DC_EVENT_MSGS_CHANGED")
@@ -598,59 +589,3 @@ class TestOnlineAccount:
ch = ac2.qr_join_chat(qr)
assert ch.id >= 10
wait_securejoin_inviter_progress(ac1, 1000)
def test_set_get_profile_image(self, acfactory, data, lp):
ac1 = acfactory.get_online_configuring_account()
ac2 = acfactory.get_online_configuring_account()
wait_configuration_progress(ac2, 1000)
wait_configuration_progress(ac1, 1000)
lp.sec("create unpromoted group chat")
chat = ac1.create_group_chat("hello")
p = data.get_path("d.png")
lp.sec("ac1: set profile image on unpromoted chat")
chat.set_profile_image(p)
ac1._evlogger.get_matching("DC_EVENT_CHAT_MODIFIED")
assert not chat.is_promoted()
lp.sec("ac1: send text to promote chat (XXX without contact added)")
# XXX first promote the chat before adding contact
# because DC does not send out profile images for unpromoted chats
# otherwise
chat.send_text("ac1: initial message to promote chat (workaround)")
assert chat.is_promoted()
lp.sec("ac2: add ac1 to a chat so the message does not land in DEADDROP")
c1 = ac2.create_contact(email=ac1.get_config("addr"))
ac2.create_chat_by_contact(c1)
ev = ac2._evlogger.get_matching("DC_EVENT_MSGS_CHANGED")
lp.sec("ac1: add ac2 to promoted group chat")
c2 = ac1.create_contact(email=ac2.get_config("addr"))
chat.add_contact(c2)
lp.sec("ac1: send a first message to ac2")
chat.send_text("hi")
assert chat.is_promoted()
lp.sec("ac2: wait for receiving message from ac1")
ev = ac2._evlogger.get_matching("DC_EVENT_INCOMING_MSG")
msg_in = ac2.get_message_by_id(ev[2])
assert not msg_in.chat.is_deaddrop()
lp.sec("ac2: create chat and read profile image")
chat2 = ac2.create_chat_by_message(msg_in)
p2 = chat2.get_profile_image()
assert p2 is not None
assert open(p2, "rb").read() == open(p, "rb").read()
ac2._evlogger.consume_events()
ac1._evlogger.consume_events()
lp.sec("ac2: delete profile image from chat")
chat2.remove_profile_image()
ev = ac1._evlogger.get_matching("DC_EVENT_INCOMING_MSG")
assert ev[1] == chat.id
chat1b = ac1.create_chat_by_message(ev[2])
assert chat1b.get_profile_image() is None
assert chat.get_profile_image() is None

View File

@@ -1,5 +1,5 @@
use std::ffi::CString;
use std::path::{Path, PathBuf};
use std::path::Path;
use crate::chatlist::*;
use crate::constants::*;
@@ -72,15 +72,15 @@ impl<'a> Chat<'a> {
},
Ok(mut chat) => {
match chat.id {
DC_CHAT_ID_DEADDROP => {
1 => {
chat.name = chat.context.stock_str(StockMessage::DeadDrop).into();
}
DC_CHAT_ID_ARCHIVED_LINK => {
6 => {
let tempname = chat.context.stock_str(StockMessage::ArchivedChats);
let cnt = dc_get_archived_cnt(chat.context);
chat.name = format!("{} ({})", tempname, cnt);
}
DC_CHAT_ID_STARRED => {
5 => {
chat.name = chat.context.stock_str(StockMessage::StarredMsgs).into();
}
_ => {
@@ -187,10 +187,10 @@ impl<'a> Chat<'a> {
.ok()
}
pub fn get_profile_image(&self) -> Option<PathBuf> {
pub unsafe fn get_profile_image(&self) -> Option<String> {
if let Some(image_rel) = self.param.get(Param::ProfileImage) {
if !image_rel.is_empty() {
return Some(dc_get_abs_path_safe(self.context, image_rel));
return Some(to_string(dc_get_abs_path(self.context, image_rel)));
}
} else if self.typ == Chattype::Single {
let contacts = get_chat_contacts(self.context, self.id);
@@ -229,10 +229,6 @@ impl<'a> Chat<'a> {
self.param.get_int(Param::Unpromoted).unwrap_or_default() == 1
}
pub fn is_promoted(&self) -> bool {
!self.is_unpromoted()
}
pub fn is_verified(&self) -> bool {
(self.typ == Chattype::VerifiedGroup)
}
@@ -1486,10 +1482,7 @@ pub unsafe fn remove_contact_from_chat(
"bad chat_id = {} <= 9",
chat_id
);
ensure!(
contact_id > DC_CONTACT_ID_LAST_SPECIAL || contact_id == DC_CONTACT_ID_SELF,
"Cannot remove special contact"
);
ensure!(contact_id != DC_CONTACT_ID_SELF, "Cannot remove self");
let mut msg = dc_msg_new_untyped(context);
let mut success = false;
@@ -1508,7 +1501,7 @@ pub unsafe fn remove_contact_from_chat(
} else {
/* we should respect this - whatever we send to the group, it gets discarded anyway! */
if let Ok(contact) = Contact::get_by_id(context, contact_id) {
if chat.is_promoted() {
if chat.param.get_int(Param::Unpromoted).unwrap_or_default() == 0 {
msg.type_0 = Viewtype::Text;
if contact.id == DC_CONTACT_ID_SELF {
set_group_explicitly_left(context, chat.grpid).unwrap();
@@ -1616,7 +1609,7 @@ pub unsafe fn set_chat_name(
)
.is_ok()
{
if chat.is_promoted() {
if chat.param.get_int(Param::Unpromoted).unwrap_or_default() == 0 {
msg.type_0 = Viewtype::Text;
msg.text = Some(context.stock_system_msg(
StockMessage::MsgGrpName,
@@ -1653,62 +1646,83 @@ pub unsafe fn set_chat_name(
}
#[allow(non_snake_case)]
pub fn set_chat_profile_image(
pub unsafe fn set_chat_profile_image(
context: &Context,
chat_id: u32,
new_image: impl AsRef<str>, // XXX use PathBuf
new_image: impl AsRef<str>,
) -> Result<(), Error> {
ensure!(chat_id > DC_CHAT_ID_LAST_SPECIAL, "Invalid chat ID");
let mut OK_TO_CONTINUE = true;
let mut success = false;
let mut chat = Chat::load_from_db(context, chat_id)?;
let mut msg = dc_msg_new_untyped(context);
let mut new_image_rel = None;
if real_group_exists(context, chat_id) {
/* we should respect this - whatever we send to the group, it gets discarded anyway! */
if !(is_contact_in_chat(context, chat_id, DC_CONTACT_ID_SELF) == 1i32) {
if !(is_contact_in_chat(context, chat_id, 1i32 as u32) == 1i32) {
log_event!(
context,
Event::ERROR_SELF_NOT_IN_GROUP,
0,
"Cannot set chat profile image; self not in group.",
);
bail!("Failed to set profile image");
}
let mut new_image_rel: String;
if !new_image.as_ref().is_empty() {
new_image_rel = new_image.as_ref().to_string();
if !dc_make_rel_and_copy(context, &mut new_image_rel) {
bail!("Failed to get relative path for profile image");
}
} else {
new_image_rel = "".to_string();
}
chat.param.set(Param::ProfileImage, &new_image_rel);
if chat.update_param().is_ok() {
if chat.is_promoted() {
let mut msg = unsafe { dc_msg_new_untyped(context) };
msg.param.set_int(Param::Cmd, DC_CMD_GROUPIMAGE_CHANGED);
msg.type_0 = Viewtype::Text;
msg.text = Some(context.stock_system_msg(
if new_image_rel == "" {
msg.param.remove(Param::Arg);
StockMessage::MsgGrpImgDeleted
} else {
msg.param.set(Param::Arg, &new_image_rel);
StockMessage::MsgGrpImgChanged
},
"",
"",
DC_CONTACT_ID_SELF,
));
msg.id = send_msg(context, chat_id, &mut msg).unwrap_or_default();
emit_event!(context, Event::MSGS_CHANGED, chat_id, msg.id);
/* we should respect this - whatever we send to the group, it gets discarded anyway! */
if !new_image.as_ref().is_empty() {
let mut img = new_image.as_ref().to_string();
if !dc_make_rel_and_copy(context, &mut img) {
OK_TO_CONTINUE = false;
}
new_image_rel = Some(img);
} else {
OK_TO_CONTINUE = false;
}
}
if OK_TO_CONTINUE {
if let Some(ref new_image_rel) = new_image_rel {
chat.param.set(Param::ProfileImage, new_image_rel);
}
if chat.update_param().is_ok() {
if chat.param.get_int(Param::Unpromoted).unwrap_or_default() == 0 {
msg.param.set_int(Param::Cmd, 3);
if let Some(ref new_image_rel) = new_image_rel {
msg.param.set(Param::Arg, new_image_rel);
}
msg.type_0 = Viewtype::Text;
msg.text = Some(context.stock_system_msg(
if new_image_rel.is_some() {
StockMessage::MsgGrpImgChanged
} else {
StockMessage::MsgGrpImgDeleted
},
"",
"",
DC_CONTACT_ID_SELF,
));
msg.id = send_msg(context, chat_id, &mut msg).unwrap_or_default();
context.call_cb(
Event::MSGS_CHANGED,
chat_id as uintptr_t,
msg.id as uintptr_t,
);
}
context.call_cb(
Event::CHAT_MODIFIED,
chat_id as uintptr_t,
0i32 as uintptr_t,
);
success = true;
}
emit_event!(context, Event::CHAT_MODIFIED, chat_id, 0);
return Ok(());
}
}
bail!("Failed to set profile image");
if !success {
bail!("Failed to set profile image");
}
Ok(())
}
pub unsafe fn forward_msgs(

View File

@@ -77,7 +77,7 @@ pub const DC_CHAT_ID_TRASH: u32 = 3;
/// a message is just in creation but not yet assigned to a chat (eg. we may need the message ID to set up blobs; this avoids unready message to be sent and shown)
const DC_CHAT_ID_MSGS_IN_CREATION: u32 = 4;
/// virtual chat showing all messages flagged with msgs.starred=2
pub const DC_CHAT_ID_STARRED: u32 = 5;
const DC_CHAT_ID_STARRED: u32 = 5;
/// only an indicator in a chatlist
pub const DC_CHAT_ID_ARCHIVED_LINK: u32 = 6;
/// only an indicator in a chatlist
@@ -557,6 +557,6 @@ pub const DC_CMD_GROUPIMAGE_CHANGED: libc::c_int = 3;
pub const DC_CMD_MEMBER_ADDED_TO_GROUP: libc::c_int = 4;
pub const DC_CMD_MEMBER_REMOVED_FROM_GROUP: libc::c_int = 5;
pub const DC_CMD_AUTOCRYPT_SETUP_MESSAGE: libc::c_int = 6;
pub const DC_CMD_SECUREJOIN_MESSAGE: libc::c_int = 7;
const DC_CMD_SECUREJOIN_MESSAGE: libc::c_int = 7;
pub const DC_CMD_LOCATION_STREAMING_ENABLED: libc::c_int = 8;
pub const DC_CMD_LOCATION_ONLY: libc::c_int = 9;
const DC_CMD_LOCATION_ONLY: libc::c_int = 9;

View File

@@ -1,7 +1,6 @@
use deltachat_derive::*;
use itertools::Itertools;
use rusqlite;
use std::path::PathBuf;
use crate::aheader::EncryptPreference;
use crate::config::Config;
@@ -767,11 +766,9 @@ impl<'a> Contact<'a> {
/// Get the contact's profile image.
/// This is the image set by each remote user on their own
/// using dc_set_config(context, "selfavatar", image).
pub fn get_profile_image(&self) -> Option<PathBuf> {
pub fn get_profile_image(&self) -> Option<String> {
if self.id == DC_CONTACT_ID_SELF {
if let Some(p) = self.context.get_config(Config::Selfavatar) {
return Some(PathBuf::from(p));
}
return self.context.get_config(Config::Selfavatar);
}
// TODO: else get image_abs from contact param
None

View File

@@ -211,8 +211,12 @@ pub fn dc_render_setup_file(context: &Context, passphrase: &str) -> Result<Strin
let encr = {
let private_key_asc_c = CString::yolo(private_key_asc);
let passphrase_c = CString::yolo(passphrase);
dc_pgp_symm_encrypt(passphrase_c.as_ptr(), private_key_asc_c.as_bytes())
.ok_or(format_err!("Failed to encrypt private key."))?
dc_pgp_symm_encrypt(
passphrase_c.as_ptr(),
private_key_asc_c.as_ptr() as *const libc::c_void,
private_key_asc_c.as_bytes().len(),
)
.ok_or(format_err!("Failed to encrypt private key."))?
};
let replacement = format!(
concat!(
@@ -445,10 +449,9 @@ pub unsafe fn dc_decrypt_setup_file(
|| binary_bytes == 0)
{
/* decrypt symmetrically */
if let Some(plain) = dc_pgp_symm_decrypt(
passphrase,
std::slice::from_raw_parts(binary as *const u8, binary_bytes),
) {
if let Some(plain) =
dc_pgp_symm_decrypt(passphrase, binary as *const libc::c_void, binary_bytes)
{
let payload_c = CString::new(plain).unwrap();
payload = strdup(payload_c.as_ptr());
}

View File

@@ -548,7 +548,7 @@ pub unsafe fn dc_mimefactory_render(factory: &mut dc_mimefactory_t) -> libc::c_i
dc_encode_header_words(name.as_ptr()),
),
);
if command == DC_CMD_MEMBER_REMOVED_FROM_GROUP {
if command == 5 {
let email_to_remove = factory
.msg
.param
@@ -567,7 +567,7 @@ pub unsafe fn dc_mimefactory_render(factory: &mut dc_mimefactory_t) -> libc::c_i
),
);
}
} else if command == DC_CMD_MEMBER_ADDED_TO_GROUP {
} else if command == 4 {
let msg = &factory.msg;
do_gossip = 1;
let email_to_add = msg.param.get(Param::Arg).unwrap_or_default().strdup();
@@ -599,7 +599,7 @@ pub unsafe fn dc_mimefactory_render(factory: &mut dc_mimefactory_t) -> libc::c_i
),
);
}
} else if command == DC_CMD_GROUPNAME_CHANGED {
} else if command == 2 {
let msg = &factory.msg;
let value_to_add = msg.param.get(Param::Arg).unwrap_or_default().strdup();
@@ -612,7 +612,7 @@ pub unsafe fn dc_mimefactory_render(factory: &mut dc_mimefactory_t) -> libc::c_i
value_to_add,
),
);
} else if command == DC_CMD_GROUPIMAGE_CHANGED {
} else if command == 3 {
let msg = &factory.msg;
grpimage = msg.param.get(Param::Arg);
if grpimage.is_none() {
@@ -626,7 +626,7 @@ pub unsafe fn dc_mimefactory_render(factory: &mut dc_mimefactory_t) -> libc::c_i
}
}
}
if command == DC_CMD_LOCATION_STREAMING_ENABLED {
if command == 8 {
mailimf_fields_add(
imf_fields,
mailimf_field_new_custom(
@@ -637,7 +637,7 @@ pub unsafe fn dc_mimefactory_render(factory: &mut dc_mimefactory_t) -> libc::c_i
),
);
}
if command == DC_CMD_AUTOCRYPT_SETUP_MESSAGE {
if command == 6 {
mailimf_fields_add(
imf_fields,
mailimf_field_new_custom(
@@ -650,7 +650,7 @@ pub unsafe fn dc_mimefactory_render(factory: &mut dc_mimefactory_t) -> libc::c_i
.stock_str(StockMessage::AcSetupMsgBody)
.strdup();
}
if command == DC_CMD_SECUREJOIN_MESSAGE {
if command == 7 {
let msg = &factory.msg;
let step = msg.param.get(Param::Arg).unwrap_or_default().strdup();
if strlen(step) > 0 {
@@ -726,7 +726,6 @@ pub unsafe fn dc_mimefactory_render(factory: &mut dc_mimefactory_t) -> libc::c_i
}
}
if let Some(grpimage) = grpimage {
info!(factory.context, 0, "setting group image '{}'", grpimage);
let mut meta = dc_msg_new_untyped(factory.context);
meta.type_0 = Viewtype::Image;
meta.param.set(Param::File, grpimage);
@@ -1084,7 +1083,7 @@ unsafe fn get_subject(
} else {
b"\x00" as *const u8 as *const libc::c_char
};
if msg.param.get_int(Param::Cmd).unwrap_or_default() == DC_CMD_AUTOCRYPT_SETUP_MESSAGE {
if msg.param.get_int(Param::Cmd).unwrap_or_default() == 6 {
ret = context.stock_str(StockMessage::AcSetupMsgSubject).strdup()
} else if chat.typ == Chattype::Group || chat.typ == Chattype::VerifiedGroup {
ret = format!(

View File

@@ -923,7 +923,7 @@ unsafe fn handle_reports(
}
}
fn save_locations(
unsafe fn save_locations(
context: &Context,
mime_parser: &dc_mimeparser_t,
chat_id: u32,
@@ -1049,7 +1049,7 @@ unsafe fn create_or_lookup_group(
// pointer somewhere into mime_parser, must not be freed
let mut X_MrAddToGrp = std::ptr::null_mut();
let mut X_MrGrpNameChanged = 0;
let mut X_MrGrpImageChanged = "".to_string();
let mut X_MrGrpImageChanged = std::ptr::null();
let mut better_msg: String = From::from("");
let mut failure_reason = std::ptr::null_mut();
@@ -1078,6 +1078,7 @@ unsafe fn create_or_lookup_group(
}
set_better_msg(mime_parser, &better_msg);
// search the grpid in the header
let optional_field = dc_mimeparser_lookup_optional_field(mime_parser, "Chat-Group-ID");
if !optional_field.is_null() {
grpid = to_string((*optional_field).fld_value)
@@ -1172,8 +1173,7 @@ unsafe fn create_or_lookup_group(
let optional_field =
dc_mimeparser_lookup_optional_field(mime_parser, "Chat-Group-Image");
if !optional_field.is_null() {
// fld_value is a pointer somewhere into mime_parser, must not be freed
X_MrGrpImageChanged = as_str((*optional_field).fld_value).to_string();
X_MrGrpImageChanged = (*optional_field).fld_value
}
better_msg = context.stock_system_msg(
StockMessage::MsgAddMember,
@@ -1197,11 +1197,14 @@ unsafe fn create_or_lookup_group(
let optional_field =
dc_mimeparser_lookup_optional_field(mime_parser, "Chat-Group-Image");
if !optional_field.is_null() {
// fld_value is a pointer somewhere into mime_parser, must not be freed
X_MrGrpImageChanged = as_str((*optional_field).fld_value).to_string();
X_MrGrpImageChanged = (*optional_field).fld_value;
mime_parser.is_system_message = DC_CMD_GROUPIMAGE_CHANGED;
better_msg = context.stock_system_msg(
if X_MrGrpImageChanged == "0" {
if strcmp(
X_MrGrpImageChanged,
b"0\x00" as *const u8 as *const libc::c_char,
) == 0
{
StockMessage::MsgGrpImgDeleted
} else {
StockMessage::MsgGrpImgChanged
@@ -1316,7 +1319,6 @@ unsafe fn create_or_lookup_group(
if !X_MrAddToGrp.is_null() || !X_MrRemoveFromGrp.is_null() {
recreate_member_list = 1;
} else if 0 != X_MrGrpNameChanged && !grpname.is_null() && strlen(grpname) < 200 {
info!(context, 0, "updating grpname for chat {}", chat_id);
if sql::execute(
context,
&context.sql,
@@ -1328,39 +1330,49 @@ unsafe fn create_or_lookup_group(
context.call_cb(Event::CHAT_MODIFIED, chat_id as uintptr_t, 0);
}
}
if !X_MrGrpImageChanged.is_empty() {
info!(
context,
0, "grp-image-change {} chat {}", X_MrGrpImageChanged, chat_id
);
let mut changed = false;
let mut grpimage = "".to_string();
if X_MrGrpImageChanged == "0" {
changed = true;
if !X_MrGrpImageChanged.is_null() {
let mut ok = 0;
let mut grpimage = ptr::null_mut();
if strcmp(
X_MrGrpImageChanged,
b"0\x00" as *const u8 as *const libc::c_char,
) == 0
{
ok = 1
} else {
for part in &mut mime_parser.parts {
if part.type_0 == Viewtype::Image {
grpimage = part
.param
.get(Param::File)
.map(|s| s.to_string())
.unwrap_or_else(|| "".to_string());
info!(context, 0, "found image {:?}", grpimage);
changed = true;
.map(|s| s.strdup())
.unwrap_or_else(|| std::ptr::null_mut());
ok = 1
}
}
}
if changed {
info!(context, 0, "New group image set to '{}'.", grpimage);
if 0 != ok {
info!(
context,
0,
"New group image set to {}.",
if !grpimage.is_null() {
"DELETED".to_string()
} else {
to_string(grpimage)
},
);
if let Ok(mut chat) = Chat::load_from_db(context, chat_id) {
if grpimage.is_empty() {
if grpimage.is_null() {
chat.param.remove(Param::ProfileImage);
} else {
chat.param.set(Param::ProfileImage, grpimage);
chat.param.set(Param::ProfileImage, as_str(grpimage));
}
chat.update_param().unwrap();
send_EVENT_CHAT_MODIFIED = 1;
}
free(grpimage as *mut libc::c_void);
}
}
@@ -1669,7 +1681,10 @@ fn hex_hash(s: impl AsRef<str>) -> String {
}
#[allow(non_snake_case)]
fn search_chat_ids_by_contact_ids(context: &Context, unsorted_contact_ids: &Vec<u32>) -> Vec<u32> {
unsafe fn search_chat_ids_by_contact_ids(
context: &Context,
unsorted_contact_ids: &Vec<u32>,
) -> Vec<u32> {
/* 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);
@@ -1686,13 +1701,7 @@ fn search_chat_ids_by_contact_ids(context: &Context, unsorted_contact_ids: &Vec<
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;",
"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;",
contact_ids_str
),
params![],
@@ -1704,15 +1713,15 @@ fn search_chat_ids_by_contact_ids(context: &Context, unsorted_contact_ids: &Vec<
for row in rows {
let (chat_id, contact_id) = row?;
if chat_id != last_chat_id {
if chat_id as u32 != last_chat_id {
if matches == contact_ids.len() && mismatches == 0 {
chat_ids.push(last_chat_id);
}
last_chat_id = chat_id;
last_chat_id = chat_id as u32;
matches = 0;
mismatches = 0;
}
if matches < contact_ids.len() && contact_id == contact_ids[matches] {
if contact_id == contact_ids[matches] {
matches += 1;
} else {
mismatches += 1;

View File

@@ -299,10 +299,8 @@ impl E2eeHelper {
ok_to_continue = false;
} else {
if let Some(ctext_v) = dc_pgp_pk_encrypt(
std::slice::from_raw_parts(
(*plain).str_0 as *const u8,
(*plain).len,
),
(*plain).str_0 as *const libc::c_void,
(*plain).len,
&keyring,
sign_key.as_ref(),
) {
@@ -909,7 +907,8 @@ unsafe fn decrypt_part(
/*if we already have fingerprints, do not add more; this ensures, only the fingerprints from the outer-most part are collected */
if let Some(plain) = dc_pgp_pk_decrypt(
std::slice::from_raw_parts(decoded_data as *const u8, decoded_data_bytes),
decoded_data as *const libc::c_void,
decoded_data_bytes,
&private_keyring,
&public_keyring_for_validate,
add_signatures,

View File

@@ -188,11 +188,15 @@ pub fn dc_pgp_create_keypair(addr: impl AsRef<str>) -> Option<(Key, Key)> {
}
pub fn dc_pgp_pk_encrypt(
plain: &[u8],
plain_text: *const libc::c_void,
plain_bytes: size_t,
public_keys_for_encryption: &Keyring,
private_key_for_signing: Option<&Key>,
) -> Option<String> {
let lit_msg = Message::new_literal_bytes("", plain);
assert!(!plain_text.is_null() && !plain_bytes > 0, "invalid input");
let bytes = unsafe { std::slice::from_raw_parts(plain_text as *const u8, plain_bytes) };
let lit_msg = Message::new_literal_bytes("", bytes);
let pkeys: Vec<&SignedPublicKey> = public_keys_for_encryption
.keys()
.into_iter()
@@ -223,11 +227,16 @@ pub fn dc_pgp_pk_encrypt(
}
pub fn dc_pgp_pk_decrypt(
ctext: &[u8],
ctext: *const libc::c_void,
ctext_bytes: size_t,
private_keys_for_decryption: &Keyring,
public_keys_for_validation: &Keyring,
ret_signature_fingerprints: Option<&mut HashSet<String>>,
) -> Option<Vec<u8>> {
assert!(!ctext.is_null() && ctext_bytes > 0, "invalid input");
let ctext = unsafe { std::slice::from_raw_parts(ctext as *const u8, ctext_bytes) };
// TODO: proper error handling
if let Ok((msg, _)) = Message::from_armor_single(Cursor::new(ctext)) {
let skeys: Vec<&SignedSecretKey> = private_keys_for_decryption
@@ -274,13 +283,19 @@ pub fn dc_pgp_pk_decrypt(
}
/// Symmetric encryption.
pub fn dc_pgp_symm_encrypt(passphrase: *const libc::c_char, plain: &[u8]) -> Option<String> {
pub fn dc_pgp_symm_encrypt(
passphrase: *const libc::c_char,
plain: *const libc::c_void,
plain_bytes: size_t,
) -> Option<String> {
assert!(!passphrase.is_null(), "invalid passphrase");
assert!(!plain.is_null() && !plain_bytes > 0, "invalid input");
let pw = unsafe { CStr::from_ptr(passphrase).to_str().unwrap() };
let bytes = unsafe { std::slice::from_raw_parts(plain as *const u8, plain_bytes) };
let mut rng = thread_rng();
let lit_msg = Message::new_literal_bytes("", plain);
let lit_msg = Message::new_literal_bytes("", bytes);
let s2k = StringToKey::new_default(&mut rng);
let msg = lit_msg.encrypt_with_password(&mut rng, s2k, Default::default(), || pw.into());
@@ -289,12 +304,18 @@ pub fn dc_pgp_symm_encrypt(passphrase: *const libc::c_char, plain: &[u8]) -> Opt
}
/// Symmetric decryption.
pub fn dc_pgp_symm_decrypt(passphrase: *const libc::c_char, ctext: &[u8]) -> Option<Vec<u8>> {
pub fn dc_pgp_symm_decrypt(
passphrase: *const libc::c_char,
ctext: *const libc::c_void,
ctext_bytes: size_t,
) -> Option<Vec<u8>> {
assert!(!passphrase.is_null(), "invalid passphrase");
assert!(!ctext.is_null() && !ctext_bytes > 0, "invalid input");
let pw = unsafe { CStr::from_ptr(passphrase).to_str().unwrap() };
let bytes = unsafe { std::slice::from_raw_parts(ctext as *const u8, ctext_bytes) };
let enc_msg = Message::from_bytes(Cursor::new(ctext));
let enc_msg = Message::from_bytes(Cursor::new(bytes));
enc_msg
.and_then(|msg| {

View File

@@ -1,6 +1,7 @@
//! Stress some functions for testing; if used as a lib, this file is obsolete.
use std::collections::HashSet;
use std::ffi::CString;
use std::ptr;
use tempfile::{tempdir, TempDir};
@@ -493,18 +494,38 @@ fn test_encryption_decryption() {
assert_ne!(public_key, public_key2);
let original_text = b"This is a test";
let original_text: *const libc::c_char =
b"This is a test\x00" as *const u8 as *const libc::c_char;
let mut keyring = Keyring::default();
keyring.add_owned(public_key.clone());
keyring.add_ref(&public_key2);
let ctext_signed = dc_pgp_pk_encrypt(original_text, &keyring, Some(&private_key)).unwrap();
assert!(!ctext_signed.is_empty());
assert!(ctext_signed.starts_with("-----BEGIN PGP MESSAGE-----"));
let ctext = dc_pgp_pk_encrypt(
original_text as *const libc::c_void,
strlen(original_text),
&keyring,
Some(&private_key),
)
.unwrap();
let ctext_unsigned = dc_pgp_pk_encrypt(original_text, &keyring, None).unwrap();
assert!(!ctext_unsigned.is_empty());
assert!(ctext_unsigned.starts_with("-----BEGIN PGP MESSAGE-----"));
assert!(!ctext.is_empty());
assert!(ctext.starts_with("-----BEGIN PGP MESSAGE-----"));
let ctext_signed_bytes = ctext.len();
let ctext_signed = CString::yolo(ctext);
let ctext = dc_pgp_pk_encrypt(
original_text as *const libc::c_void,
strlen(original_text),
&keyring,
None,
)
.unwrap();
assert!(!ctext.is_empty());
assert!(ctext.starts_with("-----BEGIN PGP MESSAGE-----"));
let ctext_unsigned_bytes = ctext.len();
let ctext_unsigned = CString::yolo(ctext);
let mut keyring = Keyring::default();
keyring.add_owned(private_key);
@@ -518,39 +539,42 @@ fn test_encryption_decryption() {
let mut valid_signatures: HashSet<String> = Default::default();
let plain = dc_pgp_pk_decrypt(
ctext_signed.as_bytes(),
ctext_signed.as_ptr() as *const _,
ctext_signed_bytes,
&keyring,
&public_keyring,
Some(&mut valid_signatures),
)
.unwrap();
assert_eq!(plain, original_text,);
assert_eq!(std::str::from_utf8(&plain).unwrap(), as_str(original_text),);
assert_eq!(valid_signatures.len(), 1);
valid_signatures.clear();
let empty_keyring = Keyring::default();
let plain = dc_pgp_pk_decrypt(
ctext_signed.as_bytes(),
ctext_signed.as_ptr() as *const _,
ctext_signed_bytes,
&keyring,
&empty_keyring,
Some(&mut valid_signatures),
)
.unwrap();
assert_eq!(plain, original_text);
assert_eq!(std::str::from_utf8(&plain).unwrap(), as_str(original_text),);
assert_eq!(valid_signatures.len(), 0);
valid_signatures.clear();
let plain = dc_pgp_pk_decrypt(
ctext_signed.as_bytes(),
ctext_signed.as_ptr() as *const _,
ctext_signed_bytes,
&keyring,
&public_keyring2,
Some(&mut valid_signatures),
)
.unwrap();
assert_eq!(plain, original_text);
assert_eq!(std::str::from_utf8(&plain).unwrap(), as_str(original_text),);
assert_eq!(valid_signatures.len(), 0);
valid_signatures.clear();
@@ -558,26 +582,28 @@ fn test_encryption_decryption() {
public_keyring2.add_ref(&public_key);
let plain = dc_pgp_pk_decrypt(
ctext_signed.as_bytes(),
ctext_signed.as_ptr() as *const _,
ctext_signed_bytes,
&keyring,
&public_keyring2,
Some(&mut valid_signatures),
)
.unwrap();
assert_eq!(plain, original_text);
assert_eq!(std::str::from_utf8(&plain).unwrap(), as_str(original_text),);
assert_eq!(valid_signatures.len(), 1);
valid_signatures.clear();
let plain = dc_pgp_pk_decrypt(
ctext_unsigned.as_bytes(),
ctext_unsigned.as_ptr() as *const _,
ctext_unsigned_bytes,
&keyring,
&public_keyring,
Some(&mut valid_signatures),
)
.unwrap();
assert_eq!(plain, original_text);
assert_eq!(std::str::from_utf8(&plain).unwrap(), as_str(original_text),);
valid_signatures.clear();
@@ -586,10 +612,16 @@ fn test_encryption_decryption() {
let mut public_keyring = Keyring::default();
public_keyring.add_ref(&public_key);
let plain =
dc_pgp_pk_decrypt(ctext_signed.as_bytes(), &keyring, &public_keyring, None).unwrap();
let plain = dc_pgp_pk_decrypt(
ctext_signed.as_ptr() as *const _,
ctext_signed_bytes,
&keyring,
&public_keyring,
None,
)
.unwrap();
assert_eq!(plain, original_text);
assert_eq!(std::str::from_utf8(&plain).unwrap(), as_str(original_text),);
}
}