#![warn(unused, clippy::all)]
#![allow(
non_camel_case_types,
non_snake_case,
non_upper_case_globals,
non_upper_case_globals,
non_camel_case_types,
clippy::missing_safety_doc,
clippy::expect_fun_call
)]
#[macro_use]
extern crate human_panic;
use std::collections::BTreeMap;
use std::convert::TryFrom;
use std::fmt::Write;
use std::future::Future;
use std::ops::Deref;
use std::ptr;
use std::str::FromStr;
use std::sync::Arc;
use std::time::{Duration, SystemTime};
use anyhow::Context as _;
use deltachat::chat::{ChatId, ChatVisibility, MessageListOptions, MuteDuration, ProtectionStatus};
use deltachat::constants::DC_MSG_ID_LAST_SPECIAL;
use deltachat::contact::{Contact, ContactId, Origin};
use deltachat::context::Context;
use deltachat::ephemeral::Timer as EphemeralTimer;
use deltachat::imex::BackupProvider;
use deltachat::key::preconfigure_keypair;
use deltachat::message::MsgId;
use deltachat::qr_code_generator::{generate_backup_qr, get_securejoin_qr_svg};
use deltachat::reaction::{get_msg_reactions, send_reaction, Reactions};
use deltachat::stock_str::StockMessage;
use deltachat::stock_str::StockStrings;
use deltachat::webxdc::StatusUpdateSerial;
use deltachat::*;
use deltachat::{accounts::Accounts, log::LogExt};
use num_traits::{FromPrimitive, ToPrimitive};
use once_cell::sync::Lazy;
use rand::Rng;
use tokio::runtime::Runtime;
use tokio::sync::RwLock;
use tokio::task::JoinHandle;
mod dc_array;
mod lot;
mod string;
use deltachat::chatlist::Chatlist;
use self::string::*;
const DC_GCM_ADDDAYMARKER: u32 = 0x01;
const DC_GCM_INFO_ONLY: u32 = 0x02;
pub type dc_context_t = Context;
pub type dc_reactions_t = Reactions;
static RT: Lazy<Runtime> = Lazy::new(|| Runtime::new().expect("unable to create tokio runtime"));
fn block_on<T>(fut: T) -> T::Output
where
T: Future,
{
RT.block_on(fut)
}
fn spawn<T>(fut: T) -> JoinHandle<T::Output>
where
T: Future + Send + 'static,
T::Output: Send + 'static,
{
RT.spawn(fut)
}
#[no_mangle]
pub unsafe extern "C" fn dc_context_new(
_os_name: *const libc::c_char,
dbfile: *const libc::c_char,
blobdir: *const libc::c_char,
) -> *mut dc_context_t {
setup_panic!();
if dbfile.is_null() {
eprintln!("ignoring careless call to dc_context_new()");
return ptr::null_mut();
}
let ctx = if blobdir.is_null() || *blobdir == 0 {
let id = rand::thread_rng().gen();
block_on(Context::new(
as_path(dbfile),
id,
Events::new(),
StockStrings::new(),
))
} else {
eprintln!("blobdir can not be defined explicitly anymore");
return ptr::null_mut();
};
match ctx {
Ok(ctx) => Box::into_raw(Box::new(ctx)),
Err(err) => {
eprintln!("failed to create context: {err:#}");
ptr::null_mut()
}
}
}
#[no_mangle]
pub unsafe extern "C" fn dc_context_new_closed(dbfile: *const libc::c_char) -> *mut dc_context_t {
setup_panic!();
if dbfile.is_null() {
eprintln!("ignoring careless call to dc_context_new_closed()");
return ptr::null_mut();
}
let id = rand::thread_rng().gen();
match block_on(Context::new_closed(
as_path(dbfile),
id,
Events::new(),
StockStrings::new(),
)) {
Ok(context) => Box::into_raw(Box::new(context)),
Err(err) => {
eprintln!("failed to create context: {err:#}");
ptr::null_mut()
}
}
}
#[no_mangle]
pub unsafe extern "C" fn dc_context_open(
context: *mut dc_context_t,
passphrase: *const libc::c_char,
) -> libc::c_int {
if context.is_null() {
eprintln!("ignoring careless call to dc_context_open()");
return 0;
}
let ctx = &*context;
let passphrase = to_string_lossy(passphrase);
block_on(ctx.open(passphrase))
.context("dc_context_open() failed")
.log_err(ctx)
.map(|b| b as libc::c_int)
.unwrap_or(0)
}
#[no_mangle]
pub unsafe extern "C" fn dc_context_change_passphrase(
context: *mut dc_context_t,
passphrase: *const libc::c_char,
) -> libc::c_int {
if context.is_null() {
eprintln!("ignoring careless call to dc_context_change_passphrase()");
return 0;
}
let ctx = &*context;
let passphrase = to_string_lossy(passphrase);
block_on(ctx.change_passphrase(passphrase))
.context("dc_context_change_passphrase() failed")
.log_err(ctx)
.is_ok() as libc::c_int
}
#[no_mangle]
pub unsafe extern "C" fn dc_context_is_open(context: *mut dc_context_t) -> libc::c_int {
if context.is_null() {
eprintln!("ignoring careless call to dc_context_is_open()");
return 0;
}
let ctx = &*context;
block_on(ctx.is_open()) as libc::c_int
}
#[no_mangle]
pub unsafe extern "C" fn dc_context_unref(context: *mut dc_context_t) {
if context.is_null() {
eprintln!("ignoring careless call to dc_context_unref()");
return;
}
drop(Box::from_raw(context));
}
#[no_mangle]
pub unsafe extern "C" fn dc_get_blobdir(context: *mut dc_context_t) -> *mut libc::c_char {
if context.is_null() {
eprintln!("ignoring careless call to dc_get_blobdir()");
return "".strdup();
}
let ctx = &*context;
ctx.get_blobdir().to_string_lossy().strdup()
}
#[no_mangle]
pub unsafe extern "C" fn dc_set_config(
context: *mut dc_context_t,
key: *const libc::c_char,
value: *const libc::c_char,
) -> libc::c_int {
if context.is_null() || key.is_null() {
eprintln!("ignoring careless call to dc_set_config()");
return 0;
}
let ctx = &*context;
let key = to_string_lossy(key);
let value = to_opt_string_lossy(value);
block_on(async move {
if key.starts_with("ui.") {
ctx.set_ui_config(&key, value.as_deref())
.await
.with_context(|| format!("dc_set_config failed: Can't set {key} to {value:?}"))
.log_err(ctx)
.is_ok() as libc::c_int
} else {
match config::Config::from_str(&key) {
Ok(key) => ctx
.set_config(key, value.as_deref())
.await
.with_context(|| {
format!("dc_set_config() failed: Can't set {key} to {value:?}")
})
.log_err(ctx)
.is_ok() as libc::c_int,
Err(_) => {
warn!(ctx, "dc_set_config(): invalid key");
0
}
}
}
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_get_config(
context: *mut dc_context_t,
key: *const libc::c_char,
) -> *mut libc::c_char {
if context.is_null() || key.is_null() {
eprintln!("ignoring careless call to dc_get_config()");
return "".strdup();
}
let ctx = &*context;
let key = to_string_lossy(key);
block_on(async move {
if key.starts_with("ui.") {
ctx.get_ui_config(&key)
.await
.context("Can't get ui-config")
.log_err(ctx)
.unwrap_or_default()
.unwrap_or_default()
.strdup()
} else {
match config::Config::from_str(&key) {
Ok(key) => ctx
.get_config(key)
.await
.context("Can't get config")
.log_err(ctx)
.unwrap_or_default()
.unwrap_or_default()
.strdup(),
Err(_) => {
warn!(ctx, "dc_get_config(): invalid key '{}'", &key);
"".strdup()
}
}
}
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_set_stock_translation(
context: *mut dc_context_t,
stock_id: u32,
stock_msg: *mut libc::c_char,
) -> libc::c_int {
if context.is_null() || stock_msg.is_null() {
eprintln!("ignoring careless call to dc_set_stock_string");
return 0;
}
let msg = to_string_lossy(stock_msg);
let ctx = &*context;
block_on(async move {
match StockMessage::from_u32(stock_id) {
Some(id) => match ctx.set_stock_translation(id, msg).await {
Ok(()) => 1,
Err(err) => {
warn!(ctx, "set_stock_translation failed: {err:#}");
0
}
},
None => {
warn!(ctx, "invalid stock message id {stock_id}");
0
}
}
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_set_config_from_qr(
context: *mut dc_context_t,
qr: *mut libc::c_char,
) -> libc::c_int {
if context.is_null() || qr.is_null() {
eprintln!("ignoring careless call to dc_set_config_from_qr");
return 0;
}
let qr = to_string_lossy(qr);
let ctx = &*context;
block_on(async move {
match qr::set_config_from_qr(ctx, &qr).await {
Ok(()) => 1,
Err(err) => {
error!(ctx, "Failed to create account from QR code: {err:#}");
0
}
}
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_get_info(context: *const dc_context_t) -> *mut libc::c_char {
if context.is_null() {
eprintln!("ignoring careless call to dc_get_info()");
return "".strdup();
}
let ctx = &*context;
block_on(async move {
match ctx.get_info().await {
Ok(info) => render_info(info).unwrap_or_default().strdup(),
Err(err) => {
warn!(ctx, "failed to get info: {err:#}");
"".strdup()
}
}
})
}
fn render_info(
info: BTreeMap<&'static str, String>,
) -> std::result::Result<String, std::fmt::Error> {
let mut res = String::new();
for (key, value) in &info {
writeln!(&mut res, "{key}={value}")?;
}
Ok(res)
}
#[no_mangle]
pub unsafe extern "C" fn dc_get_connectivity(context: *const dc_context_t) -> libc::c_int {
if context.is_null() {
eprintln!("ignoring careless call to dc_get_connectivity()");
return 0;
}
let ctx = &*context;
block_on(async move { ctx.get_connectivity().await as u32 as libc::c_int })
}
#[no_mangle]
pub unsafe extern "C" fn dc_get_connectivity_html(
context: *const dc_context_t,
) -> *mut libc::c_char {
if context.is_null() {
eprintln!("ignoring careless call to dc_get_connectivity_html()");
return "".strdup();
}
let ctx = &*context;
block_on(async move {
match ctx.get_connectivity_html().await {
Ok(html) => html.strdup(),
Err(err) => {
error!(ctx, "Failed to get connectivity html: {err:#}");
"".strdup()
}
}
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_all_work_done(context: *mut dc_context_t) -> libc::c_int {
if context.is_null() {
eprintln!("ignoring careless call to dc_all_work_done()");
return 0;
}
let ctx = &*context;
block_on(async move { ctx.all_work_done().await as libc::c_int })
}
#[no_mangle]
pub unsafe extern "C" fn dc_get_oauth2_url(
context: *mut dc_context_t,
addr: *const libc::c_char,
redirect: *const libc::c_char,
) -> *mut libc::c_char {
if context.is_null() {
eprintln!("ignoring careless call to dc_get_oauth2_url()");
return ptr::null_mut(); }
let ctx = &*context;
let addr = to_string_lossy(addr);
let redirect = to_string_lossy(redirect);
block_on(async move {
match oauth2::get_oauth2_url(ctx, &addr, &redirect)
.await
.context("dc_get_oauth2_url failed")
.log_err(ctx)
{
Ok(Some(res)) => res.strdup(),
Ok(None) | Err(_) => ptr::null_mut(),
}
})
}
fn spawn_configure(ctx: Context) {
spawn(async move {
ctx.configure()
.await
.context("Configure failed")
.log_err(&ctx)
});
}
#[no_mangle]
pub unsafe extern "C" fn dc_configure(context: *mut dc_context_t) {
if context.is_null() {
eprintln!("ignoring careless call to dc_configure()");
return;
}
let ctx = &*context;
spawn_configure(ctx.clone());
}
#[no_mangle]
pub unsafe extern "C" fn dc_is_configured(context: *mut dc_context_t) -> libc::c_int {
if context.is_null() {
eprintln!("ignoring careless call to dc_is_configured()");
return 0;
}
let ctx = &*context;
block_on(async move {
ctx.is_configured()
.await
.context("failed to get configured state")
.log_err(ctx)
.unwrap_or_default() as libc::c_int
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_start_io(context: *mut dc_context_t) {
if context.is_null() {
return;
}
let ctx = &mut *context;
block_on(ctx.start_io())
}
#[no_mangle]
pub unsafe extern "C" fn dc_get_id(context: *mut dc_context_t) -> libc::c_int {
if context.is_null() {
return 0;
}
let ctx = &*context;
ctx.get_id() as libc::c_int
}
pub type dc_event_t = Event;
#[no_mangle]
pub unsafe extern "C" fn dc_event_unref(a: *mut dc_event_t) {
if a.is_null() {
eprintln!("ignoring careless call to dc_event_unref()");
return;
}
drop(Box::from_raw(a));
}
#[no_mangle]
pub unsafe extern "C" fn dc_event_get_id(event: *mut dc_event_t) -> libc::c_int {
if event.is_null() {
eprintln!("ignoring careless call to dc_event_get_id()");
return 0;
}
let event = &*event;
match event.typ {
EventType::Info(_) => 100,
EventType::SmtpConnected(_) => 101,
EventType::ImapConnected(_) => 102,
EventType::SmtpMessageSent(_) => 103,
EventType::ImapMessageDeleted(_) => 104,
EventType::ImapMessageMoved(_) => 105,
EventType::ImapInboxIdle => 106,
EventType::NewBlobFile(_) => 150,
EventType::DeletedBlobFile(_) => 151,
EventType::Warning(_) => 300,
EventType::Error(_) => 400,
EventType::ErrorSelfNotInGroup(_) => 410,
EventType::MsgsChanged { .. } => 2000,
EventType::ReactionsChanged { .. } => 2001,
EventType::IncomingMsg { .. } => 2005,
EventType::IncomingMsgBunch { .. } => 2006,
EventType::MsgsNoticed { .. } => 2008,
EventType::MsgDelivered { .. } => 2010,
EventType::MsgFailed { .. } => 2012,
EventType::MsgRead { .. } => 2015,
EventType::MsgDeleted { .. } => 2016,
EventType::ChatModified(_) => 2020,
EventType::ChatEphemeralTimerModified { .. } => 2021,
EventType::ContactsChanged(_) => 2030,
EventType::LocationChanged(_) => 2035,
EventType::ConfigureProgress { .. } => 2041,
EventType::ImexProgress(_) => 2051,
EventType::ImexFileWritten(_) => 2052,
EventType::SecurejoinInviterProgress { .. } => 2060,
EventType::SecurejoinJoinerProgress { .. } => 2061,
EventType::ConnectivityChanged => 2100,
EventType::SelfavatarChanged => 2110,
EventType::ConfigSynced { .. } => 2111,
EventType::WebxdcStatusUpdate { .. } => 2120,
EventType::WebxdcInstanceDeleted { .. } => 2121,
EventType::AccountsBackgroundFetchDone => 2200,
}
}
#[no_mangle]
pub unsafe extern "C" fn dc_event_get_data1_int(event: *mut dc_event_t) -> libc::c_int {
if event.is_null() {
eprintln!("ignoring careless call to dc_event_get_data1_int()");
return 0;
}
let event = &(*event).typ;
match event {
EventType::Info(_)
| EventType::SmtpConnected(_)
| EventType::ImapConnected(_)
| EventType::SmtpMessageSent(_)
| EventType::ImapMessageDeleted(_)
| EventType::ImapMessageMoved(_)
| EventType::ImapInboxIdle
| EventType::NewBlobFile(_)
| EventType::DeletedBlobFile(_)
| EventType::Warning(_)
| EventType::Error(_)
| EventType::ConnectivityChanged
| EventType::SelfavatarChanged
| EventType::ConfigSynced { .. }
| EventType::IncomingMsgBunch { .. }
| EventType::ErrorSelfNotInGroup(_)
| EventType::AccountsBackgroundFetchDone => 0,
EventType::MsgsChanged { chat_id, .. }
| EventType::ReactionsChanged { chat_id, .. }
| EventType::IncomingMsg { chat_id, .. }
| EventType::MsgsNoticed(chat_id)
| EventType::MsgDelivered { chat_id, .. }
| EventType::MsgFailed { chat_id, .. }
| EventType::MsgRead { chat_id, .. }
| EventType::MsgDeleted { chat_id, .. }
| EventType::ChatModified(chat_id)
| EventType::ChatEphemeralTimerModified { chat_id, .. } => chat_id.to_u32() as libc::c_int,
EventType::ContactsChanged(id) | EventType::LocationChanged(id) => {
let id = id.unwrap_or_default();
id.to_u32() as libc::c_int
}
EventType::ConfigureProgress { progress, .. } | EventType::ImexProgress(progress) => {
*progress as libc::c_int
}
EventType::ImexFileWritten(_) => 0,
EventType::SecurejoinInviterProgress { contact_id, .. }
| EventType::SecurejoinJoinerProgress { contact_id, .. } => {
contact_id.to_u32() as libc::c_int
}
EventType::WebxdcStatusUpdate { msg_id, .. } => msg_id.to_u32() as libc::c_int,
EventType::WebxdcInstanceDeleted { msg_id, .. } => msg_id.to_u32() as libc::c_int,
}
}
#[no_mangle]
pub unsafe extern "C" fn dc_event_get_data2_int(event: *mut dc_event_t) -> libc::c_int {
if event.is_null() {
eprintln!("ignoring careless call to dc_event_get_data2_int()");
return 0;
}
let event = &(*event).typ;
match event {
EventType::Info(_)
| EventType::SmtpConnected(_)
| EventType::ImapConnected(_)
| EventType::SmtpMessageSent(_)
| EventType::ImapMessageDeleted(_)
| EventType::ImapMessageMoved(_)
| EventType::ImapInboxIdle
| EventType::NewBlobFile(_)
| EventType::DeletedBlobFile(_)
| EventType::Warning(_)
| EventType::Error(_)
| EventType::ErrorSelfNotInGroup(_)
| EventType::ContactsChanged(_)
| EventType::LocationChanged(_)
| EventType::ConfigureProgress { .. }
| EventType::ImexProgress(_)
| EventType::ImexFileWritten(_)
| EventType::MsgsNoticed(_)
| EventType::ConnectivityChanged
| EventType::WebxdcInstanceDeleted { .. }
| EventType::IncomingMsgBunch { .. }
| EventType::SelfavatarChanged
| EventType::AccountsBackgroundFetchDone
| EventType::ConfigSynced { .. } => 0,
EventType::ChatModified(_) => 0,
EventType::MsgsChanged { msg_id, .. }
| EventType::ReactionsChanged { msg_id, .. }
| EventType::IncomingMsg { msg_id, .. }
| EventType::MsgDelivered { msg_id, .. }
| EventType::MsgFailed { msg_id, .. }
| EventType::MsgRead { msg_id, .. }
| EventType::MsgDeleted { msg_id, .. } => msg_id.to_u32() as libc::c_int,
EventType::SecurejoinInviterProgress { progress, .. }
| EventType::SecurejoinJoinerProgress { progress, .. } => *progress as libc::c_int,
EventType::ChatEphemeralTimerModified { timer, .. } => timer.to_u32() as libc::c_int,
EventType::WebxdcStatusUpdate {
status_update_serial,
..
} => status_update_serial.to_u32() as libc::c_int,
}
}
#[no_mangle]
pub unsafe extern "C" fn dc_event_get_data2_str(event: *mut dc_event_t) -> *mut libc::c_char {
if event.is_null() {
eprintln!("ignoring careless call to dc_event_get_data2_str()");
return ptr::null_mut();
}
let event = &(*event).typ;
match event {
EventType::Info(msg)
| EventType::SmtpConnected(msg)
| EventType::ImapConnected(msg)
| EventType::SmtpMessageSent(msg)
| EventType::ImapMessageDeleted(msg)
| EventType::ImapMessageMoved(msg)
| EventType::NewBlobFile(msg)
| EventType::DeletedBlobFile(msg)
| EventType::Warning(msg)
| EventType::Error(msg)
| EventType::ErrorSelfNotInGroup(msg) => {
let data2 = msg.to_c_string().unwrap_or_default();
data2.into_raw()
}
EventType::MsgsChanged { .. }
| EventType::ReactionsChanged { .. }
| EventType::IncomingMsg { .. }
| EventType::ImapInboxIdle
| EventType::MsgsNoticed(_)
| EventType::MsgDelivered { .. }
| EventType::MsgFailed { .. }
| EventType::MsgRead { .. }
| EventType::MsgDeleted { .. }
| EventType::ChatModified(_)
| EventType::ContactsChanged(_)
| EventType::LocationChanged(_)
| EventType::ImexProgress(_)
| EventType::SecurejoinInviterProgress { .. }
| EventType::SecurejoinJoinerProgress { .. }
| EventType::ConnectivityChanged
| EventType::SelfavatarChanged
| EventType::WebxdcStatusUpdate { .. }
| EventType::WebxdcInstanceDeleted { .. }
| EventType::AccountsBackgroundFetchDone
| EventType::ChatEphemeralTimerModified { .. } => ptr::null_mut(),
EventType::ConfigureProgress { comment, .. } => {
if let Some(comment) = comment {
comment.to_c_string().unwrap_or_default().into_raw()
} else {
ptr::null_mut()
}
}
EventType::ImexFileWritten(file) => {
let data2 = file.to_c_string().unwrap_or_default();
data2.into_raw()
}
EventType::IncomingMsgBunch { msg_ids } => serde_json::to_string(msg_ids)
.unwrap_or_default()
.to_c_string()
.unwrap_or_default()
.into_raw(),
EventType::ConfigSynced { key } => {
let data2 = key.to_string().to_c_string().unwrap_or_default();
data2.into_raw()
}
}
}
#[no_mangle]
pub unsafe extern "C" fn dc_event_get_account_id(event: *mut dc_event_t) -> u32 {
if event.is_null() {
eprintln!("ignoring careless call to dc_event_get_account_id()");
return 0;
}
(*event).id
}
pub type dc_event_emitter_t = EventEmitter;
#[no_mangle]
pub unsafe extern "C" fn dc_get_event_emitter(
context: *mut dc_context_t,
) -> *mut dc_event_emitter_t {
if context.is_null() {
eprintln!("ignoring careless call to dc_get_event_emitter()");
return ptr::null_mut();
}
let ctx = &*context;
Box::into_raw(Box::new(ctx.get_event_emitter()))
}
#[no_mangle]
pub unsafe extern "C" fn dc_event_emitter_unref(emitter: *mut dc_event_emitter_t) {
if emitter.is_null() {
eprintln!("ignoring careless call to dc_event_emitter_unref()");
return;
}
drop(Box::from_raw(emitter));
}
#[no_mangle]
pub unsafe extern "C" fn dc_get_next_event(events: *mut dc_event_emitter_t) -> *mut dc_event_t {
if events.is_null() {
eprintln!("ignoring careless call to dc_get_next_event()");
return ptr::null_mut();
}
let events = &*events;
block_on(async move {
events
.recv()
.await
.map(|ev| Box::into_raw(Box::new(ev)))
.unwrap_or_else(ptr::null_mut)
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_stop_io(context: *mut dc_context_t) {
if context.is_null() {
eprintln!("ignoring careless call to dc_stop_io()");
return;
}
let ctx = &*context;
block_on(async move {
ctx.stop_io().await;
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_maybe_network(context: *mut dc_context_t) {
if context.is_null() {
eprintln!("ignoring careless call to dc_maybe_network()");
return;
}
let ctx = &*context;
block_on(async move { ctx.maybe_network().await })
}
#[no_mangle]
pub unsafe extern "C" fn dc_preconfigure_keypair(
context: *mut dc_context_t,
addr: *const libc::c_char,
_public_data: *const libc::c_char,
secret_data: *const libc::c_char,
) -> i32 {
if context.is_null() {
eprintln!("ignoring careless call to dc_preconfigure_keypair()");
return 0;
}
let ctx = &*context;
let addr = to_string_lossy(addr);
let secret_data = to_string_lossy(secret_data);
block_on(preconfigure_keypair(ctx, &addr, &secret_data))
.context("Failed to save keypair")
.log_err(ctx)
.is_ok() as libc::c_int
}
#[no_mangle]
pub unsafe extern "C" fn dc_get_chatlist(
context: *mut dc_context_t,
flags: libc::c_int,
query_str: *const libc::c_char,
query_id: u32,
) -> *mut dc_chatlist_t {
if context.is_null() {
eprintln!("ignoring careless call to dc_get_chatlist()");
return ptr::null_mut();
}
let ctx = &*context;
let qs = to_opt_string_lossy(query_str);
let qi = if query_id == 0 {
None
} else {
Some(ContactId::new(query_id))
};
block_on(async move {
match chatlist::Chatlist::try_load(ctx, flags as usize, qs.as_deref(), qi)
.await
.context("Failed to get chatlist")
.log_err(ctx)
{
Ok(list) => {
let ffi_list = ChatlistWrapper { context, list };
Box::into_raw(Box::new(ffi_list))
}
Err(_) => ptr::null_mut(),
}
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_create_chat_by_contact_id(
context: *mut dc_context_t,
contact_id: u32,
) -> u32 {
if context.is_null() {
eprintln!("ignoring careless call to dc_create_chat_by_contact_id()");
return 0;
}
let ctx = &*context;
block_on(async move {
ChatId::create_for_contact(ctx, ContactId::new(contact_id))
.await
.context("Failed to create chat from contact_id")
.log_err(ctx)
.map(|id| id.to_u32())
.unwrap_or(0)
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_get_chat_id_by_contact_id(
context: *mut dc_context_t,
contact_id: u32,
) -> u32 {
if context.is_null() {
eprintln!("ignoring careless call to dc_get_chat_id_by_contact_id()");
return 0;
}
let ctx = &*context;
block_on(async move {
ChatId::lookup_by_contact(ctx, ContactId::new(contact_id))
.await
.context("Failed to get chat for contact_id")
.log_err(ctx)
.unwrap_or_default() .map(|id| id.to_u32())
.unwrap_or(0) })
}
#[no_mangle]
pub unsafe extern "C" fn dc_prepare_msg(
context: *mut dc_context_t,
chat_id: u32,
msg: *mut dc_msg_t,
) -> u32 {
if context.is_null() || chat_id == 0 || msg.is_null() {
eprintln!("ignoring careless call to dc_prepare_msg()");
return 0;
}
let ctx = &mut *context;
let ffi_msg: &mut MessageWrapper = &mut *msg;
block_on(async move {
chat::prepare_msg(ctx, ChatId::new(chat_id), &mut ffi_msg.message)
.await
.unwrap_or_log_default(ctx, "Failed to prepare message")
})
.to_u32()
}
#[no_mangle]
pub unsafe extern "C" fn dc_send_msg(
context: *mut dc_context_t,
chat_id: u32,
msg: *mut dc_msg_t,
) -> u32 {
if context.is_null() || msg.is_null() {
eprintln!("ignoring careless call to dc_send_msg()");
return 0;
}
let ctx = &mut *context;
let ffi_msg = &mut *msg;
block_on(async move {
chat::send_msg(ctx, ChatId::new(chat_id), &mut ffi_msg.message)
.await
.unwrap_or_log_default(ctx, "Failed to send message")
})
.to_u32()
}
#[no_mangle]
pub unsafe extern "C" fn dc_send_msg_sync(
context: *mut dc_context_t,
chat_id: u32,
msg: *mut dc_msg_t,
) -> u32 {
if context.is_null() || msg.is_null() {
eprintln!("ignoring careless call to dc_send_msg_sync()");
return 0;
}
let ctx = &mut *context;
let ffi_msg = &mut *msg;
block_on(async move {
chat::send_msg_sync(ctx, ChatId::new(chat_id), &mut ffi_msg.message)
.await
.unwrap_or_log_default(ctx, "Failed to send message")
})
.to_u32()
}
#[no_mangle]
pub unsafe extern "C" fn dc_send_text_msg(
context: *mut dc_context_t,
chat_id: u32,
text_to_send: *const libc::c_char,
) -> u32 {
if context.is_null() || text_to_send.is_null() {
eprintln!("ignoring careless call to dc_send_text_msg()");
return 0;
}
let ctx = &*context;
let text_to_send = to_string_lossy(text_to_send);
block_on(async move {
chat::send_text_msg(ctx, ChatId::new(chat_id), text_to_send)
.await
.map(|msg_id| msg_id.to_u32())
.unwrap_or_log_default(ctx, "Failed to send text message")
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_send_videochat_invitation(
context: *mut dc_context_t,
chat_id: u32,
) -> u32 {
if context.is_null() {
eprintln!("ignoring careless call to dc_send_videochat_invitation()");
return 0;
}
let ctx = &*context;
block_on(async move {
chat::send_videochat_invitation(ctx, ChatId::new(chat_id))
.await
.map(|msg_id| msg_id.to_u32())
.unwrap_or_log_default(ctx, "Failed to send video chat invitation")
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_send_reaction(
context: *mut dc_context_t,
msg_id: u32,
reaction: *const libc::c_char,
) -> u32 {
if context.is_null() {
eprintln!("ignoring careless call to dc_send_reaction()");
return 0;
}
let ctx = &*context;
block_on(async move {
send_reaction(ctx, MsgId::new(msg_id), &to_string_lossy(reaction))
.await
.map(|msg_id| msg_id.to_u32())
.unwrap_or_log_default(ctx, "Failed to send reaction")
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_get_msg_reactions(
context: *mut dc_context_t,
msg_id: u32,
) -> *mut dc_reactions_t {
if context.is_null() {
eprintln!("ignoring careless call to dc_get_msg_reactions()");
return ptr::null_mut();
}
let ctx = &*context;
let reactions = if let Ok(reactions) = block_on(get_msg_reactions(ctx, MsgId::new(msg_id)))
.context("failed dc_get_msg_reactions() call")
.log_err(ctx)
{
reactions
} else {
return ptr::null_mut();
};
Box::into_raw(Box::new(reactions))
}
#[no_mangle]
pub unsafe extern "C" fn dc_send_webxdc_status_update(
context: *mut dc_context_t,
msg_id: u32,
json: *const libc::c_char,
descr: *const libc::c_char,
) -> libc::c_int {
if context.is_null() {
eprintln!("ignoring careless call to dc_send_webxdc_status_update()");
return 0;
}
let ctx = &*context;
block_on(ctx.send_webxdc_status_update(
MsgId::new(msg_id),
&to_string_lossy(json),
&to_string_lossy(descr),
))
.context("Failed to send webxdc update")
.log_err(ctx)
.is_ok() as libc::c_int
}
#[no_mangle]
pub unsafe extern "C" fn dc_get_webxdc_status_updates(
context: *mut dc_context_t,
msg_id: u32,
last_known_serial: u32,
) -> *mut libc::c_char {
if context.is_null() {
eprintln!("ignoring careless call to dc_get_webxdc_status_updates()");
return "".strdup();
}
let ctx = &*context;
block_on(ctx.get_webxdc_status_updates(
MsgId::new(msg_id),
StatusUpdateSerial::new(last_known_serial),
))
.unwrap_or_else(|_| "".to_string())
.strdup()
}
#[no_mangle]
pub unsafe extern "C" fn dc_set_draft(
context: *mut dc_context_t,
chat_id: u32,
msg: *mut dc_msg_t,
) {
if context.is_null() {
eprintln!("ignoring careless call to dc_set_draft()");
return;
}
let ctx = &*context;
let msg = if msg.is_null() {
None
} else {
let ffi_msg: &mut MessageWrapper = &mut *msg;
Some(&mut ffi_msg.message)
};
block_on(async move {
ChatId::new(chat_id)
.set_draft(ctx, msg)
.await
.unwrap_or_log_default(ctx, "failed to set draft");
});
}
#[no_mangle]
pub unsafe extern "C" fn dc_add_device_msg(
context: *mut dc_context_t,
label: *const libc::c_char,
msg: *mut dc_msg_t,
) -> u32 {
if context.is_null() || (label.is_null() && msg.is_null()) {
eprintln!("ignoring careless call to dc_add_device_msg()");
return 0;
}
let ctx = &mut *context;
let msg = if msg.is_null() {
None
} else {
let ffi_msg: &mut MessageWrapper = &mut *msg;
Some(&mut ffi_msg.message)
};
block_on(async move {
chat::add_device_msg(ctx, to_opt_string_lossy(label).as_deref(), msg)
.await
.unwrap_or_log_default(ctx, "Failed to add device message")
})
.to_u32()
}
#[no_mangle]
pub unsafe extern "C" fn dc_was_device_msg_ever_added(
context: *mut dc_context_t,
label: *const libc::c_char,
) -> libc::c_int {
if context.is_null() || label.is_null() {
eprintln!("ignoring careless call to dc_was_device_msg_ever_added()");
return 0;
}
let ctx = &mut *context;
block_on(async move {
chat::was_device_msg_ever_added(ctx, &to_string_lossy(label))
.await
.unwrap_or(false) as libc::c_int
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_get_draft(context: *mut dc_context_t, chat_id: u32) -> *mut dc_msg_t {
if context.is_null() {
eprintln!("ignoring careless call to dc_get_draft()");
return ptr::null_mut(); }
let ctx = &*context;
block_on(async move {
match ChatId::new(chat_id).get_draft(ctx).await {
Ok(Some(draft)) => {
let ffi_msg = MessageWrapper {
context,
message: draft,
};
Box::into_raw(Box::new(ffi_msg))
}
Ok(None) => ptr::null_mut(),
Err(err) => {
error!(ctx, "Failed to get draft for chat #{chat_id}: {err:#}");
ptr::null_mut()
}
}
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_get_chat_msgs(
context: *mut dc_context_t,
chat_id: u32,
flags: u32,
_marker1before: u32,
) -> *mut dc_array::dc_array_t {
if context.is_null() {
eprintln!("ignoring careless call to dc_get_chat_msgs()");
return ptr::null_mut();
}
let ctx = &*context;
let info_only = (flags & DC_GCM_INFO_ONLY) != 0;
let add_daymarker = (flags & DC_GCM_ADDDAYMARKER) != 0;
block_on(async move {
Box::into_raw(Box::new(
chat::get_chat_msgs_ex(
ctx,
ChatId::new(chat_id),
MessageListOptions {
info_only,
add_daymarker,
},
)
.await
.unwrap_or_log_default(ctx, "failed to get chat msgs")
.into(),
))
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_get_msg_cnt(context: *mut dc_context_t, chat_id: u32) -> libc::c_int {
if context.is_null() {
eprintln!("ignoring careless call to dc_get_msg_cnt()");
return 0;
}
let ctx = &*context;
block_on(async move {
ChatId::new(chat_id)
.get_msg_cnt(ctx)
.await
.unwrap_or_log_default(ctx, "failed to get msg count") as libc::c_int
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_get_fresh_msg_cnt(
context: *mut dc_context_t,
chat_id: u32,
) -> libc::c_int {
if context.is_null() {
eprintln!("ignoring careless call to dc_get_fresh_msg_cnt()");
return 0;
}
let ctx = &*context;
block_on(async move {
ChatId::new(chat_id)
.get_fresh_msg_cnt(ctx)
.await
.unwrap_or_log_default(ctx, "failed to get fresh msg cnt") as libc::c_int
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_get_similar_chatlist(
context: *mut dc_context_t,
chat_id: u32,
) -> *mut dc_chatlist_t {
if context.is_null() {
eprintln!("ignoring careless call to dc_get_similar_chatlist()");
return ptr::null_mut();
}
let ctx = &*context;
let chat_id = ChatId::new(chat_id);
match block_on(chat_id.get_similar_chatlist(ctx))
.context("failed to get similar chatlist")
.log_err(ctx)
{
Ok(list) => {
let ffi_list = ChatlistWrapper { context, list };
Box::into_raw(Box::new(ffi_list))
}
Err(_) => ptr::null_mut(),
}
}
#[no_mangle]
pub unsafe extern "C" fn dc_estimate_deletion_cnt(
context: *mut dc_context_t,
from_server: libc::c_int,
seconds: i64,
) -> libc::c_int {
if context.is_null() || seconds < 0 {
eprintln!("ignoring careless call to dc_estimate_deletion_cnt()");
return 0;
}
let ctx = &*context;
block_on(async move {
message::estimate_deletion_cnt(ctx, from_server != 0, seconds)
.await
.unwrap_or(0) as libc::c_int
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_get_fresh_msgs(
context: *mut dc_context_t,
) -> *mut dc_array::dc_array_t {
if context.is_null() {
eprintln!("ignoring careless call to dc_get_fresh_msgs()");
return ptr::null_mut();
}
let ctx = &*context;
block_on(async move {
let arr = dc_array_t::from(
ctx.get_fresh_msgs()
.await
.context("Failed to get fresh messages")
.log_err(ctx)
.unwrap_or_default()
.iter()
.map(|msg_id| msg_id.to_u32())
.collect::<Vec<u32>>(),
);
Box::into_raw(Box::new(arr))
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_get_next_msgs(context: *mut dc_context_t) -> *mut dc_array::dc_array_t {
if context.is_null() {
eprintln!("ignoring careless call to dc_get_next_msgs()");
return ptr::null_mut();
}
let ctx = &*context;
let msg_ids = block_on(ctx.get_next_msgs())
.context("failed to get next messages")
.log_err(ctx)
.unwrap_or_default();
let arr = dc_array_t::from(
msg_ids
.iter()
.map(|msg_id| msg_id.to_u32())
.collect::<Vec<u32>>(),
);
Box::into_raw(Box::new(arr))
}
#[no_mangle]
pub unsafe extern "C" fn dc_wait_next_msgs(
context: *mut dc_context_t,
) -> *mut dc_array::dc_array_t {
if context.is_null() {
eprintln!("ignoring careless call to dc_wait_next_msgs()");
return ptr::null_mut();
}
let ctx = &*context;
let msg_ids = block_on(ctx.wait_next_msgs())
.context("failed to wait for next messages")
.log_err(ctx)
.unwrap_or_default();
let arr = dc_array_t::from(
msg_ids
.iter()
.map(|msg_id| msg_id.to_u32())
.collect::<Vec<u32>>(),
);
Box::into_raw(Box::new(arr))
}
#[no_mangle]
pub unsafe extern "C" fn dc_marknoticed_chat(context: *mut dc_context_t, chat_id: u32) {
if context.is_null() {
eprintln!("ignoring careless call to dc_marknoticed_chat()");
return;
}
let ctx = &*context;
block_on(async move {
chat::marknoticed_chat(ctx, ChatId::new(chat_id))
.await
.context("Failed marknoticed chat")
.log_err(ctx)
.unwrap_or(())
})
}
fn from_prim<S, T>(s: S) -> Option<T>
where
T: FromPrimitive,
S: Into<i64>,
{
FromPrimitive::from_i64(s.into())
}
#[no_mangle]
pub unsafe extern "C" fn dc_get_chat_media(
context: *mut dc_context_t,
chat_id: u32,
msg_type: libc::c_int,
or_msg_type2: libc::c_int,
or_msg_type3: libc::c_int,
) -> *mut dc_array::dc_array_t {
if context.is_null() {
eprintln!("ignoring careless call to dc_get_chat_media()");
return ptr::null_mut();
}
let ctx = &*context;
let chat_id = if chat_id == 0 {
None
} else {
Some(ChatId::new(chat_id))
};
let msg_type = from_prim(msg_type).expect(&format!("invalid msg_type = {msg_type}"));
let or_msg_type2 =
from_prim(or_msg_type2).expect(&format!("incorrect or_msg_type2 = {or_msg_type2}"));
let or_msg_type3 =
from_prim(or_msg_type3).expect(&format!("incorrect or_msg_type3 = {or_msg_type3}"));
block_on(async move {
Box::into_raw(Box::new(
chat::get_chat_media(ctx, chat_id, msg_type, or_msg_type2, or_msg_type3)
.await
.unwrap_or_log_default(ctx, "Failed get_chat_media")
.into(),
))
})
}
#[no_mangle]
#[allow(deprecated)]
pub unsafe extern "C" fn dc_get_next_media(
context: *mut dc_context_t,
msg_id: u32,
dir: libc::c_int,
msg_type: libc::c_int,
or_msg_type2: libc::c_int,
or_msg_type3: libc::c_int,
) -> u32 {
if context.is_null() {
eprintln!("ignoring careless call to dc_get_next_media()");
return 0;
}
let direction = if dir < 0 {
chat::Direction::Backward
} else {
chat::Direction::Forward
};
let ctx = &*context;
let msg_type = from_prim(msg_type).expect(&format!("invalid msg_type = {msg_type}"));
let or_msg_type2 =
from_prim(or_msg_type2).expect(&format!("incorrect or_msg_type2 = {or_msg_type2}"));
let or_msg_type3 =
from_prim(or_msg_type3).expect(&format!("incorrect or_msg_type3 = {or_msg_type3}"));
block_on(async move {
chat::get_next_media(
ctx,
MsgId::new(msg_id),
direction,
msg_type,
or_msg_type2,
or_msg_type3,
)
.await
.map(|msg_id| msg_id.map(|id| id.to_u32()).unwrap_or_default())
.unwrap_or(0)
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_set_chat_visibility(
context: *mut dc_context_t,
chat_id: u32,
archive: libc::c_int,
) {
if context.is_null() {
eprintln!("ignoring careless call to dc_set_chat_visibility()");
return;
}
let ctx = &*context;
let visibility = match archive {
0 => ChatVisibility::Normal,
1 => ChatVisibility::Archived,
2 => ChatVisibility::Pinned,
_ => {
warn!(
ctx,
"ignoring careless call to dc_set_chat_visibility(): unknown archived state",
);
return;
}
};
block_on(async move {
ChatId::new(chat_id)
.set_visibility(ctx, visibility)
.await
.context("Failed setting chat visibility")
.log_err(ctx)
.unwrap_or(())
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_delete_chat(context: *mut dc_context_t, chat_id: u32) {
if context.is_null() {
eprintln!("ignoring careless call to dc_delete_chat()");
return;
}
let ctx = &*context;
block_on(async move {
ChatId::new(chat_id)
.delete(ctx)
.await
.context("Failed chat delete")
.log_err(ctx)
.ok();
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_block_chat(context: *mut dc_context_t, chat_id: u32) {
if context.is_null() {
eprintln!("ignoring careless call to dc_block_chat()");
return;
}
let ctx = &*context;
block_on(async move {
ChatId::new(chat_id)
.block(ctx)
.await
.context("Failed chat block")
.log_err(ctx)
.ok();
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_accept_chat(context: *mut dc_context_t, chat_id: u32) {
if context.is_null() {
eprintln!("ignoring careless call to dc_accept_chat()");
return;
}
let ctx = &*context;
block_on(async move {
ChatId::new(chat_id)
.accept(ctx)
.await
.context("Failed chat accept")
.log_err(ctx)
.ok();
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_get_chat_contacts(
context: *mut dc_context_t,
chat_id: u32,
) -> *mut dc_array::dc_array_t {
if context.is_null() {
eprintln!("ignoring careless call to dc_get_chat_contacts()");
return ptr::null_mut();
}
let ctx = &*context;
block_on(async move {
let arr = dc_array_t::from(
chat::get_chat_contacts(ctx, ChatId::new(chat_id))
.await
.unwrap_or_log_default(ctx, "Failed get_chat_contacts")
.iter()
.map(|id| id.to_u32())
.collect::<Vec<u32>>(),
);
Box::into_raw(Box::new(arr))
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_search_msgs(
context: *mut dc_context_t,
chat_id: u32,
query: *const libc::c_char,
) -> *mut dc_array::dc_array_t {
if context.is_null() || query.is_null() {
eprintln!("ignoring careless call to dc_search_msgs()");
return ptr::null_mut();
}
let ctx = &*context;
let chat_id = if chat_id == 0 {
None
} else {
Some(ChatId::new(chat_id))
};
block_on(async move {
let arr = dc_array_t::from(
ctx.search_msgs(chat_id, &to_string_lossy(query))
.await
.unwrap_or_log_default(ctx, "Failed search_msgs")
.iter()
.map(|msg_id| msg_id.to_u32())
.collect::<Vec<u32>>(),
);
Box::into_raw(Box::new(arr))
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_get_chat(context: *mut dc_context_t, chat_id: u32) -> *mut dc_chat_t {
if context.is_null() {
eprintln!("ignoring careless call to dc_get_chat()");
return ptr::null_mut();
}
let ctx = &*context;
block_on(async move {
match chat::Chat::load_from_db(ctx, ChatId::new(chat_id)).await {
Ok(chat) => {
let ffi_chat = ChatWrapper { context, chat };
Box::into_raw(Box::new(ffi_chat))
}
Err(_) => ptr::null_mut(),
}
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_create_group_chat(
context: *mut dc_context_t,
protect: libc::c_int,
name: *const libc::c_char,
) -> u32 {
if context.is_null() || name.is_null() {
eprintln!("ignoring careless call to dc_create_group_chat()");
return 0;
}
let ctx = &*context;
let protect = if let Some(s) = ProtectionStatus::from_i32(protect) {
s
} else {
warn!(ctx, "bad protect-value for dc_create_group_chat()");
return 0;
};
block_on(async move {
chat::create_group_chat(ctx, protect, &to_string_lossy(name))
.await
.context("Failed to create group chat")
.log_err(ctx)
.map(|id| id.to_u32())
.unwrap_or(0)
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_create_broadcast_list(context: *mut dc_context_t) -> u32 {
if context.is_null() {
eprintln!("ignoring careless call to dc_create_broadcast_list()");
return 0;
}
let ctx = &*context;
block_on(chat::create_broadcast_list(ctx))
.context("Failed to create broadcast list")
.log_err(ctx)
.map(|id| id.to_u32())
.unwrap_or(0)
}
#[no_mangle]
pub unsafe extern "C" fn dc_is_contact_in_chat(
context: *mut dc_context_t,
chat_id: u32,
contact_id: u32,
) -> libc::c_int {
if context.is_null() {
eprintln!("ignoring careless call to dc_is_contact_in_chat()");
return 0;
}
let ctx = &*context;
block_on(chat::is_contact_in_chat(
ctx,
ChatId::new(chat_id),
ContactId::new(contact_id),
))
.context("is_contact_in_chat failed")
.log_err(ctx)
.unwrap_or_default() as libc::c_int
}
#[no_mangle]
pub unsafe extern "C" fn dc_add_contact_to_chat(
context: *mut dc_context_t,
chat_id: u32,
contact_id: u32,
) -> libc::c_int {
if context.is_null() {
eprintln!("ignoring careless call to dc_add_contact_to_chat()");
return 0;
}
let ctx = &*context;
block_on(chat::add_contact_to_chat(
ctx,
ChatId::new(chat_id),
ContactId::new(contact_id),
))
.context("Failed to add contact")
.log_err(ctx)
.is_ok() as libc::c_int
}
#[no_mangle]
pub unsafe extern "C" fn dc_remove_contact_from_chat(
context: *mut dc_context_t,
chat_id: u32,
contact_id: u32,
) -> libc::c_int {
if context.is_null() {
eprintln!("ignoring careless call to dc_remove_contact_from_chat()");
return 0;
}
let ctx = &*context;
block_on(chat::remove_contact_from_chat(
ctx,
ChatId::new(chat_id),
ContactId::new(contact_id),
))
.context("Failed to remove contact")
.log_err(ctx)
.is_ok() as libc::c_int
}
#[no_mangle]
pub unsafe extern "C" fn dc_set_chat_name(
context: *mut dc_context_t,
chat_id: u32,
name: *const libc::c_char,
) -> libc::c_int {
if context.is_null() || chat_id <= constants::DC_CHAT_ID_LAST_SPECIAL.to_u32() || name.is_null()
{
eprintln!("ignoring careless call to dc_set_chat_name()");
return 0;
}
let ctx = &*context;
block_on(async move {
chat::set_chat_name(ctx, ChatId::new(chat_id), &to_string_lossy(name))
.await
.map(|_| 1)
.unwrap_or_log_default(ctx, "Failed to set chat name")
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_set_chat_profile_image(
context: *mut dc_context_t,
chat_id: u32,
image: *const libc::c_char,
) -> libc::c_int {
if context.is_null() || chat_id <= constants::DC_CHAT_ID_LAST_SPECIAL.to_u32() {
eprintln!("ignoring careless call to dc_set_chat_profile_image()");
return 0;
}
let ctx = &*context;
block_on(async move {
chat::set_chat_profile_image(ctx, ChatId::new(chat_id), &to_string_lossy(image))
.await
.map(|_| 1)
.unwrap_or_log_default(ctx, "Failed to set profile image")
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_set_chat_mute_duration(
context: *mut dc_context_t,
chat_id: u32,
duration: i64,
) -> libc::c_int {
if context.is_null() {
eprintln!("ignoring careless call to dc_set_chat_mute_duration()");
return 0;
}
let ctx = &*context;
let muteDuration = match duration {
0 => MuteDuration::NotMuted,
-1 => MuteDuration::Forever,
n if n > 0 => SystemTime::now()
.checked_add(Duration::from_secs(duration as u64))
.map_or(MuteDuration::Forever, MuteDuration::Until),
_ => {
warn!(
ctx,
"dc_chat_set_mute_duration(): Can not use negative duration other than -1",
);
return 0;
}
};
block_on(async move {
chat::set_muted(ctx, ChatId::new(chat_id), muteDuration)
.await
.map(|_| 1)
.unwrap_or_log_default(ctx, "Failed to set mute duration")
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_get_chat_encrinfo(
context: *mut dc_context_t,
chat_id: u32,
) -> *mut libc::c_char {
if context.is_null() {
eprintln!("ignoring careless call to dc_get_chat_encrinfo()");
return "".strdup();
}
let ctx = &*context;
block_on(async move {
ChatId::new(chat_id)
.get_encryption_info(ctx)
.await
.map(|s| s.strdup())
.unwrap_or_else(|e| {
error!(ctx, "{e:#}");
ptr::null_mut()
})
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_get_chat_ephemeral_timer(
context: *mut dc_context_t,
chat_id: u32,
) -> u32 {
if context.is_null() {
eprintln!("ignoring careless call to dc_get_chat_ephemeral_timer()");
return 0;
}
let ctx = &*context;
block_on(async move { ChatId::new(chat_id).get_ephemeral_timer(ctx).await })
.context("Failed to get ephemeral timer")
.log_err(ctx)
.unwrap_or_default()
.to_u32()
}
#[no_mangle]
pub unsafe extern "C" fn dc_set_chat_ephemeral_timer(
context: *mut dc_context_t,
chat_id: u32,
timer: u32,
) -> libc::c_int {
if context.is_null() {
eprintln!("ignoring careless call to dc_set_chat_ephemeral_timer()");
return 0;
}
let ctx = &*context;
block_on(async move {
ChatId::new(chat_id)
.set_ephemeral_timer(ctx, EphemeralTimer::from_u32(timer))
.await
.context("Failed to set ephemeral timer")
.log_err(ctx)
.is_ok() as libc::c_int
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_get_msg_info(
context: *mut dc_context_t,
msg_id: u32,
) -> *mut libc::c_char {
if context.is_null() {
eprintln!("ignoring careless call to dc_get_msg_info()");
return "".strdup();
}
let ctx = &*context;
let msg_id = MsgId::new(msg_id);
block_on(msg_id.get_info(ctx))
.unwrap_or_log_default(ctx, "failed to get msg id")
.strdup()
}
#[no_mangle]
pub unsafe extern "C" fn dc_get_msg_html(
context: *mut dc_context_t,
msg_id: u32,
) -> *mut libc::c_char {
if context.is_null() {
eprintln!("ignoring careless call to dc_get_msg_html()");
return ptr::null_mut();
}
let ctx = &*context;
block_on(MsgId::new(msg_id).get_html(ctx))
.unwrap_or_log_default(ctx, "Failed get_msg_html")
.strdup()
}
#[no_mangle]
pub unsafe extern "C" fn dc_get_mime_headers(
context: *mut dc_context_t,
msg_id: u32,
) -> *mut libc::c_char {
if context.is_null() {
eprintln!("ignoring careless call to dc_get_mime_headers()");
return ptr::null_mut(); }
let ctx = &*context;
block_on(async move {
let mime = message::get_mime_headers(ctx, MsgId::new(msg_id))
.await
.unwrap_or_log_default(ctx, "failed to get mime headers");
if mime.is_empty() {
return ptr::null_mut();
}
mime.strdup()
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_delete_msgs(
context: *mut dc_context_t,
msg_ids: *const u32,
msg_cnt: libc::c_int,
) {
if context.is_null() || msg_ids.is_null() || msg_cnt <= 0 {
eprintln!("ignoring careless call to dc_delete_msgs()");
return;
}
let ctx = &*context;
let msg_ids = convert_and_prune_message_ids(msg_ids, msg_cnt);
block_on(message::delete_msgs(ctx, &msg_ids))
.context("failed dc_delete_msgs() call")
.log_err(ctx)
.ok();
}
#[no_mangle]
pub unsafe extern "C" fn dc_forward_msgs(
context: *mut dc_context_t,
msg_ids: *const u32,
msg_cnt: libc::c_int,
chat_id: u32,
) {
if context.is_null()
|| msg_ids.is_null()
|| msg_cnt <= 0
|| chat_id <= constants::DC_CHAT_ID_LAST_SPECIAL.to_u32()
{
eprintln!("ignoring careless call to dc_forward_msgs()");
return;
}
let msg_ids = convert_and_prune_message_ids(msg_ids, msg_cnt);
let ctx = &*context;
block_on(async move {
chat::forward_msgs(ctx, &msg_ids[..], ChatId::new(chat_id))
.await
.unwrap_or_log_default(ctx, "Failed to forward message")
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_resend_msgs(
context: *mut dc_context_t,
msg_ids: *const u32,
msg_cnt: libc::c_int,
) -> libc::c_int {
if context.is_null() || msg_ids.is_null() || msg_cnt <= 0 {
eprintln!("ignoring careless call to dc_resend_msgs()");
return 0;
}
let ctx = &*context;
let msg_ids = convert_and_prune_message_ids(msg_ids, msg_cnt);
if let Err(err) = block_on(chat::resend_msgs(ctx, &msg_ids)) {
error!(ctx, "Resending failed: {err:#}");
0
} else {
1
}
}
#[no_mangle]
pub unsafe extern "C" fn dc_markseen_msgs(
context: *mut dc_context_t,
msg_ids: *const u32,
msg_cnt: libc::c_int,
) {
if context.is_null() || msg_ids.is_null() || msg_cnt <= 0 {
eprintln!("ignoring careless call to dc_markseen_msgs()");
return;
}
let msg_ids = convert_and_prune_message_ids(msg_ids, msg_cnt);
let ctx = &*context;
block_on(message::markseen_msgs(ctx, msg_ids))
.context("failed dc_markseen_msgs() call")
.log_err(ctx)
.ok();
}
#[no_mangle]
pub unsafe extern "C" fn dc_get_msg(context: *mut dc_context_t, msg_id: u32) -> *mut dc_msg_t {
if context.is_null() {
eprintln!("ignoring careless call to dc_get_msg()");
return ptr::null_mut();
}
let ctx = &*context;
block_on(async move {
let message = match message::Message::load_from_db(ctx, MsgId::new(msg_id)).await {
Ok(msg) => msg,
Err(e) => {
if msg_id <= constants::DC_MSG_ID_LAST_SPECIAL {
warn!(
ctx,
"dc_get_msg called with special msg_id={msg_id}, returning empty msg"
);
message::Message::default()
} else {
error!(ctx, "dc_get_msg could not retrieve msg_id {msg_id}: {e:#}");
return ptr::null_mut();
}
}
};
let ffi_msg = MessageWrapper { context, message };
Box::into_raw(Box::new(ffi_msg))
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_download_full_msg(context: *mut dc_context_t, msg_id: u32) {
if context.is_null() {
eprintln!("ignoring careless call to dc_download_full_msg()");
return;
}
let ctx = &*context;
block_on(MsgId::new(msg_id).download_full(ctx))
.context("Failed to download message fully.")
.log_err(ctx)
.ok();
}
#[no_mangle]
pub unsafe extern "C" fn dc_may_be_valid_addr(addr: *const libc::c_char) -> libc::c_int {
if addr.is_null() {
eprintln!("ignoring careless call to dc_may_be_valid_addr()");
return 0;
}
contact::may_be_valid_addr(&to_string_lossy(addr)) as libc::c_int
}
#[no_mangle]
pub unsafe extern "C" fn dc_lookup_contact_id_by_addr(
context: *mut dc_context_t,
addr: *const libc::c_char,
) -> u32 {
if context.is_null() || addr.is_null() {
eprintln!("ignoring careless call to dc_lookup_contact_id_by_addr()");
return 0;
}
let ctx = &*context;
block_on(async move {
Contact::lookup_id_by_addr(ctx, &to_string_lossy(addr), Origin::IncomingReplyTo)
.await
.unwrap_or_log_default(ctx, "failed to lookup id")
.map(|id| id.to_u32())
.unwrap_or_default()
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_create_contact(
context: *mut dc_context_t,
name: *const libc::c_char,
addr: *const libc::c_char,
) -> u32 {
if context.is_null() || addr.is_null() {
eprintln!("ignoring careless call to dc_create_contact()");
return 0;
}
let ctx = &*context;
let name = to_string_lossy(name);
block_on(Contact::create(ctx, &name, &to_string_lossy(addr)))
.context("Cannot create contact")
.log_err(ctx)
.map(|id| id.to_u32())
.unwrap_or(0)
}
#[no_mangle]
pub unsafe extern "C" fn dc_add_address_book(
context: *mut dc_context_t,
addr_book: *const libc::c_char,
) -> libc::c_int {
if context.is_null() || addr_book.is_null() {
eprintln!("ignoring careless call to dc_add_address_book()");
return 0;
}
let ctx = &*context;
block_on(async move {
match Contact::add_address_book(ctx, &to_string_lossy(addr_book)).await {
Ok(cnt) => cnt as libc::c_int,
Err(_) => 0,
}
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_get_contacts(
context: *mut dc_context_t,
flags: u32,
query: *const libc::c_char,
) -> *mut dc_array::dc_array_t {
if context.is_null() {
eprintln!("ignoring careless call to dc_get_contacts()");
return ptr::null_mut();
}
let ctx = &*context;
let query = to_opt_string_lossy(query);
block_on(async move {
match Contact::get_all(ctx, flags, query.as_deref()).await {
Ok(contacts) => Box::into_raw(Box::new(dc_array_t::from(
contacts.iter().map(|id| id.to_u32()).collect::<Vec<u32>>(),
))),
Err(_) => ptr::null_mut(),
}
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_get_blocked_cnt(context: *mut dc_context_t) -> libc::c_int {
if context.is_null() {
eprintln!("ignoring careless call to dc_get_blocked_cnt()");
return 0;
}
let ctx = &*context;
block_on(async move {
Contact::get_all_blocked(ctx)
.await
.unwrap_or_log_default(ctx, "failed to get blocked count")
.len() as libc::c_int
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_get_blocked_contacts(
context: *mut dc_context_t,
) -> *mut dc_array::dc_array_t {
if context.is_null() {
eprintln!("ignoring careless call to dc_get_blocked_contacts()");
return ptr::null_mut();
}
let ctx = &*context;
block_on(async move {
Box::into_raw(Box::new(dc_array_t::from(
Contact::get_all_blocked(ctx)
.await
.context("Can't get blocked contacts")
.log_err(ctx)
.unwrap_or_default()
.iter()
.map(|id| id.to_u32())
.collect::<Vec<u32>>(),
)))
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_block_contact(
context: *mut dc_context_t,
contact_id: u32,
block: libc::c_int,
) {
let contact_id = ContactId::new(contact_id);
if context.is_null() || contact_id.is_special() {
eprintln!("ignoring careless call to dc_block_contact()");
return;
}
let ctx = &*context;
block_on(async move {
if block == 0 {
Contact::unblock(ctx, contact_id)
.await
.context("Can't unblock contact")
.log_err(ctx)
.ok();
} else {
Contact::block(ctx, contact_id)
.await
.context("Can't block contact")
.log_err(ctx)
.ok();
}
});
}
#[no_mangle]
pub unsafe extern "C" fn dc_get_contact_encrinfo(
context: *mut dc_context_t,
contact_id: u32,
) -> *mut libc::c_char {
if context.is_null() {
eprintln!("ignoring careless call to dc_get_contact_encrinfo()");
return "".strdup();
}
let ctx = &*context;
block_on(async move {
Contact::get_encrinfo(ctx, ContactId::new(contact_id))
.await
.map(|s| s.strdup())
.unwrap_or_else(|e| {
error!(ctx, "{e:#}");
ptr::null_mut()
})
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_delete_contact(
context: *mut dc_context_t,
contact_id: u32,
) -> libc::c_int {
let contact_id = ContactId::new(contact_id);
if context.is_null() || contact_id.is_special() {
eprintln!("ignoring careless call to dc_delete_contact()");
return 0;
}
let ctx = &*context;
block_on(async move {
match Contact::delete(ctx, contact_id).await {
Ok(_) => 1,
Err(err) => {
error!(ctx, "cannot delete contact: {err:#}");
0
}
}
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_get_contact(
context: *mut dc_context_t,
contact_id: u32,
) -> *mut dc_contact_t {
if context.is_null() {
eprintln!("ignoring careless call to dc_get_contact()");
return ptr::null_mut();
}
let ctx = &*context;
block_on(async move {
Contact::get_by_id(ctx, ContactId::new(contact_id))
.await
.map(|contact| Box::into_raw(Box::new(ContactWrapper { context, contact })))
.unwrap_or_else(|_| ptr::null_mut())
})
}
fn spawn_imex(ctx: Context, what: imex::ImexMode, param1: String, passphrase: Option<String>) {
spawn(async move {
imex::imex(&ctx, what, param1.as_ref(), passphrase)
.await
.context("IMEX failed")
.log_err(&ctx)
});
}
#[no_mangle]
pub unsafe extern "C" fn dc_imex(
context: *mut dc_context_t,
what_raw: libc::c_int,
param1: *const libc::c_char,
param2: *const libc::c_char,
) {
if context.is_null() {
eprintln!("ignoring careless call to dc_imex()");
return;
}
let what = match imex::ImexMode::from_i32(what_raw) {
Some(what) => what,
None => {
eprintln!("ignoring invalid argument {what_raw} to dc_imex");
return;
}
};
let passphrase = to_opt_string_lossy(param2);
let ctx = &*context;
if let Some(param1) = to_opt_string_lossy(param1) {
spawn_imex(ctx.clone(), what, param1, passphrase);
} else {
eprintln!("dc_imex called without a valid directory");
}
}
#[no_mangle]
pub unsafe extern "C" fn dc_imex_has_backup(
context: *mut dc_context_t,
dir: *const libc::c_char,
) -> *mut libc::c_char {
if context.is_null() || dir.is_null() {
eprintln!("ignoring careless call to dc_imex_has_backup()");
return ptr::null_mut(); }
let ctx = &*context;
block_on(async move {
match imex::has_backup(ctx, to_string_lossy(dir).as_ref()).await {
Ok(res) => res.strdup(),
Err(err) => {
warn!(ctx, "dc_imex_has_backup: {err:#}");
ptr::null_mut()
}
}
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_initiate_key_transfer(context: *mut dc_context_t) -> *mut libc::c_char {
if context.is_null() {
eprintln!("ignoring careless call to dc_initiate_key_transfer()");
return ptr::null_mut(); }
let ctx = &*context;
block_on(async move {
match imex::initiate_key_transfer(ctx).await {
Ok(res) => res.strdup(),
Err(err) => {
error!(ctx, "dc_initiate_key_transfer(): {err:#}");
ptr::null_mut()
}
}
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_continue_key_transfer(
context: *mut dc_context_t,
msg_id: u32,
setup_code: *const libc::c_char,
) -> libc::c_int {
if context.is_null() || msg_id <= constants::DC_MSG_ID_LAST_SPECIAL || setup_code.is_null() {
eprintln!("ignoring careless call to dc_continue_key_transfer()");
return 0;
}
let ctx = &*context;
block_on(async move {
match imex::continue_key_transfer(ctx, MsgId::new(msg_id), &to_string_lossy(setup_code))
.await
{
Ok(()) => 1,
Err(err) => {
warn!(ctx, "dc_continue_key_transfer: {err:#}");
0
}
}
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_stop_ongoing_process(context: *mut dc_context_t) {
if context.is_null() {
eprintln!("ignoring careless call to dc_stop_ongoing_process()");
return;
}
let ctx = &*context;
block_on(ctx.stop_ongoing());
}
#[no_mangle]
pub unsafe extern "C" fn dc_check_qr(
context: *mut dc_context_t,
qr: *const libc::c_char,
) -> *mut dc_lot_t {
if context.is_null() || qr.is_null() {
eprintln!("ignoring careless call to dc_check_qr()");
return ptr::null_mut();
}
let ctx = &*context;
let lot = match block_on(qr::check_qr(ctx, &to_string_lossy(qr))) {
Ok(qr) => qr.into(),
Err(err) => err.into(),
};
Box::into_raw(Box::new(lot))
}
#[no_mangle]
pub unsafe extern "C" fn dc_get_securejoin_qr(
context: *mut dc_context_t,
chat_id: u32,
) -> *mut libc::c_char {
if context.is_null() {
eprintln!("ignoring careless call to dc_get_securejoin_qr()");
return "".strdup();
}
let ctx = &*context;
let chat_id = if chat_id == 0 {
None
} else {
Some(ChatId::new(chat_id))
};
block_on(securejoin::get_securejoin_qr(ctx, chat_id))
.unwrap_or_else(|_| "".to_string())
.strdup()
}
#[no_mangle]
pub unsafe extern "C" fn dc_get_securejoin_qr_svg(
context: *mut dc_context_t,
chat_id: u32,
) -> *mut libc::c_char {
if context.is_null() {
eprintln!("ignoring careless call to generate_verification_qr()");
return "".strdup();
}
let ctx = &*context;
let chat_id = if chat_id == 0 {
None
} else {
Some(ChatId::new(chat_id))
};
block_on(get_securejoin_qr_svg(ctx, chat_id))
.unwrap_or_else(|_| "".to_string())
.strdup()
}
#[no_mangle]
pub unsafe extern "C" fn dc_join_securejoin(
context: *mut dc_context_t,
qr: *const libc::c_char,
) -> u32 {
if context.is_null() || qr.is_null() {
eprintln!("ignoring careless call to dc_join_securejoin()");
return 0;
}
let ctx = &*context;
block_on(async move {
securejoin::join_securejoin(ctx, &to_string_lossy(qr))
.await
.map(|chatid| chatid.to_u32())
.context("failed dc_join_securejoin() call")
.log_err(ctx)
.unwrap_or_default()
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_send_locations_to_chat(
context: *mut dc_context_t,
chat_id: u32,
seconds: libc::c_int,
) {
if context.is_null() || chat_id <= constants::DC_CHAT_ID_LAST_SPECIAL.to_u32() || seconds < 0 {
eprintln!("ignoring careless call to dc_send_locations_to_chat()");
return;
}
let ctx = &*context;
block_on(location::send_locations_to_chat(
ctx,
ChatId::new(chat_id),
seconds as i64,
))
.context("Failed dc_send_locations_to_chat()")
.log_err(ctx)
.ok();
}
#[no_mangle]
pub unsafe extern "C" fn dc_is_sending_locations_to_chat(
context: *mut dc_context_t,
chat_id: u32,
) -> libc::c_int {
if context.is_null() {
eprintln!("ignoring careless call to dc_is_sending_locations_to_chat()");
return 0;
}
let ctx = &*context;
let chat_id = if chat_id == 0 {
None
} else {
Some(ChatId::new(chat_id))
};
block_on(location::is_sending_locations_to_chat(ctx, chat_id))
.unwrap_or_log_default(ctx, "Failed dc_is_sending_locations_to_chat()") as libc::c_int
}
#[no_mangle]
pub unsafe extern "C" fn dc_set_location(
context: *mut dc_context_t,
latitude: libc::c_double,
longitude: libc::c_double,
accuracy: libc::c_double,
) -> libc::c_int {
if context.is_null() {
eprintln!("ignoring careless call to dc_set_location()");
return 0;
}
let ctx = &*context;
block_on(async move {
location::set(ctx, latitude, longitude, accuracy)
.await
.log_err(ctx)
.unwrap_or_default()
}) as libc::c_int
}
#[no_mangle]
pub unsafe extern "C" fn dc_get_locations(
context: *mut dc_context_t,
chat_id: u32,
contact_id: u32,
timestamp_begin: i64,
timestamp_end: i64,
) -> *mut dc_array::dc_array_t {
if context.is_null() {
eprintln!("ignoring careless call to dc_get_locations()");
return ptr::null_mut();
}
let ctx = &*context;
let chat_id = if chat_id == 0 {
None
} else {
Some(ChatId::new(chat_id))
};
let contact_id = if contact_id == 0 {
None
} else {
Some(contact_id)
};
block_on(async move {
let res = location::get_range(ctx, chat_id, contact_id, timestamp_begin, timestamp_end)
.await
.unwrap_or_log_default(ctx, "Failed get_locations");
Box::into_raw(Box::new(dc_array_t::from(res)))
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_delete_all_locations(context: *mut dc_context_t) {
if context.is_null() {
eprintln!("ignoring careless call to dc_delete_all_locations()");
return;
}
let ctx = &*context;
block_on(async move {
location::delete_all(ctx)
.await
.context("Failed to delete locations")
.log_err(ctx)
.ok()
});
}
#[no_mangle]
pub unsafe extern "C" fn dc_get_last_error(context: *mut dc_context_t) -> *mut libc::c_char {
if context.is_null() {
eprintln!("ignoring careless call to dc_get_last_error()");
return "".strdup();
}
let ctx = &*context;
ctx.get_last_error().strdup()
}
pub type dc_array_t = dc_array::dc_array_t;
#[no_mangle]
pub unsafe extern "C" fn dc_array_unref(a: *mut dc_array::dc_array_t) {
if a.is_null() {
eprintln!("ignoring careless call to dc_array_unref()");
return;
}
drop(Box::from_raw(a));
}
#[no_mangle]
pub unsafe extern "C" fn dc_array_get_cnt(array: *const dc_array_t) -> libc::size_t {
if array.is_null() {
eprintln!("ignoring careless call to dc_array_get_cnt()");
return 0;
}
(*array).len()
}
#[no_mangle]
pub unsafe extern "C" fn dc_array_get_id(array: *const dc_array_t, index: libc::size_t) -> u32 {
if array.is_null() {
eprintln!("ignoring careless call to dc_array_get_id()");
return 0;
}
(*array).get_id(index)
}
#[no_mangle]
pub unsafe extern "C" fn dc_array_get_latitude(
array: *const dc_array_t,
index: libc::size_t,
) -> libc::c_double {
if array.is_null() {
eprintln!("ignoring careless call to dc_array_get_latitude()");
return 0.0;
}
(*array).get_location(index).latitude
}
#[no_mangle]
pub unsafe extern "C" fn dc_array_get_longitude(
array: *const dc_array_t,
index: libc::size_t,
) -> libc::c_double {
if array.is_null() {
eprintln!("ignoring careless call to dc_array_get_longitude()");
return 0.0;
}
(*array).get_location(index).longitude
}
#[no_mangle]
pub unsafe extern "C" fn dc_array_get_accuracy(
array: *const dc_array_t,
index: libc::size_t,
) -> libc::c_double {
if array.is_null() {
eprintln!("ignoring careless call to dc_array_get_accuracy()");
return 0.0;
}
(*array).get_location(index).accuracy
}
#[no_mangle]
pub unsafe extern "C" fn dc_array_get_timestamp(
array: *const dc_array_t,
index: libc::size_t,
) -> i64 {
if array.is_null() {
eprintln!("ignoring careless call to dc_array_get_timestamp()");
return 0;
}
(*array).get_timestamp(index).unwrap_or_default()
}
#[no_mangle]
pub unsafe extern "C" fn dc_array_get_chat_id(
array: *const dc_array_t,
index: libc::size_t,
) -> libc::c_uint {
if array.is_null() {
eprintln!("ignoring careless call to dc_array_get_chat_id()");
return 0;
}
(*array).get_location(index).chat_id.to_u32()
}
#[no_mangle]
pub unsafe extern "C" fn dc_array_get_contact_id(
array: *const dc_array_t,
index: libc::size_t,
) -> libc::c_uint {
if array.is_null() {
eprintln!("ignoring careless call to dc_array_get_contact_id()");
return 0;
}
(*array).get_location(index).contact_id.to_u32()
}
#[no_mangle]
pub unsafe extern "C" fn dc_array_get_msg_id(
array: *const dc_array_t,
index: libc::size_t,
) -> libc::c_uint {
if array.is_null() {
eprintln!("ignoring careless call to dc_array_get_msg_id()");
return 0;
}
(*array).get_location(index).msg_id
}
#[no_mangle]
pub unsafe extern "C" fn dc_array_get_marker(
array: *const dc_array_t,
index: libc::size_t,
) -> *mut libc::c_char {
if array.is_null() {
eprintln!("ignoring careless call to dc_array_get_marker()");
return std::ptr::null_mut(); }
if let Some(s) = (*array).get_marker(index) {
s.strdup()
} else {
std::ptr::null_mut()
}
}
#[no_mangle]
pub unsafe extern "C" fn dc_array_search_id(
array: *const dc_array_t,
needle: libc::c_uint,
ret_index: *mut libc::size_t,
) -> libc::c_int {
if array.is_null() {
eprintln!("ignoring careless call to dc_array_search_id()");
return 0;
}
if let Some(i) = (*array).search_id(needle) {
if !ret_index.is_null() {
*ret_index = i
}
1
} else {
0
}
}
#[no_mangle]
pub unsafe fn dc_array_is_independent(
array: *const dc_array_t,
index: libc::size_t,
) -> libc::c_int {
if array.is_null() {
eprintln!("ignoring careless call to dc_array_is_independent()");
return 0;
}
(*array).get_location(index).independent as libc::c_int
}
pub struct ChatlistWrapper {
context: *const dc_context_t,
list: chatlist::Chatlist,
}
pub type dc_chatlist_t = ChatlistWrapper;
#[no_mangle]
pub unsafe extern "C" fn dc_chatlist_unref(chatlist: *mut dc_chatlist_t) {
if chatlist.is_null() {
eprintln!("ignoring careless call to dc_chatlist_unref()");
return;
}
drop(Box::from_raw(chatlist));
}
#[no_mangle]
pub unsafe extern "C" fn dc_chatlist_get_cnt(chatlist: *mut dc_chatlist_t) -> libc::size_t {
if chatlist.is_null() {
eprintln!("ignoring careless call to dc_chatlist_get_cnt()");
return 0;
}
let ffi_list = &*chatlist;
ffi_list.list.len() as libc::size_t
}
#[no_mangle]
pub unsafe extern "C" fn dc_chatlist_get_chat_id(
chatlist: *mut dc_chatlist_t,
index: libc::size_t,
) -> u32 {
if chatlist.is_null() {
eprintln!("ignoring careless call to dc_chatlist_get_chat_id()");
return 0;
}
let ffi_list = &*chatlist;
let ctx = &*ffi_list.context;
match ffi_list.list.get_chat_id(index) {
Ok(chat_id) => chat_id.to_u32(),
Err(err) => {
warn!(ctx, "get_chat_id failed: {err:#}");
0
}
}
}
#[no_mangle]
pub unsafe extern "C" fn dc_chatlist_get_msg_id(
chatlist: *mut dc_chatlist_t,
index: libc::size_t,
) -> u32 {
if chatlist.is_null() {
eprintln!("ignoring careless call to dc_chatlist_get_msg_id()");
return 0;
}
let ffi_list = &*chatlist;
let ctx = &*ffi_list.context;
match ffi_list.list.get_msg_id(index) {
Ok(msg_id) => msg_id.map_or(0, |msg_id| msg_id.to_u32()),
Err(err) => {
warn!(ctx, "get_msg_id failed: {err:#}");
0
}
}
}
#[no_mangle]
pub unsafe extern "C" fn dc_chatlist_get_summary(
chatlist: *mut dc_chatlist_t,
index: libc::size_t,
chat: *mut dc_chat_t,
) -> *mut dc_lot_t {
if chatlist.is_null() {
eprintln!("ignoring careless call to dc_chatlist_get_summary()");
return ptr::null_mut();
}
let maybe_chat = if chat.is_null() {
None
} else {
let ffi_chat = &*chat;
Some(&ffi_chat.chat)
};
let ffi_list = &*chatlist;
let ctx = &*ffi_list.context;
block_on(async move {
let summary = ffi_list
.list
.get_summary(ctx, index, maybe_chat)
.await
.context("get_summary failed")
.log_err(ctx)
.unwrap_or_default();
Box::into_raw(Box::new(summary.into()))
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_chatlist_get_summary2(
context: *mut dc_context_t,
chat_id: u32,
msg_id: u32,
) -> *mut dc_lot_t {
if context.is_null() {
eprintln!("ignoring careless call to dc_chatlist_get_summary2()");
return ptr::null_mut();
}
let ctx = &*context;
let msg_id = if msg_id == 0 {
None
} else {
Some(MsgId::new(msg_id))
};
let summary = block_on(Chatlist::get_summary2(
ctx,
ChatId::new(chat_id),
msg_id,
None,
))
.context("get_summary2 failed")
.log_err(ctx)
.unwrap_or_default();
Box::into_raw(Box::new(summary.into()))
}
#[no_mangle]
pub unsafe extern "C" fn dc_chatlist_get_context(
chatlist: *mut dc_chatlist_t,
) -> *const dc_context_t {
if chatlist.is_null() {
eprintln!("ignoring careless call to dc_chatlist_get_context()");
return ptr::null_mut();
}
let ffi_list = &*chatlist;
ffi_list.context
}
pub struct ChatWrapper {
context: *const dc_context_t,
chat: chat::Chat,
}
pub type dc_chat_t = ChatWrapper;
#[no_mangle]
pub unsafe extern "C" fn dc_chat_unref(chat: *mut dc_chat_t) {
if chat.is_null() {
eprintln!("ignoring careless call to dc_chat_unref()");
return;
}
drop(Box::from_raw(chat));
}
#[no_mangle]
pub unsafe extern "C" fn dc_chat_get_id(chat: *mut dc_chat_t) -> u32 {
if chat.is_null() {
eprintln!("ignoring careless call to dc_chat_get_id()");
return 0;
}
let ffi_chat = &*chat;
ffi_chat.chat.get_id().to_u32()
}
#[no_mangle]
pub unsafe extern "C" fn dc_chat_get_type(chat: *mut dc_chat_t) -> libc::c_int {
if chat.is_null() {
eprintln!("ignoring careless call to dc_chat_get_type()");
return 0;
}
let ffi_chat = &*chat;
ffi_chat.chat.get_type() as libc::c_int
}
#[no_mangle]
pub unsafe extern "C" fn dc_chat_get_name(chat: *mut dc_chat_t) -> *mut libc::c_char {
if chat.is_null() {
eprintln!("ignoring careless call to dc_chat_get_name()");
return "".strdup();
}
let ffi_chat = &*chat;
ffi_chat.chat.get_name().strdup()
}
#[no_mangle]
pub unsafe extern "C" fn dc_chat_get_mailinglist_addr(chat: *mut dc_chat_t) -> *mut libc::c_char {
if chat.is_null() {
eprintln!("ignoring careless call to dc_chat_get_mailinglist_addr()");
return "".strdup();
}
let ffi_chat = &*chat;
ffi_chat
.chat
.get_mailinglist_addr()
.unwrap_or_default()
.strdup()
}
#[no_mangle]
pub unsafe extern "C" fn dc_chat_get_profile_image(chat: *mut dc_chat_t) -> *mut libc::c_char {
if chat.is_null() {
eprintln!("ignoring careless call to dc_chat_get_profile_image()");
return ptr::null_mut(); }
let ffi_chat = &*chat;
let ctx = &*ffi_chat.context;
block_on(async move {
match ffi_chat.chat.get_profile_image(ctx).await {
Ok(Some(p)) => p.to_string_lossy().strdup(),
Ok(None) => ptr::null_mut(),
Err(err) => {
error!(ctx, "failed to get profile image: {err:#}");
ptr::null_mut()
}
}
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_chat_get_color(chat: *mut dc_chat_t) -> u32 {
if chat.is_null() {
eprintln!("ignoring careless call to dc_chat_get_color()");
return 0;
}
let ffi_chat = &*chat;
let ctx = &*ffi_chat.context;
block_on(ffi_chat.chat.get_color(ctx)).unwrap_or_log_default(ctx, "Failed get_color")
}
#[no_mangle]
pub unsafe extern "C" fn dc_chat_get_visibility(chat: *mut dc_chat_t) -> libc::c_int {
if chat.is_null() {
eprintln!("ignoring careless call to dc_chat_get_visibility()");
return 0;
}
let ffi_chat = &*chat;
match ffi_chat.chat.visibility {
ChatVisibility::Normal => 0,
ChatVisibility::Archived => 1,
ChatVisibility::Pinned => 2,
}
}
#[no_mangle]
pub unsafe extern "C" fn dc_chat_is_contact_request(chat: *mut dc_chat_t) -> libc::c_int {
if chat.is_null() {
eprintln!("ignoring careless call to dc_chat_is_contact_request()");
return 0;
}
let ffi_chat = &*chat;
ffi_chat.chat.is_contact_request() as libc::c_int
}
#[no_mangle]
pub unsafe extern "C" fn dc_chat_is_unpromoted(chat: *mut dc_chat_t) -> libc::c_int {
if chat.is_null() {
eprintln!("ignoring careless call to dc_chat_is_unpromoted()");
return 0;
}
let ffi_chat = &*chat;
ffi_chat.chat.is_unpromoted() as libc::c_int
}
#[no_mangle]
pub unsafe extern "C" fn dc_chat_is_self_talk(chat: *mut dc_chat_t) -> libc::c_int {
if chat.is_null() {
eprintln!("ignoring careless call to dc_chat_is_self_talk()");
return 0;
}
let ffi_chat = &*chat;
ffi_chat.chat.is_self_talk() as libc::c_int
}
#[no_mangle]
pub unsafe extern "C" fn dc_chat_is_device_talk(chat: *mut dc_chat_t) -> libc::c_int {
if chat.is_null() {
eprintln!("ignoring careless call to dc_chat_is_device_talk()");
return 0;
}
let ffi_chat = &*chat;
ffi_chat.chat.is_device_talk() as libc::c_int
}
#[no_mangle]
pub unsafe extern "C" fn dc_chat_can_send(chat: *mut dc_chat_t) -> libc::c_int {
if chat.is_null() {
eprintln!("ignoring careless call to dc_chat_can_send()");
return 0;
}
let ffi_chat = &*chat;
let ctx = &*ffi_chat.context;
block_on(ffi_chat.chat.can_send(ctx))
.context("can_send failed")
.log_err(ctx)
.unwrap_or_default() as libc::c_int
}
#[no_mangle]
pub unsafe extern "C" fn dc_chat_is_protected(chat: *mut dc_chat_t) -> libc::c_int {
if chat.is_null() {
eprintln!("ignoring careless call to dc_chat_is_protected()");
return 0;
}
let ffi_chat = &*chat;
ffi_chat.chat.is_protected() as libc::c_int
}
#[no_mangle]
pub unsafe extern "C" fn dc_chat_is_protection_broken(chat: *mut dc_chat_t) -> libc::c_int {
if chat.is_null() {
eprintln!("ignoring careless call to dc_chat_is_protection_broken()");
return 0;
}
let ffi_chat = &*chat;
ffi_chat.chat.is_protection_broken() as libc::c_int
}
#[no_mangle]
pub unsafe extern "C" fn dc_chat_is_sending_locations(chat: *mut dc_chat_t) -> libc::c_int {
if chat.is_null() {
eprintln!("ignoring careless call to dc_chat_is_sending_locations()");
return 0;
}
let ffi_chat = &*chat;
ffi_chat.chat.is_sending_locations() as libc::c_int
}
#[no_mangle]
pub unsafe extern "C" fn dc_chat_is_muted(chat: *mut dc_chat_t) -> libc::c_int {
if chat.is_null() {
eprintln!("ignoring careless call to dc_chat_is_muted()");
return 0;
}
let ffi_chat = &*chat;
ffi_chat.chat.is_muted() as libc::c_int
}
#[no_mangle]
pub unsafe extern "C" fn dc_chat_get_remaining_mute_duration(chat: *mut dc_chat_t) -> i64 {
if chat.is_null() {
eprintln!("ignoring careless call to dc_chat_get_remaining_mute_duration()");
return 0;
}
let ffi_chat = &*chat;
if !ffi_chat.chat.is_muted() {
return 0;
}
match ffi_chat.chat.mute_duration {
MuteDuration::NotMuted => 0,
MuteDuration::Forever => -1,
MuteDuration::Until(when) => when
.duration_since(SystemTime::now())
.map(|d| d.as_secs() as i64)
.unwrap_or(0),
}
}
#[no_mangle]
pub unsafe extern "C" fn dc_chat_get_info_json(
context: *mut dc_context_t,
chat_id: u32,
) -> *mut libc::c_char {
if context.is_null() {
eprintln!("ignoring careless call to dc_chat_get_info_json()");
return "".strdup();
}
let ctx = &*context;
block_on(async move {
let chat = match chat::Chat::load_from_db(ctx, ChatId::new(chat_id)).await {
Ok(chat) => chat,
Err(err) => {
error!(ctx, "dc_get_chat_info_json() failed to load chat: {err:#}");
return "".strdup();
}
};
let info = match chat.get_info(ctx).await {
Ok(info) => info,
Err(err) => {
error!(
ctx,
"dc_get_chat_info_json() failed to get chat info: {err:#}"
);
return "".strdup();
}
};
serde_json::to_string(&info)
.unwrap_or_log_default(ctx, "dc_get_chat_info_json() failed to serialise to json")
.strdup()
})
}
pub struct MessageWrapper {
context: *const dc_context_t,
message: message::Message,
}
pub type dc_msg_t = MessageWrapper;
#[no_mangle]
pub unsafe extern "C" fn dc_msg_new(
context: *mut dc_context_t,
viewtype: libc::c_int,
) -> *mut dc_msg_t {
if context.is_null() {
eprintln!("ignoring careless call to dc_msg_new()");
return ptr::null_mut();
}
let context = &*context;
let viewtype = from_prim(viewtype).expect(&format!("invalid viewtype = {viewtype}"));
let msg = MessageWrapper {
context,
message: message::Message::new(viewtype),
};
Box::into_raw(Box::new(msg))
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_unref(msg: *mut dc_msg_t) {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_unref()");
return;
}
drop(Box::from_raw(msg));
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_get_id(msg: *mut dc_msg_t) -> u32 {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_get_id()");
return 0;
}
let ffi_msg = &*msg;
ffi_msg.message.get_id().to_u32()
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_get_from_id(msg: *mut dc_msg_t) -> u32 {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_get_from_id()");
return 0;
}
let ffi_msg = &*msg;
ffi_msg.message.get_from_id().to_u32()
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_get_chat_id(msg: *mut dc_msg_t) -> u32 {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_get_chat_id()");
return 0;
}
let ffi_msg = &*msg;
ffi_msg.message.get_chat_id().to_u32()
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_get_viewtype(msg: *mut dc_msg_t) -> libc::c_int {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_get_viewtype()");
return 0;
}
let ffi_msg = &*msg;
ffi_msg
.message
.get_viewtype()
.to_i64()
.expect("impossible: Viewtype -> i64 conversion failed") as libc::c_int
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_get_state(msg: *mut dc_msg_t) -> libc::c_int {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_get_state()");
return 0;
}
let ffi_msg = &*msg;
ffi_msg.message.get_state() as libc::c_int
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_get_download_state(msg: *mut dc_msg_t) -> libc::c_int {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_get_download_state()");
return 0;
}
let ffi_msg = &*msg;
ffi_msg.message.download_state() as libc::c_int
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_get_timestamp(msg: *mut dc_msg_t) -> i64 {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_get_received_timestamp()");
return 0;
}
let ffi_msg = &*msg;
ffi_msg.message.get_timestamp()
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_get_received_timestamp(msg: *mut dc_msg_t) -> i64 {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_get_received_timestamp()");
return 0;
}
let ffi_msg = &*msg;
ffi_msg.message.get_received_timestamp()
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_get_sort_timestamp(msg: *mut dc_msg_t) -> i64 {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_get_sort_timestamp()");
return 0;
}
let ffi_msg = &*msg;
ffi_msg.message.get_sort_timestamp()
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_get_text(msg: *mut dc_msg_t) -> *mut libc::c_char {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_get_text()");
return "".strdup();
}
let ffi_msg = &*msg;
ffi_msg.message.get_text().strdup()
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_get_subject(msg: *mut dc_msg_t) -> *mut libc::c_char {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_get_subject()");
return "".strdup();
}
let ffi_msg = &*msg;
ffi_msg.message.get_subject().strdup()
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_get_file(msg: *mut dc_msg_t) -> *mut libc::c_char {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_get_file()");
return "".strdup();
}
let ffi_msg = &*msg;
let ctx = &*ffi_msg.context;
ffi_msg
.message
.get_file(ctx)
.map(|p| p.to_string_lossy().strdup())
.unwrap_or_else(|| "".strdup())
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_get_filename(msg: *mut dc_msg_t) -> *mut libc::c_char {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_get_filename()");
return "".strdup();
}
let ffi_msg = &*msg;
ffi_msg.message.get_filename().unwrap_or_default().strdup()
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_get_webxdc_blob(
msg: *mut dc_msg_t,
filename: *const libc::c_char,
ret_bytes: *mut libc::size_t,
) -> *mut libc::c_char {
if msg.is_null() || filename.is_null() || ret_bytes.is_null() {
eprintln!("ignoring careless call to dc_msg_get_webxdc_blob()");
return ptr::null_mut();
}
let ffi_msg = &*msg;
let ctx = &*ffi_msg.context;
let blob = block_on(async move {
ffi_msg
.message
.get_webxdc_blob(ctx, &to_string_lossy(filename))
.await
});
match blob {
Ok(blob) => {
*ret_bytes = blob.len();
let ptr = libc::malloc(*ret_bytes);
libc::memcpy(ptr, blob.as_ptr() as *mut libc::c_void, *ret_bytes);
ptr as *mut libc::c_char
}
Err(err) => {
eprintln!("failed read blob from archive: {err}");
ptr::null_mut()
}
}
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_get_webxdc_info(msg: *mut dc_msg_t) -> *mut libc::c_char {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_get_webxdc_info()");
return "".strdup();
}
let ffi_msg = &*msg;
let ctx = &*ffi_msg.context;
block_on(async move {
let info = match ffi_msg.message.get_webxdc_info(ctx).await {
Ok(info) => info,
Err(err) => {
error!(ctx, "dc_msg_get_webxdc_info() failed to get info: {err:#}");
return "".strdup();
}
};
serde_json::to_string(&info)
.unwrap_or_log_default(ctx, "dc_msg_get_webxdc_info() failed to serialise to json")
.strdup()
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_get_filemime(msg: *mut dc_msg_t) -> *mut libc::c_char {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_get_filemime()");
return "".strdup();
}
let ffi_msg = &*msg;
if let Some(x) = ffi_msg.message.get_filemime() {
x.strdup()
} else {
"".strdup()
}
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_get_filebytes(msg: *mut dc_msg_t) -> u64 {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_get_filebytes()");
return 0;
}
let ffi_msg = &*msg;
let ctx = &*ffi_msg.context;
block_on(ffi_msg.message.get_filebytes(ctx))
.unwrap_or_log_default(ctx, "Cannot get file size")
.unwrap_or_default()
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_get_width(msg: *mut dc_msg_t) -> libc::c_int {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_get_width()");
return 0;
}
let ffi_msg = &*msg;
ffi_msg.message.get_width()
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_get_height(msg: *mut dc_msg_t) -> libc::c_int {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_get_height()");
return 0;
}
let ffi_msg = &*msg;
ffi_msg.message.get_height()
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_get_duration(msg: *mut dc_msg_t) -> libc::c_int {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_get_duration()");
return 0;
}
let ffi_msg = &*msg;
ffi_msg.message.get_duration()
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_get_showpadlock(msg: *mut dc_msg_t) -> libc::c_int {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_get_showpadlock()");
return 0;
}
let ffi_msg = &*msg;
ffi_msg.message.get_showpadlock() as libc::c_int
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_is_bot(msg: *mut dc_msg_t) -> libc::c_int {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_is_bot()");
return 0;
}
let ffi_msg = &*msg;
ffi_msg.message.is_bot() as libc::c_int
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_get_ephemeral_timer(msg: *mut dc_msg_t) -> u32 {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_get_ephemeral_timer()");
return 0;
}
let ffi_msg = &*msg;
ffi_msg.message.get_ephemeral_timer().to_u32()
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_get_ephemeral_timestamp(msg: *mut dc_msg_t) -> i64 {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_get_ephemeral_timer()");
return 0;
}
let ffi_msg = &*msg;
ffi_msg.message.get_ephemeral_timestamp()
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_get_summary(
msg: *mut dc_msg_t,
chat: *mut dc_chat_t,
) -> *mut dc_lot_t {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_get_summary()");
return ptr::null_mut();
}
let maybe_chat = if chat.is_null() {
None
} else {
let ffi_chat = &*chat;
Some(&ffi_chat.chat)
};
let ffi_msg = &mut *msg;
let ctx = &*ffi_msg.context;
let summary = block_on(ffi_msg.message.get_summary(ctx, maybe_chat))
.context("dc_msg_get_summary failed")
.log_err(ctx)
.unwrap_or_default();
Box::into_raw(Box::new(summary.into()))
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_get_summarytext(
msg: *mut dc_msg_t,
approx_characters: libc::c_int,
) -> *mut libc::c_char {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_get_summarytext()");
return "".strdup();
}
let ffi_msg = &mut *msg;
let ctx = &*ffi_msg.context;
let summary = block_on(ffi_msg.message.get_summary(ctx, None))
.context("dc_msg_get_summarytext failed")
.log_err(ctx)
.unwrap_or_default();
match usize::try_from(approx_characters) {
Ok(chars) => summary.truncated_text(chars).strdup(),
Err(_) => summary.text.strdup(),
}
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_get_override_sender_name(msg: *mut dc_msg_t) -> *mut libc::c_char {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_get_override_sender_name()");
return "".strdup();
}
let ffi_msg = &mut *msg;
ffi_msg.message.get_override_sender_name().strdup()
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_has_deviating_timestamp(msg: *mut dc_msg_t) -> libc::c_int {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_has_deviating_timestamp()");
return 0;
}
let ffi_msg = &*msg;
ffi_msg.message.has_deviating_timestamp().into()
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_has_location(msg: *mut dc_msg_t) -> libc::c_int {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_has_location()");
return 0;
}
let ffi_msg = &*msg;
ffi_msg.message.has_location() as libc::c_int
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_is_sent(msg: *mut dc_msg_t) -> libc::c_int {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_is_sent()");
return 0;
}
let ffi_msg = &*msg;
ffi_msg.message.is_sent().into()
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_is_forwarded(msg: *mut dc_msg_t) -> libc::c_int {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_is_forwarded()");
return 0;
}
let ffi_msg = &*msg;
ffi_msg.message.is_forwarded().into()
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_is_info(msg: *mut dc_msg_t) -> libc::c_int {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_is_info()");
return 0;
}
let ffi_msg = &*msg;
ffi_msg.message.is_info().into()
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_get_info_type(msg: *mut dc_msg_t) -> libc::c_int {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_get_info_type()");
return 0;
}
let ffi_msg = &*msg;
ffi_msg.message.get_info_type() as libc::c_int
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_is_increation(msg: *mut dc_msg_t) -> libc::c_int {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_is_increation()");
return 0;
}
let ffi_msg = &*msg;
ffi_msg.message.is_increation().into()
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_is_setupmessage(msg: *mut dc_msg_t) -> libc::c_int {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_is_setupmessage()");
return 0;
}
let ffi_msg = &*msg;
ffi_msg.message.is_setupmessage().into()
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_has_html(msg: *mut dc_msg_t) -> libc::c_int {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_has_html()");
return 0;
}
let ffi_msg = &*msg;
ffi_msg.message.has_html().into()
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_get_videochat_url(msg: *mut dc_msg_t) -> *mut libc::c_char {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_get_videochat_url()");
return "".strdup();
}
let ffi_msg = &*msg;
ffi_msg
.message
.get_videochat_url()
.unwrap_or_default()
.strdup()
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_get_videochat_type(msg: *mut dc_msg_t) -> libc::c_int {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_get_videochat_type()");
return 0;
}
let ffi_msg = &*msg;
ffi_msg.message.get_videochat_type().unwrap_or_default() as i32
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_get_setupcodebegin(msg: *mut dc_msg_t) -> *mut libc::c_char {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_get_setupcodebegin()");
return "".strdup();
}
let ffi_msg = &*msg;
let ctx = &*ffi_msg.context;
block_on(ffi_msg.message.get_setupcodebegin(ctx))
.unwrap_or_default()
.strdup()
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_set_text(msg: *mut dc_msg_t, text: *const libc::c_char) {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_set_text()");
return;
}
let ffi_msg = &mut *msg;
ffi_msg.message.set_text(to_string_lossy(text))
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_set_html(msg: *mut dc_msg_t, html: *const libc::c_char) {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_set_html()");
return;
}
let ffi_msg = &mut *msg;
ffi_msg.message.set_html(to_opt_string_lossy(html))
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_set_subject(msg: *mut dc_msg_t, subject: *const libc::c_char) {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_get_subject()");
return;
}
let ffi_msg = &mut *msg;
ffi_msg.message.set_subject(to_string_lossy(subject));
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_set_override_sender_name(
msg: *mut dc_msg_t,
name: *const libc::c_char,
) {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_set_override_sender_name()");
return;
}
let ffi_msg = &mut *msg;
ffi_msg
.message
.set_override_sender_name(to_opt_string_lossy(name))
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_set_file(
msg: *mut dc_msg_t,
file: *const libc::c_char,
filemime: *const libc::c_char,
) {
if msg.is_null() || file.is_null() {
eprintln!("ignoring careless call to dc_msg_set_file()");
return;
}
let ffi_msg = &mut *msg;
ffi_msg.message.set_file(
to_string_lossy(file),
to_opt_string_lossy(filemime).as_deref(),
)
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_set_dimension(
msg: *mut dc_msg_t,
width: libc::c_int,
height: libc::c_int,
) {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_set_dimension()");
return;
}
let ffi_msg = &mut *msg;
ffi_msg.message.set_dimension(width, height)
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_set_duration(msg: *mut dc_msg_t, duration: libc::c_int) {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_set_duration()");
return;
}
let ffi_msg = &mut *msg;
ffi_msg.message.set_duration(duration)
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_set_location(
msg: *mut dc_msg_t,
latitude: libc::c_double,
longitude: libc::c_double,
) {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_set_location()");
return;
}
let ffi_msg = &mut *msg;
ffi_msg.message.set_location(latitude, longitude)
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_latefiling_mediasize(
msg: *mut dc_msg_t,
width: libc::c_int,
height: libc::c_int,
duration: libc::c_int,
) {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_latefiling_mediasize()");
return;
}
let ffi_msg = &mut *msg;
let ctx = &*ffi_msg.context;
block_on({
ffi_msg
.message
.latefiling_mediasize(ctx, width, height, duration)
})
.context("Cannot set media size")
.log_err(ctx)
.ok();
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_get_error(msg: *mut dc_msg_t) -> *mut libc::c_char {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_get_error()");
return ptr::null_mut();
}
let ffi_msg = &*msg;
match ffi_msg.message.error() {
Some(error) => error.strdup(),
None => ptr::null_mut(),
}
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_set_quote(msg: *mut dc_msg_t, quote: *const dc_msg_t) {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_set_quote()");
return;
}
let ffi_msg = &mut *msg;
let quote_msg = if quote.is_null() {
None
} else {
let ffi_quote = &*quote;
if ffi_msg.context != ffi_quote.context {
eprintln!("ignoring attempt to quote message from a different context");
return;
}
Some(&ffi_quote.message)
};
block_on(async move {
ffi_msg
.message
.set_quote(&*ffi_msg.context, quote_msg)
.await
.context("failed to set quote")
.log_err(&*ffi_msg.context)
.ok();
});
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_get_quoted_text(msg: *const dc_msg_t) -> *mut libc::c_char {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_get_quoted_text()");
return ptr::null_mut();
}
let ffi_msg: &MessageWrapper = &*msg;
ffi_msg
.message
.quoted_text()
.map_or_else(ptr::null_mut, |s| s.strdup())
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_get_quoted_msg(msg: *const dc_msg_t) -> *mut dc_msg_t {
if msg.is_null() {
eprintln!("ignoring careless call to dc_get_quoted_msg()");
return ptr::null_mut();
}
let ffi_msg: &MessageWrapper = &*msg;
let context = &*ffi_msg.context;
let res = block_on(async move {
ffi_msg
.message
.quoted_message(context)
.await
.context("failed to get quoted message")
.log_err(context)
.unwrap_or(None)
});
match res {
Some(message) => Box::into_raw(Box::new(MessageWrapper { context, message })),
None => ptr::null_mut(),
}
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_get_parent(msg: *const dc_msg_t) -> *mut dc_msg_t {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_get_parent()");
return ptr::null_mut();
}
let ffi_msg: &MessageWrapper = &*msg;
let context = &*ffi_msg.context;
let res = block_on(async move {
ffi_msg
.message
.parent(context)
.await
.context("failed to get parent message")
.log_err(context)
.unwrap_or(None)
});
match res {
Some(message) => Box::into_raw(Box::new(MessageWrapper { context, message })),
None => ptr::null_mut(),
}
}
#[no_mangle]
pub unsafe extern "C" fn dc_msg_force_plaintext(msg: *mut dc_msg_t) {
if msg.is_null() {
eprintln!("ignoring careless call to dc_msg_force_plaintext()");
return;
}
let ffi_msg = &mut *msg;
ffi_msg.message.force_plaintext();
}
pub struct ContactWrapper {
context: *const dc_context_t,
contact: contact::Contact,
}
pub type dc_contact_t = ContactWrapper;
#[no_mangle]
pub unsafe extern "C" fn dc_contact_unref(contact: *mut dc_contact_t) {
if contact.is_null() {
eprintln!("ignoring careless call to dc_contact_unref()");
return;
}
drop(Box::from_raw(contact));
}
#[no_mangle]
pub unsafe extern "C" fn dc_contact_get_id(contact: *mut dc_contact_t) -> u32 {
if contact.is_null() {
eprintln!("ignoring careless call to dc_contact_get_id()");
return 0;
}
let ffi_contact = &*contact;
ffi_contact.contact.get_id().to_u32()
}
#[no_mangle]
pub unsafe extern "C" fn dc_contact_get_addr(contact: *mut dc_contact_t) -> *mut libc::c_char {
if contact.is_null() {
eprintln!("ignoring careless call to dc_contact_get_addr()");
return "".strdup();
}
let ffi_contact = &*contact;
ffi_contact.contact.get_addr().strdup()
}
#[no_mangle]
pub unsafe extern "C" fn dc_contact_get_name(contact: *mut dc_contact_t) -> *mut libc::c_char {
if contact.is_null() {
eprintln!("ignoring careless call to dc_contact_get_name()");
return "".strdup();
}
let ffi_contact = &*contact;
ffi_contact.contact.get_name().strdup()
}
#[no_mangle]
pub unsafe extern "C" fn dc_contact_get_auth_name(contact: *mut dc_contact_t) -> *mut libc::c_char {
if contact.is_null() {
eprintln!("ignoring careless call to dc_contact_get_auth_name()");
return "".strdup();
}
let ffi_contact = &*contact;
ffi_contact.contact.get_authname().strdup()
}
#[no_mangle]
pub unsafe extern "C" fn dc_contact_get_display_name(
contact: *mut dc_contact_t,
) -> *mut libc::c_char {
if contact.is_null() {
eprintln!("ignoring careless call to dc_contact_get_display_name()");
return "".strdup();
}
let ffi_contact = &*contact;
ffi_contact.contact.get_display_name().strdup()
}
#[no_mangle]
pub unsafe extern "C" fn dc_contact_get_name_n_addr(
contact: *mut dc_contact_t,
) -> *mut libc::c_char {
if contact.is_null() {
eprintln!("ignoring careless call to dc_contact_get_name_n_addr()");
return "".strdup();
}
let ffi_contact = &*contact;
ffi_contact.contact.get_name_n_addr().strdup()
}
#[no_mangle]
pub unsafe extern "C" fn dc_contact_get_profile_image(
contact: *mut dc_contact_t,
) -> *mut libc::c_char {
if contact.is_null() {
eprintln!("ignoring careless call to dc_contact_get_profile_image()");
return ptr::null_mut(); }
let ffi_contact = &*contact;
let ctx = &*ffi_contact.context;
block_on(async move {
ffi_contact
.contact
.get_profile_image(ctx)
.await
.unwrap_or_log_default(ctx, "failed to get profile image")
.map(|p| p.to_string_lossy().strdup())
.unwrap_or_else(std::ptr::null_mut)
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_contact_get_color(contact: *mut dc_contact_t) -> u32 {
if contact.is_null() {
eprintln!("ignoring careless call to dc_contact_get_color()");
return 0;
}
let ffi_contact = &*contact;
ffi_contact.contact.get_color()
}
#[no_mangle]
pub unsafe extern "C" fn dc_contact_get_status(contact: *mut dc_contact_t) -> *mut libc::c_char {
if contact.is_null() {
eprintln!("ignoring careless call to dc_contact_get_status()");
return "".strdup();
}
let ffi_contact = &*contact;
ffi_contact.contact.get_status().strdup()
}
#[no_mangle]
pub unsafe extern "C" fn dc_contact_get_last_seen(contact: *mut dc_contact_t) -> i64 {
if contact.is_null() {
eprintln!("ignoring careless call to dc_contact_get_last_seen()");
return 0;
}
let ffi_contact = &*contact;
ffi_contact.contact.last_seen()
}
#[no_mangle]
pub unsafe extern "C" fn dc_contact_was_seen_recently(contact: *mut dc_contact_t) -> libc::c_int {
if contact.is_null() {
eprintln!("ignoring careless call to dc_contact_was_seen_recently()");
return 0;
}
let ffi_contact = &*contact;
ffi_contact.contact.was_seen_recently() as libc::c_int
}
#[no_mangle]
pub unsafe extern "C" fn dc_contact_is_blocked(contact: *mut dc_contact_t) -> libc::c_int {
if contact.is_null() {
eprintln!("ignoring careless call to dc_contact_is_blocked()");
return 0;
}
let ffi_contact = &*contact;
ffi_contact.contact.is_blocked() as libc::c_int
}
#[no_mangle]
pub unsafe extern "C" fn dc_contact_is_verified(contact: *mut dc_contact_t) -> libc::c_int {
if contact.is_null() {
eprintln!("ignoring careless call to dc_contact_is_verified()");
return 0;
}
let ffi_contact = &*contact;
let ctx = &*ffi_contact.context;
if block_on(ffi_contact.contact.is_verified(ctx))
.context("is_verified failed")
.log_err(ctx)
.unwrap_or_default()
{
2
} else {
0
}
}
#[no_mangle]
pub unsafe extern "C" fn dc_contact_is_bot(contact: *mut dc_contact_t) -> libc::c_int {
if contact.is_null() {
eprintln!("ignoring careless call to dc_contact_is_bot()");
return 0;
}
(*contact).contact.is_bot() as libc::c_int
}
#[no_mangle]
pub unsafe extern "C" fn dc_contact_get_verifier_id(contact: *mut dc_contact_t) -> u32 {
if contact.is_null() {
eprintln!("ignoring careless call to dc_contact_get_verifier_id()");
return 0;
}
let ffi_contact = &*contact;
let ctx = &*ffi_contact.context;
let verifier_contact_id = block_on(ffi_contact.contact.get_verifier_id(ctx))
.context("failed to get verifier")
.log_err(ctx)
.unwrap_or_default()
.unwrap_or_default();
verifier_contact_id.to_u32()
}
pub type dc_lot_t = lot::Lot;
#[no_mangle]
pub unsafe extern "C" fn dc_lot_unref(lot: *mut dc_lot_t) {
if lot.is_null() {
eprintln!("ignoring careless call to dc_lot_unref()");
return;
}
drop(Box::from_raw(lot));
}
#[no_mangle]
pub unsafe extern "C" fn dc_lot_get_text1(lot: *mut dc_lot_t) -> *mut libc::c_char {
if lot.is_null() {
eprintln!("ignoring careless call to dc_lot_get_text1()");
return ptr::null_mut(); }
let lot = &*lot;
lot.get_text1().strdup()
}
#[no_mangle]
pub unsafe extern "C" fn dc_lot_get_text2(lot: *mut dc_lot_t) -> *mut libc::c_char {
if lot.is_null() {
eprintln!("ignoring careless call to dc_lot_get_text2()");
return ptr::null_mut(); }
let lot = &*lot;
lot.get_text2().strdup()
}
#[no_mangle]
pub unsafe extern "C" fn dc_lot_get_text1_meaning(lot: *mut dc_lot_t) -> libc::c_int {
if lot.is_null() {
eprintln!("ignoring careless call to dc_lot_get_text1_meaning()");
return 0;
}
let lot = &*lot;
lot.get_text1_meaning() as libc::c_int
}
#[no_mangle]
pub unsafe extern "C" fn dc_lot_get_state(lot: *mut dc_lot_t) -> libc::c_int {
if lot.is_null() {
eprintln!("ignoring careless call to dc_lot_get_state()");
return 0;
}
let lot = &*lot;
lot.get_state() as libc::c_int
}
#[no_mangle]
pub unsafe extern "C" fn dc_lot_get_id(lot: *mut dc_lot_t) -> u32 {
if lot.is_null() {
eprintln!("ignoring careless call to dc_lot_get_id()");
return 0;
}
let lot = &*lot;
lot.get_id()
}
#[no_mangle]
pub unsafe extern "C" fn dc_lot_get_timestamp(lot: *mut dc_lot_t) -> i64 {
if lot.is_null() {
eprintln!("ignoring careless call to dc_lot_get_timestamp()");
return 0;
}
let lot = &*lot;
lot.get_timestamp()
}
#[no_mangle]
pub unsafe extern "C" fn dc_reactions_get_contacts(
reactions: *mut dc_reactions_t,
) -> *mut dc_array::dc_array_t {
if reactions.is_null() {
eprintln!("ignoring careless call to dc_reactions_get_contacts()");
return ptr::null_mut();
}
let reactions = &*reactions;
let array: dc_array_t = reactions.contacts().into();
Box::into_raw(Box::new(array))
}
#[no_mangle]
pub unsafe extern "C" fn dc_reactions_get_by_contact_id(
reactions: *mut dc_reactions_t,
contact_id: u32,
) -> *mut libc::c_char {
if reactions.is_null() {
eprintln!("ignoring careless call to dc_reactions_get_by_contact_id()");
return ptr::null_mut();
}
let reactions = &*reactions;
reactions.get(ContactId::new(contact_id)).as_str().strdup()
}
#[no_mangle]
pub unsafe extern "C" fn dc_reactions_unref(reactions: *mut dc_reactions_t) {
if reactions.is_null() {
eprintln!("ignoring careless call to dc_reactions_unref()");
return;
}
drop(Box::from_raw(reactions));
}
#[no_mangle]
pub unsafe extern "C" fn dc_str_unref(s: *mut libc::c_char) {
libc::free(s as *mut _)
}
pub struct BackupProviderWrapper {
context: *const dc_context_t,
provider: BackupProvider,
}
pub type dc_backup_provider_t = BackupProviderWrapper;
#[no_mangle]
pub unsafe extern "C" fn dc_backup_provider_new(
context: *mut dc_context_t,
) -> *mut dc_backup_provider_t {
if context.is_null() {
eprintln!("ignoring careless call to dc_backup_provider_new()");
return ptr::null_mut();
}
let ctx = &*context;
block_on(BackupProvider::prepare(ctx))
.map(|provider| BackupProviderWrapper {
context: ctx,
provider,
})
.map(|ffi_provider| Box::into_raw(Box::new(ffi_provider)))
.context("BackupProvider failed")
.log_err(ctx)
.set_last_error(ctx)
.unwrap_or(ptr::null_mut())
}
#[no_mangle]
pub unsafe extern "C" fn dc_backup_provider_get_qr(
provider: *const dc_backup_provider_t,
) -> *mut libc::c_char {
if provider.is_null() {
eprintln!("ignoring careless call to dc_backup_provider_qr");
return "".strdup();
}
let ffi_provider = &*provider;
let ctx = &*ffi_provider.context;
deltachat::qr::format_backup(&ffi_provider.provider.qr())
.context("BackupProvider get_qr failed")
.log_err(ctx)
.set_last_error(ctx)
.unwrap_or_default()
.strdup()
}
#[no_mangle]
pub unsafe extern "C" fn dc_backup_provider_get_qr_svg(
provider: *const dc_backup_provider_t,
) -> *mut libc::c_char {
if provider.is_null() {
eprintln!("ignoring careless call to dc_backup_provider_qr_svg()");
return "".strdup();
}
let ffi_provider = &*provider;
let ctx = &*ffi_provider.context;
let provider = &ffi_provider.provider;
block_on(generate_backup_qr(ctx, &provider.qr()))
.context("BackupProvider get_qr_svg failed")
.log_err(ctx)
.set_last_error(ctx)
.unwrap_or_default()
.strdup()
}
#[no_mangle]
pub unsafe extern "C" fn dc_backup_provider_wait(provider: *mut dc_backup_provider_t) {
if provider.is_null() {
eprintln!("ignoring careless call to dc_backup_provider_wait()");
return;
}
let ffi_provider = &mut *provider;
let ctx = &*ffi_provider.context;
let provider = &mut ffi_provider.provider;
block_on(provider)
.context("Failed to await BackupProvider")
.log_err(ctx)
.set_last_error(ctx)
.ok();
}
#[no_mangle]
pub unsafe extern "C" fn dc_backup_provider_unref(provider: *mut dc_backup_provider_t) {
if provider.is_null() {
eprintln!("ignoring careless call to dc_backup_provider_unref()");
return;
}
drop(Box::from_raw(provider));
}
#[no_mangle]
pub unsafe extern "C" fn dc_receive_backup(
context: *mut dc_context_t,
qr: *const libc::c_char,
) -> libc::c_int {
if context.is_null() {
eprintln!("ignoring careless call to dc_receive_backup()");
return 0;
}
let ctx = &*context;
let qr_text = to_string_lossy(qr);
receive_backup(ctx.clone(), qr_text)
}
fn receive_backup(ctx: Context, qr_text: String) -> libc::c_int {
let qr = match block_on(qr::check_qr(&ctx, &qr_text))
.context("Invalid QR code")
.log_err(&ctx)
.set_last_error(&ctx)
{
Ok(qr) => qr,
Err(_) => return 0,
};
match block_on(imex::get_backup(&ctx, qr))
.context("Get backup failed")
.log_err(&ctx)
.set_last_error(&ctx)
{
Ok(_) => 1,
Err(_) => 0,
}
}
trait ResultExt<T, E> {
fn unwrap_or_log_default(self, context: &context::Context, message: &str) -> T;
}
impl<T: Default, E: std::fmt::Display> ResultExt<T, E> for Result<T, E> {
fn unwrap_or_log_default(self, context: &context::Context, message: &str) -> T {
match self {
Ok(t) => t,
Err(err) => {
error!(context, "{message}: {err:#}");
Default::default()
}
}
}
}
trait ResultLastError<T, E>
where
E: std::fmt::Display,
{
fn set_last_error(self, context: &context::Context) -> Result<T, E>;
}
impl<T, E> ResultLastError<T, E> for Result<T, E>
where
E: std::fmt::Display,
{
fn set_last_error(self, context: &context::Context) -> Result<T, E> {
if let Err(ref err) = self {
context.set_last_error(&format!("{err:#}"));
}
self
}
}
trait ResultNullableExt<T> {
fn into_raw(self) -> *mut T;
}
impl<T, E> ResultNullableExt<T> for Result<T, E> {
fn into_raw(self) -> *mut T {
match self {
Ok(t) => Box::into_raw(Box::new(t)),
Err(_) => ptr::null_mut(),
}
}
}
fn convert_and_prune_message_ids(msg_ids: *const u32, msg_cnt: libc::c_int) -> Vec<MsgId> {
let ids = unsafe { std::slice::from_raw_parts(msg_ids, msg_cnt as usize) };
let msg_ids: Vec<MsgId> = ids
.iter()
.filter(|id| **id > DC_MSG_ID_LAST_SPECIAL)
.map(|id| MsgId::new(*id))
.collect();
msg_ids
}
pub type dc_provider_t = provider::Provider;
#[no_mangle]
pub unsafe extern "C" fn dc_provider_new_from_email(
context: *const dc_context_t,
addr: *const libc::c_char,
) -> *const dc_provider_t {
if context.is_null() || addr.is_null() {
eprintln!("ignoring careless call to dc_provider_new_from_email()");
return ptr::null();
}
let addr = to_string_lossy(addr);
let ctx = &*context;
match block_on(provider::get_provider_info_by_addr(
ctx,
addr.as_str(),
true,
))
.log_err(ctx)
.unwrap_or_default()
{
Some(provider) => provider,
None => ptr::null_mut(),
}
}
#[no_mangle]
pub unsafe extern "C" fn dc_provider_new_from_email_with_dns(
context: *const dc_context_t,
addr: *const libc::c_char,
) -> *const dc_provider_t {
if context.is_null() || addr.is_null() {
eprintln!("ignoring careless call to dc_provider_new_from_email_with_dns()");
return ptr::null();
}
let addr = to_string_lossy(addr);
let ctx = &*context;
let socks5_enabled = block_on(async move {
ctx.get_config_bool(config::Config::Socks5Enabled)
.await
.context("Can't get config")
.log_err(ctx)
});
match socks5_enabled {
Ok(socks5_enabled) => {
match block_on(provider::get_provider_info_by_addr(
ctx,
addr.as_str(),
socks5_enabled,
))
.log_err(ctx)
.unwrap_or_default()
{
Some(provider) => provider,
None => ptr::null_mut(),
}
}
Err(_) => ptr::null_mut(),
}
}
#[no_mangle]
pub unsafe extern "C" fn dc_provider_get_overview_page(
provider: *const dc_provider_t,
) -> *mut libc::c_char {
if provider.is_null() {
eprintln!("ignoring careless call to dc_provider_get_overview_page()");
return "".strdup();
}
let provider = &*provider;
provider.overview_page.strdup()
}
#[no_mangle]
pub unsafe extern "C" fn dc_provider_get_before_login_hint(
provider: *const dc_provider_t,
) -> *mut libc::c_char {
if provider.is_null() {
eprintln!("ignoring careless call to dc_provider_get_before_login_hint()");
return "".strdup();
}
let provider = &*provider;
provider.before_login_hint.strdup()
}
#[no_mangle]
pub unsafe extern "C" fn dc_provider_get_status(provider: *const dc_provider_t) -> libc::c_int {
if provider.is_null() {
eprintln!("ignoring careless call to dc_provider_get_status()");
return 0;
}
let provider = &*provider;
provider.status as libc::c_int
}
#[no_mangle]
#[allow(clippy::needless_return)]
pub unsafe extern "C" fn dc_provider_unref(provider: *mut dc_provider_t) {
if provider.is_null() {
eprintln!("ignoring careless call to dc_provider_unref()");
return;
}
}
pub struct AccountsWrapper {
inner: Arc<RwLock<Accounts>>,
}
impl Deref for AccountsWrapper {
type Target = Arc<RwLock<Accounts>>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl AccountsWrapper {
fn new(accounts: Accounts) -> Self {
let inner = Arc::new(RwLock::new(accounts));
Self { inner }
}
}
pub type dc_accounts_t = AccountsWrapper;
#[no_mangle]
pub unsafe extern "C" fn dc_accounts_new(
dir: *const libc::c_char,
writable: libc::c_int,
) -> *mut dc_accounts_t {
setup_panic!();
if dir.is_null() {
eprintln!("ignoring careless call to dc_accounts_new()");
return ptr::null_mut();
}
let accs = block_on(Accounts::new(as_path(dir).into(), writable != 0));
match accs {
Ok(accs) => Box::into_raw(Box::new(AccountsWrapper::new(accs))),
Err(err) => {
eprintln!("failed to create accounts: {err:#}");
ptr::null_mut()
}
}
}
#[no_mangle]
pub unsafe extern "C" fn dc_accounts_unref(accounts: *mut dc_accounts_t) {
if accounts.is_null() {
eprintln!("ignoring careless call to dc_accounts_unref()");
return;
}
let _ = Box::from_raw(accounts);
}
#[no_mangle]
pub unsafe extern "C" fn dc_accounts_get_account(
accounts: *mut dc_accounts_t,
id: u32,
) -> *mut dc_context_t {
if accounts.is_null() {
eprintln!("ignoring careless call to dc_accounts_get_account()");
return ptr::null_mut();
}
let accounts = &*accounts;
block_on(accounts.read())
.get_account(id)
.map(|ctx| Box::into_raw(Box::new(ctx)))
.unwrap_or_else(std::ptr::null_mut)
}
#[no_mangle]
pub unsafe extern "C" fn dc_accounts_get_selected_account(
accounts: *mut dc_accounts_t,
) -> *mut dc_context_t {
if accounts.is_null() {
eprintln!("ignoring careless call to dc_accounts_get_selected_account()");
return ptr::null_mut();
}
let accounts = &*accounts;
block_on(accounts.read())
.get_selected_account()
.map(|ctx| Box::into_raw(Box::new(ctx)))
.unwrap_or_else(std::ptr::null_mut)
}
#[no_mangle]
pub unsafe extern "C" fn dc_accounts_select_account(
accounts: *mut dc_accounts_t,
id: u32,
) -> libc::c_int {
if accounts.is_null() {
eprintln!("ignoring careless call to dc_accounts_select_account()");
return 0;
}
let accounts = &*accounts;
block_on(async move {
let mut accounts = accounts.write().await;
match accounts.select_account(id).await {
Ok(()) => 1,
Err(err) => {
accounts.emit_event(EventType::Error(format!(
"Failed to select account: {err:#}"
)));
0
}
}
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_accounts_add_account(accounts: *mut dc_accounts_t) -> u32 {
if accounts.is_null() {
eprintln!("ignoring careless call to dc_accounts_add_account()");
return 0;
}
let accounts = &mut *accounts;
block_on(async move {
let mut accounts = accounts.write().await;
match accounts.add_account().await {
Ok(id) => id,
Err(err) => {
accounts.emit_event(EventType::Error(format!("Failed to add account: {err:#}")));
0
}
}
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_accounts_add_closed_account(accounts: *mut dc_accounts_t) -> u32 {
if accounts.is_null() {
eprintln!("ignoring careless call to dc_accounts_add_closed_account()");
return 0;
}
let accounts = &mut *accounts;
block_on(async move {
let mut accounts = accounts.write().await;
match accounts.add_closed_account().await {
Ok(id) => id,
Err(err) => {
accounts.emit_event(EventType::Error(format!("Failed to add account: {err:#}")));
0
}
}
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_accounts_remove_account(
accounts: *mut dc_accounts_t,
id: u32,
) -> libc::c_int {
if accounts.is_null() {
eprintln!("ignoring careless call to dc_accounts_remove_account()");
return 0;
}
let accounts = &mut *accounts;
block_on(async move {
let mut accounts = accounts.write().await;
match accounts.remove_account(id).await {
Ok(()) => 1,
Err(err) => {
accounts.emit_event(EventType::Error(format!(
"Failed to remove account: {err:#}"
)));
0
}
}
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_accounts_migrate_account(
accounts: *mut dc_accounts_t,
dbfile: *const libc::c_char,
) -> u32 {
if accounts.is_null() || dbfile.is_null() {
eprintln!("ignoring careless call to dc_accounts_migrate_account()");
return 0;
}
let accounts = &mut *accounts;
let dbfile = to_string_lossy(dbfile);
block_on(async move {
let mut accounts = accounts.write().await;
match accounts
.migrate_account(std::path::PathBuf::from(dbfile))
.await
{
Ok(id) => id,
Err(err) => {
accounts.emit_event(EventType::Error(format!(
"Failed to migrate account: {err:#}"
)));
0
}
}
})
}
#[no_mangle]
pub unsafe extern "C" fn dc_accounts_get_all(accounts: *mut dc_accounts_t) -> *mut dc_array_t {
if accounts.is_null() {
eprintln!("ignoring careless call to dc_accounts_get_all()");
return ptr::null_mut();
}
let accounts = &*accounts;
let list = block_on(accounts.read()).get_all();
let array: dc_array_t = list.into();
Box::into_raw(Box::new(array))
}
#[no_mangle]
pub unsafe extern "C" fn dc_accounts_all_work_done(accounts: *mut dc_accounts_t) -> libc::c_int {
if accounts.is_null() {
eprintln!("ignoring careless call to dc_accounts_all_work_done()");
return 0;
}
let accounts = &*accounts;
block_on(async move { accounts.read().await.all_work_done().await as libc::c_int })
}
#[no_mangle]
pub unsafe extern "C" fn dc_accounts_start_io(accounts: *mut dc_accounts_t) {
if accounts.is_null() {
eprintln!("ignoring careless call to dc_accounts_start_io()");
return;
}
let accounts = &mut *accounts;
block_on(async move { accounts.write().await.start_io().await });
}
#[no_mangle]
pub unsafe extern "C" fn dc_accounts_stop_io(accounts: *mut dc_accounts_t) {
if accounts.is_null() {
eprintln!("ignoring careless call to dc_accounts_stop_io()");
return;
}
let accounts = &*accounts;
block_on(async move { accounts.read().await.stop_io().await });
}
#[no_mangle]
pub unsafe extern "C" fn dc_accounts_maybe_network(accounts: *mut dc_accounts_t) {
if accounts.is_null() {
eprintln!("ignoring careless call to dc_accounts_maybe_network()");
return;
}
let accounts = &*accounts;
block_on(async move { accounts.read().await.maybe_network().await });
}
#[no_mangle]
pub unsafe extern "C" fn dc_accounts_maybe_network_lost(accounts: *mut dc_accounts_t) {
if accounts.is_null() {
eprintln!("ignoring careless call to dc_accounts_maybe_network_lost()");
return;
}
let accounts = &*accounts;
block_on(async move { accounts.write().await.maybe_network_lost().await });
}
#[no_mangle]
pub unsafe extern "C" fn dc_accounts_background_fetch(
accounts: *mut dc_accounts_t,
timeout_in_seconds: u64,
) -> libc::c_int {
if accounts.is_null() || timeout_in_seconds <= 2 {
eprintln!("ignoring careless call to dc_accounts_background_fetch()");
return 0;
}
let accounts = &*accounts;
block_on(async move {
let accounts = accounts.read().await;
accounts
.background_fetch(Duration::from_secs(timeout_in_seconds))
.await;
});
1
}
#[no_mangle]
pub unsafe extern "C" fn dc_accounts_get_event_emitter(
accounts: *mut dc_accounts_t,
) -> *mut dc_event_emitter_t {
if accounts.is_null() {
eprintln!("ignoring careless call to dc_accounts_get_event_emitter()");
return ptr::null_mut();
}
let accounts = &*accounts;
let emitter = block_on(accounts.read()).get_event_emitter();
Box::into_raw(Box::new(emitter))
}
#[cfg(feature = "jsonrpc")]
mod jsonrpc {
use deltachat_jsonrpc::api::CommandApi;
use deltachat_jsonrpc::yerpc::{OutReceiver, RpcClient, RpcSession};
use super::*;
pub struct dc_jsonrpc_instance_t {
receiver: OutReceiver,
handle: RpcSession<CommandApi>,
}
#[no_mangle]
pub unsafe extern "C" fn dc_jsonrpc_init(
account_manager: *mut dc_accounts_t,
) -> *mut dc_jsonrpc_instance_t {
if account_manager.is_null() {
eprintln!("ignoring careless call to dc_jsonrpc_init()");
return ptr::null_mut();
}
let account_manager = &*account_manager;
let cmd_api = deltachat_jsonrpc::api::CommandApi::from_arc(account_manager.inner.clone());
let (request_handle, receiver) = RpcClient::new();
let handle = RpcSession::new(request_handle, cmd_api);
let instance = dc_jsonrpc_instance_t { receiver, handle };
Box::into_raw(Box::new(instance))
}
#[no_mangle]
pub unsafe extern "C" fn dc_jsonrpc_unref(jsonrpc_instance: *mut dc_jsonrpc_instance_t) {
if jsonrpc_instance.is_null() {
eprintln!("ignoring careless call to dc_jsonrpc_unref()");
return;
}
drop(Box::from_raw(jsonrpc_instance));
}
fn spawn_handle_jsonrpc_request(handle: RpcSession<CommandApi>, request: String) {
spawn(async move {
handle.handle_incoming(&request).await;
});
}
#[no_mangle]
pub unsafe extern "C" fn dc_jsonrpc_request(
jsonrpc_instance: *mut dc_jsonrpc_instance_t,
request: *const libc::c_char,
) {
if jsonrpc_instance.is_null() || request.is_null() {
eprintln!("ignoring careless call to dc_jsonrpc_request()");
return;
}
let handle = &(*jsonrpc_instance).handle;
let request = to_string_lossy(request);
spawn_handle_jsonrpc_request(handle.clone(), request);
}
#[no_mangle]
pub unsafe extern "C" fn dc_jsonrpc_next_response(
jsonrpc_instance: *mut dc_jsonrpc_instance_t,
) -> *mut libc::c_char {
if jsonrpc_instance.is_null() {
eprintln!("ignoring careless call to dc_jsonrpc_next_response()");
return ptr::null_mut();
}
let api = &*jsonrpc_instance;
block_on(api.receiver.recv())
.map(|result| serde_json::to_string(&result).unwrap_or_default().strdup())
.unwrap_or(ptr::null_mut())
}
#[no_mangle]
pub unsafe extern "C" fn dc_jsonrpc_blocking_call(
jsonrpc_instance: *mut dc_jsonrpc_instance_t,
input: *const libc::c_char,
) -> *mut libc::c_char {
if jsonrpc_instance.is_null() {
eprintln!("ignoring careless call to dc_jsonrpc_blocking_call()");
return ptr::null_mut();
}
let api = &*jsonrpc_instance;
let input = to_string_lossy(input);
let res = block_on(api.handle.process_incoming(&input));
match res {
Some(message) => {
if let Ok(message) = serde_json::to_string(&message) {
message.strdup()
} else {
ptr::null_mut()
}
}
None => ptr::null_mut(),
}
}
}