1#![recursion_limit = "256"]
2#![warn(unused, clippy::all)]
3#![allow(
4 non_camel_case_types,
5 non_snake_case,
6 non_upper_case_globals,
7 clippy::missing_safety_doc,
8 clippy::expect_fun_call
9)]
10
11#[macro_use]
12extern crate human_panic;
13
14use std::collections::BTreeMap;
15use std::convert::TryFrom;
16use std::fmt::Write;
17use std::future::Future;
18use std::ops::Deref;
19use std::ptr;
20use std::str::FromStr;
21use std::sync::{Arc, LazyLock};
22use std::time::{Duration, SystemTime};
23
24use anyhow::Context as _;
25use deltachat::chat::{ChatId, ChatVisibility, MessageListOptions, MuteDuration, ProtectionStatus};
26use deltachat::constants::DC_MSG_ID_LAST_SPECIAL;
27use deltachat::contact::{Contact, ContactId, Origin};
28use deltachat::context::{Context, ContextBuilder};
29use deltachat::ephemeral::Timer as EphemeralTimer;
30use deltachat::imex::BackupProvider;
31use deltachat::key::preconfigure_keypair;
32use deltachat::message::MsgId;
33use deltachat::qr_code_generator::{create_qr_svg, generate_backup_qr, get_securejoin_qr_svg};
34use deltachat::stock_str::StockMessage;
35use deltachat::webxdc::StatusUpdateSerial;
36use deltachat::*;
37use deltachat::{accounts::Accounts, log::LogExt};
38use deltachat_jsonrpc::api::CommandApi;
39use deltachat_jsonrpc::yerpc::{OutReceiver, RpcClient, RpcSession};
40use message::Viewtype;
41use num_traits::{FromPrimitive, ToPrimitive};
42use rand::Rng;
43use tokio::runtime::Runtime;
44use tokio::sync::RwLock;
45use tokio::task::JoinHandle;
46
47mod dc_array;
48mod lot;
49
50mod string;
51use deltachat::chatlist::Chatlist;
52
53use self::string::*;
54
55const DC_GCM_ADDDAYMARKER: u32 = 0x01;
64const DC_GCM_INFO_ONLY: u32 = 0x02;
65
66pub type dc_context_t = Context;
70
71static RT: LazyLock<Runtime> =
72 LazyLock::new(|| Runtime::new().expect("unable to create tokio runtime"));
73
74fn block_on<T>(fut: T) -> T::Output
75where
76 T: Future,
77{
78 RT.block_on(fut)
79}
80
81fn spawn<T>(fut: T) -> JoinHandle<T::Output>
82where
83 T: Future + Send + 'static,
84 T::Output: Send + 'static,
85{
86 RT.spawn(fut)
87}
88
89#[no_mangle]
90pub unsafe extern "C" fn dc_context_new(
91 _os_name: *const libc::c_char,
92 dbfile: *const libc::c_char,
93 blobdir: *const libc::c_char,
94) -> *mut dc_context_t {
95 setup_panic!();
96
97 if dbfile.is_null() {
98 eprintln!("ignoring careless call to dc_context_new()");
99 return ptr::null_mut();
100 }
101
102 let ctx = if blobdir.is_null() || *blobdir == 0 {
103 let id = rand::thread_rng().gen();
105 block_on(
106 ContextBuilder::new(as_path(dbfile).to_path_buf())
107 .with_id(id)
108 .open(),
109 )
110 } else {
111 eprintln!("blobdir can not be defined explicitly anymore");
112 return ptr::null_mut();
113 };
114 match ctx {
115 Ok(ctx) => Box::into_raw(Box::new(ctx)),
116 Err(err) => {
117 eprintln!("failed to create context: {err:#}");
118 ptr::null_mut()
119 }
120 }
121}
122
123#[no_mangle]
124pub unsafe extern "C" fn dc_context_new_closed(dbfile: *const libc::c_char) -> *mut dc_context_t {
125 setup_panic!();
126
127 if dbfile.is_null() {
128 eprintln!("ignoring careless call to dc_context_new_closed()");
129 return ptr::null_mut();
130 }
131
132 let id = rand::thread_rng().gen();
133 match block_on(
134 ContextBuilder::new(as_path(dbfile).to_path_buf())
135 .with_id(id)
136 .build(),
137 ) {
138 Ok(context) => Box::into_raw(Box::new(context)),
139 Err(err) => {
140 eprintln!("failed to create context: {err:#}");
141 ptr::null_mut()
142 }
143 }
144}
145
146#[no_mangle]
147pub unsafe extern "C" fn dc_context_open(
148 context: *mut dc_context_t,
149 passphrase: *const libc::c_char,
150) -> libc::c_int {
151 if context.is_null() {
152 eprintln!("ignoring careless call to dc_context_open()");
153 return 0;
154 }
155
156 let ctx = &*context;
157 let passphrase = to_string_lossy(passphrase);
158 block_on(ctx.open(passphrase))
159 .context("dc_context_open() failed")
160 .log_err(ctx)
161 .map(|b| b as libc::c_int)
162 .unwrap_or(0)
163}
164
165#[no_mangle]
166pub unsafe extern "C" fn dc_context_change_passphrase(
167 context: *mut dc_context_t,
168 passphrase: *const libc::c_char,
169) -> libc::c_int {
170 if context.is_null() {
171 eprintln!("ignoring careless call to dc_context_change_passphrase()");
172 return 0;
173 }
174
175 let ctx = &*context;
176 let passphrase = to_string_lossy(passphrase);
177 block_on(ctx.change_passphrase(passphrase))
178 .context("dc_context_change_passphrase() failed")
179 .log_err(ctx)
180 .is_ok() as libc::c_int
181}
182
183#[no_mangle]
184pub unsafe extern "C" fn dc_context_is_open(context: *mut dc_context_t) -> libc::c_int {
185 if context.is_null() {
186 eprintln!("ignoring careless call to dc_context_is_open()");
187 return 0;
188 }
189
190 let ctx = &*context;
191 block_on(ctx.is_open()) as libc::c_int
192}
193
194#[no_mangle]
198pub unsafe extern "C" fn dc_context_unref(context: *mut dc_context_t) {
199 if context.is_null() {
200 eprintln!("ignoring careless call to dc_context_unref()");
201 return;
202 }
203 drop(Box::from_raw(context));
204}
205
206#[no_mangle]
207pub unsafe extern "C" fn dc_get_blobdir(context: *mut dc_context_t) -> *mut libc::c_char {
208 if context.is_null() {
209 eprintln!("ignoring careless call to dc_get_blobdir()");
210 return "".strdup();
211 }
212 let ctx = &*context;
213 ctx.get_blobdir().to_string_lossy().strdup()
214}
215
216#[no_mangle]
217pub unsafe extern "C" fn dc_set_config(
218 context: *mut dc_context_t,
219 key: *const libc::c_char,
220 value: *const libc::c_char,
221) -> libc::c_int {
222 if context.is_null() || key.is_null() {
223 eprintln!("ignoring careless call to dc_set_config()");
224 return 0;
225 }
226 let ctx = &*context;
227 let key = to_string_lossy(key);
228 let value = to_opt_string_lossy(value);
229
230 block_on(async move {
231 if key.starts_with("ui.") {
232 ctx.set_ui_config(&key, value.as_deref())
233 .await
234 .with_context(|| format!("dc_set_config failed: Can't set {key} to {value:?}"))
235 .log_err(ctx)
236 .is_ok() as libc::c_int
237 } else {
238 match config::Config::from_str(&key) {
239 Ok(key) => ctx
240 .set_config(key, value.as_deref())
241 .await
242 .with_context(|| {
243 format!("dc_set_config() failed: Can't set {key} to {value:?}")
244 })
245 .log_err(ctx)
246 .is_ok() as libc::c_int,
247 Err(_) => {
248 warn!(ctx, "dc_set_config(): invalid key");
249 0
250 }
251 }
252 }
253 })
254}
255
256#[no_mangle]
257pub unsafe extern "C" fn dc_get_config(
258 context: *mut dc_context_t,
259 key: *const libc::c_char,
260) -> *mut libc::c_char {
261 if context.is_null() || key.is_null() {
262 eprintln!("ignoring careless call to dc_get_config()");
263 return "".strdup();
264 }
265 let ctx = &*context;
266
267 let key = to_string_lossy(key);
268
269 block_on(async move {
270 if key.starts_with("ui.") {
271 ctx.get_ui_config(&key)
272 .await
273 .context("Can't get ui-config")
274 .log_err(ctx)
275 .unwrap_or_default()
276 .unwrap_or_default()
277 .strdup()
278 } else {
279 match config::Config::from_str(&key) {
280 Ok(key) => ctx
281 .get_config(key)
282 .await
283 .context("Can't get config")
284 .log_err(ctx)
285 .unwrap_or_default()
286 .unwrap_or_default()
287 .strdup(),
288 Err(_) => {
289 warn!(ctx, "dc_get_config(): invalid key '{}'", &key);
290 "".strdup()
291 }
292 }
293 }
294 })
295}
296
297#[no_mangle]
298pub unsafe extern "C" fn dc_set_stock_translation(
299 context: *mut dc_context_t,
300 stock_id: u32,
301 stock_msg: *mut libc::c_char,
302) -> libc::c_int {
303 if context.is_null() || stock_msg.is_null() {
304 eprintln!("ignoring careless call to dc_set_stock_string");
305 return 0;
306 }
307 let msg = to_string_lossy(stock_msg);
308 let ctx = &*context;
309
310 block_on(async move {
311 match StockMessage::from_u32(stock_id) {
312 Some(id) => match ctx.set_stock_translation(id, msg).await {
313 Ok(()) => 1,
314 Err(err) => {
315 warn!(ctx, "set_stock_translation failed: {err:#}");
316 0
317 }
318 },
319 None => {
320 warn!(ctx, "invalid stock message id {stock_id}");
321 0
322 }
323 }
324 })
325}
326
327#[no_mangle]
328pub unsafe extern "C" fn dc_set_config_from_qr(
329 context: *mut dc_context_t,
330 qr: *mut libc::c_char,
331) -> libc::c_int {
332 if context.is_null() || qr.is_null() {
333 eprintln!("ignoring careless call to dc_set_config_from_qr");
334 return 0;
335 }
336 let qr = to_string_lossy(qr);
337 let ctx = &*context;
338
339 block_on(async move {
340 match qr::set_config_from_qr(ctx, &qr).await {
341 Ok(()) => 1,
342 Err(err) => {
343 error!(ctx, "Failed to create account from QR code: {err:#}");
344 0
345 }
346 }
347 })
348}
349
350#[no_mangle]
351pub unsafe extern "C" fn dc_get_info(context: *const dc_context_t) -> *mut libc::c_char {
352 if context.is_null() {
353 eprintln!("ignoring careless call to dc_get_info()");
354 return "".strdup();
355 }
356 let ctx = &*context;
357 block_on(async move {
358 match ctx.get_info().await {
359 Ok(info) => render_info(info).unwrap_or_default().strdup(),
360 Err(err) => {
361 warn!(ctx, "failed to get info: {err:#}");
362 "".strdup()
363 }
364 }
365 })
366}
367
368fn render_info(
369 info: BTreeMap<&'static str, String>,
370) -> std::result::Result<String, std::fmt::Error> {
371 let mut res = String::new();
372 for (key, value) in &info {
373 writeln!(&mut res, "{key}={value}")?;
374 }
375
376 Ok(res)
377}
378
379#[no_mangle]
380pub unsafe extern "C" fn dc_get_connectivity(context: *const dc_context_t) -> libc::c_int {
381 if context.is_null() {
382 eprintln!("ignoring careless call to dc_get_connectivity()");
383 return 0;
384 }
385 let ctx = &*context;
386 block_on(ctx.get_connectivity()) as u32 as libc::c_int
387}
388
389#[no_mangle]
390pub unsafe extern "C" fn dc_get_connectivity_html(
391 context: *const dc_context_t,
392) -> *mut libc::c_char {
393 if context.is_null() {
394 eprintln!("ignoring careless call to dc_get_connectivity_html()");
395 return "".strdup();
396 }
397 let ctx = &*context;
398 block_on(async move {
399 match ctx.get_connectivity_html().await {
400 Ok(html) => html.strdup(),
401 Err(err) => {
402 error!(ctx, "Failed to get connectivity html: {err:#}");
403 "".strdup()
404 }
405 }
406 })
407}
408
409#[no_mangle]
410pub unsafe extern "C" fn dc_get_push_state(context: *const dc_context_t) -> libc::c_int {
411 if context.is_null() {
412 eprintln!("ignoring careless call to dc_get_push_state()");
413 return 0;
414 }
415 let ctx = &*context;
416 block_on(ctx.push_state()) as libc::c_int
417}
418
419#[no_mangle]
420pub unsafe extern "C" fn dc_get_oauth2_url(
421 context: *mut dc_context_t,
422 addr: *const libc::c_char,
423 redirect: *const libc::c_char,
424) -> *mut libc::c_char {
425 if context.is_null() {
426 eprintln!("ignoring careless call to dc_get_oauth2_url()");
427 return ptr::null_mut(); }
429 let ctx = &*context;
430 let addr = to_string_lossy(addr);
431 let redirect = to_string_lossy(redirect);
432
433 block_on(async move {
434 match oauth2::get_oauth2_url(ctx, &addr, &redirect)
435 .await
436 .context("dc_get_oauth2_url failed")
437 .log_err(ctx)
438 {
439 Ok(Some(res)) => res.strdup(),
440 Ok(None) | Err(_) => ptr::null_mut(),
441 }
442 })
443}
444
445fn spawn_configure(ctx: Context) {
446 spawn(async move {
447 ctx.configure()
448 .await
449 .context("Configure failed")
450 .log_err(&ctx)
451 });
452}
453
454#[no_mangle]
455pub unsafe extern "C" fn dc_configure(context: *mut dc_context_t) {
456 if context.is_null() {
457 eprintln!("ignoring careless call to dc_configure()");
458 return;
459 }
460
461 let ctx = &*context;
462 spawn_configure(ctx.clone());
463}
464
465#[no_mangle]
466pub unsafe extern "C" fn dc_is_configured(context: *mut dc_context_t) -> libc::c_int {
467 if context.is_null() {
468 eprintln!("ignoring careless call to dc_is_configured()");
469 return 0;
470 }
471 let ctx = &*context;
472
473 block_on(async move {
474 ctx.is_configured()
475 .await
476 .context("failed to get configured state")
477 .log_err(ctx)
478 .unwrap_or_default() as libc::c_int
479 })
480}
481
482#[no_mangle]
483pub unsafe extern "C" fn dc_start_io(context: *mut dc_context_t) {
484 if context.is_null() {
485 return;
486 }
487 let ctx = &mut *context;
488
489 block_on(ctx.start_io())
490}
491
492#[no_mangle]
493pub unsafe extern "C" fn dc_get_id(context: *mut dc_context_t) -> libc::c_int {
494 if context.is_null() {
495 return 0;
496 }
497 let ctx = &*context;
498
499 ctx.get_id() as libc::c_int
500}
501
502pub type dc_event_t = Event;
503
504#[no_mangle]
505pub unsafe extern "C" fn dc_event_unref(a: *mut dc_event_t) {
506 if a.is_null() {
507 eprintln!("ignoring careless call to dc_event_unref()");
508 return;
509 }
510
511 drop(Box::from_raw(a));
512}
513
514#[no_mangle]
515pub unsafe extern "C" fn dc_event_get_id(event: *mut dc_event_t) -> libc::c_int {
516 if event.is_null() {
517 eprintln!("ignoring careless call to dc_event_get_id()");
518 return 0;
519 }
520
521 let event = &*event;
522 match event.typ {
523 EventType::Info(_) => 100,
524 EventType::SmtpConnected(_) => 101,
525 EventType::ImapConnected(_) => 102,
526 EventType::SmtpMessageSent(_) => 103,
527 EventType::ImapMessageDeleted(_) => 104,
528 EventType::ImapMessageMoved(_) => 105,
529 EventType::ImapInboxIdle => 106,
530 EventType::NewBlobFile(_) => 150,
531 EventType::DeletedBlobFile(_) => 151,
532 EventType::Warning(_) => 300,
533 EventType::Error(_) => 400,
534 EventType::ErrorSelfNotInGroup(_) => 410,
535 EventType::MsgsChanged { .. } => 2000,
536 EventType::ReactionsChanged { .. } => 2001,
537 EventType::IncomingReaction { .. } => 2002,
538 EventType::IncomingWebxdcNotify { .. } => 2003,
539 EventType::IncomingMsg { .. } => 2005,
540 EventType::IncomingMsgBunch => 2006,
541 EventType::MsgsNoticed { .. } => 2008,
542 EventType::MsgDelivered { .. } => 2010,
543 EventType::MsgFailed { .. } => 2012,
544 EventType::MsgRead { .. } => 2015,
545 EventType::MsgDeleted { .. } => 2016,
546 EventType::ChatModified(_) => 2020,
547 EventType::ChatEphemeralTimerModified { .. } => 2021,
548 EventType::ChatDeleted { .. } => 2023,
549 EventType::ContactsChanged(_) => 2030,
550 EventType::LocationChanged(_) => 2035,
551 EventType::ConfigureProgress { .. } => 2041,
552 EventType::ImexProgress(_) => 2051,
553 EventType::ImexFileWritten(_) => 2052,
554 EventType::SecurejoinInviterProgress { .. } => 2060,
555 EventType::SecurejoinJoinerProgress { .. } => 2061,
556 EventType::ConnectivityChanged => 2100,
557 EventType::SelfavatarChanged => 2110,
558 EventType::ConfigSynced { .. } => 2111,
559 EventType::WebxdcStatusUpdate { .. } => 2120,
560 EventType::WebxdcInstanceDeleted { .. } => 2121,
561 EventType::WebxdcRealtimeData { .. } => 2150,
562 EventType::WebxdcRealtimeAdvertisementReceived { .. } => 2151,
563 EventType::AccountsBackgroundFetchDone => 2200,
564 EventType::ChatlistChanged => 2300,
565 EventType::ChatlistItemChanged { .. } => 2301,
566 EventType::AccountsChanged => 2302,
567 EventType::AccountsItemChanged => 2303,
568 EventType::EventChannelOverflow { .. } => 2400,
569 #[allow(unreachable_patterns)]
570 #[cfg(test)]
571 _ => unreachable!("This is just to silence a rust_analyzer false-positive"),
572 }
573}
574
575#[no_mangle]
576pub unsafe extern "C" fn dc_event_get_data1_int(event: *mut dc_event_t) -> libc::c_int {
577 if event.is_null() {
578 eprintln!("ignoring careless call to dc_event_get_data1_int()");
579 return 0;
580 }
581
582 let event = &(*event).typ;
583 match event {
584 EventType::Info(_)
585 | EventType::SmtpConnected(_)
586 | EventType::ImapConnected(_)
587 | EventType::SmtpMessageSent(_)
588 | EventType::ImapMessageDeleted(_)
589 | EventType::ImapMessageMoved(_)
590 | EventType::ImapInboxIdle
591 | EventType::NewBlobFile(_)
592 | EventType::DeletedBlobFile(_)
593 | EventType::Warning(_)
594 | EventType::Error(_)
595 | EventType::ConnectivityChanged
596 | EventType::SelfavatarChanged
597 | EventType::ConfigSynced { .. }
598 | EventType::IncomingMsgBunch
599 | EventType::ErrorSelfNotInGroup(_)
600 | EventType::AccountsBackgroundFetchDone
601 | EventType::ChatlistChanged
602 | EventType::AccountsChanged
603 | EventType::AccountsItemChanged => 0,
604 EventType::IncomingReaction { contact_id, .. }
605 | EventType::IncomingWebxdcNotify { contact_id, .. } => contact_id.to_u32() as libc::c_int,
606 EventType::MsgsChanged { chat_id, .. }
607 | EventType::ReactionsChanged { chat_id, .. }
608 | EventType::IncomingMsg { chat_id, .. }
609 | EventType::MsgsNoticed(chat_id)
610 | EventType::MsgDelivered { chat_id, .. }
611 | EventType::MsgFailed { chat_id, .. }
612 | EventType::MsgRead { chat_id, .. }
613 | EventType::MsgDeleted { chat_id, .. }
614 | EventType::ChatModified(chat_id)
615 | EventType::ChatEphemeralTimerModified { chat_id, .. }
616 | EventType::ChatDeleted { chat_id } => chat_id.to_u32() as libc::c_int,
617 EventType::ContactsChanged(id) | EventType::LocationChanged(id) => {
618 let id = id.unwrap_or_default();
619 id.to_u32() as libc::c_int
620 }
621 EventType::ConfigureProgress { progress, .. } | EventType::ImexProgress(progress) => {
622 *progress as libc::c_int
623 }
624 EventType::ImexFileWritten(_) => 0,
625 EventType::SecurejoinInviterProgress { contact_id, .. }
626 | EventType::SecurejoinJoinerProgress { contact_id, .. } => {
627 contact_id.to_u32() as libc::c_int
628 }
629 EventType::WebxdcRealtimeData { msg_id, .. }
630 | EventType::WebxdcStatusUpdate { msg_id, .. }
631 | EventType::WebxdcRealtimeAdvertisementReceived { msg_id }
632 | EventType::WebxdcInstanceDeleted { msg_id, .. } => msg_id.to_u32() as libc::c_int,
633 EventType::ChatlistItemChanged { chat_id } => {
634 chat_id.unwrap_or_default().to_u32() as libc::c_int
635 }
636 EventType::EventChannelOverflow { n } => *n as libc::c_int,
637 #[allow(unreachable_patterns)]
638 #[cfg(test)]
639 _ => unreachable!("This is just to silence a rust_analyzer false-positive"),
640 }
641}
642
643#[no_mangle]
644pub unsafe extern "C" fn dc_event_get_data2_int(event: *mut dc_event_t) -> libc::c_int {
645 if event.is_null() {
646 eprintln!("ignoring careless call to dc_event_get_data2_int()");
647 return 0;
648 }
649
650 let event = &(*event).typ;
651
652 match event {
653 EventType::Info(_)
654 | EventType::SmtpConnected(_)
655 | EventType::ImapConnected(_)
656 | EventType::SmtpMessageSent(_)
657 | EventType::ImapMessageDeleted(_)
658 | EventType::ImapMessageMoved(_)
659 | EventType::ImapInboxIdle
660 | EventType::NewBlobFile(_)
661 | EventType::DeletedBlobFile(_)
662 | EventType::Warning(_)
663 | EventType::Error(_)
664 | EventType::ErrorSelfNotInGroup(_)
665 | EventType::ContactsChanged(_)
666 | EventType::LocationChanged(_)
667 | EventType::ConfigureProgress { .. }
668 | EventType::ImexProgress(_)
669 | EventType::ImexFileWritten(_)
670 | EventType::MsgsNoticed(_)
671 | EventType::ConnectivityChanged
672 | EventType::WebxdcInstanceDeleted { .. }
673 | EventType::IncomingMsgBunch
674 | EventType::SelfavatarChanged
675 | EventType::AccountsBackgroundFetchDone
676 | EventType::ChatlistChanged
677 | EventType::ChatlistItemChanged { .. }
678 | EventType::AccountsChanged
679 | EventType::AccountsItemChanged
680 | EventType::ConfigSynced { .. }
681 | EventType::ChatModified(_)
682 | EventType::ChatDeleted { .. }
683 | EventType::WebxdcRealtimeAdvertisementReceived { .. }
684 | EventType::EventChannelOverflow { .. } => 0,
685 EventType::MsgsChanged { msg_id, .. }
686 | EventType::ReactionsChanged { msg_id, .. }
687 | EventType::IncomingReaction { msg_id, .. }
688 | EventType::IncomingWebxdcNotify { msg_id, .. }
689 | EventType::IncomingMsg { msg_id, .. }
690 | EventType::MsgDelivered { msg_id, .. }
691 | EventType::MsgFailed { msg_id, .. }
692 | EventType::MsgRead { msg_id, .. }
693 | EventType::MsgDeleted { msg_id, .. } => msg_id.to_u32() as libc::c_int,
694 EventType::SecurejoinInviterProgress { progress, .. }
695 | EventType::SecurejoinJoinerProgress { progress, .. } => *progress as libc::c_int,
696 EventType::ChatEphemeralTimerModified { timer, .. } => timer.to_u32() as libc::c_int,
697 EventType::WebxdcStatusUpdate {
698 status_update_serial,
699 ..
700 } => status_update_serial.to_u32() as libc::c_int,
701 EventType::WebxdcRealtimeData { data, .. } => data.len() as libc::c_int,
702 #[allow(unreachable_patterns)]
703 #[cfg(test)]
704 _ => unreachable!("This is just to silence a rust_analyzer false-positive"),
705 }
706}
707
708#[no_mangle]
709pub unsafe extern "C" fn dc_event_get_data1_str(event: *mut dc_event_t) -> *mut libc::c_char {
710 if event.is_null() {
711 eprintln!("ignoring careless call to dc_event_get_data1_str()");
712 return ptr::null_mut();
713 }
714
715 let event = &(*event).typ;
716
717 match event {
718 EventType::IncomingWebxdcNotify { href, .. } => {
719 if let Some(href) = href {
720 href.to_c_string().unwrap_or_default().into_raw()
721 } else {
722 ptr::null_mut()
723 }
724 }
725 _ => ptr::null_mut(),
726 }
727}
728
729#[no_mangle]
730pub unsafe extern "C" fn dc_event_get_data2_str(event: *mut dc_event_t) -> *mut libc::c_char {
731 if event.is_null() {
732 eprintln!("ignoring careless call to dc_event_get_data2_str()");
733 return ptr::null_mut();
734 }
735
736 let event = &(*event).typ;
737
738 match event {
739 EventType::Info(msg)
740 | EventType::SmtpConnected(msg)
741 | EventType::ImapConnected(msg)
742 | EventType::SmtpMessageSent(msg)
743 | EventType::ImapMessageDeleted(msg)
744 | EventType::ImapMessageMoved(msg)
745 | EventType::NewBlobFile(msg)
746 | EventType::DeletedBlobFile(msg)
747 | EventType::Warning(msg)
748 | EventType::Error(msg)
749 | EventType::ErrorSelfNotInGroup(msg) => {
750 let data2 = msg.to_c_string().unwrap_or_default();
751 data2.into_raw()
752 }
753 EventType::MsgsChanged { .. }
754 | EventType::ReactionsChanged { .. }
755 | EventType::IncomingMsg { .. }
756 | EventType::ImapInboxIdle
757 | EventType::MsgsNoticed(_)
758 | EventType::MsgDelivered { .. }
759 | EventType::MsgFailed { .. }
760 | EventType::MsgRead { .. }
761 | EventType::MsgDeleted { .. }
762 | EventType::ChatModified(_)
763 | EventType::ContactsChanged(_)
764 | EventType::LocationChanged(_)
765 | EventType::ImexProgress(_)
766 | EventType::SecurejoinInviterProgress { .. }
767 | EventType::SecurejoinJoinerProgress { .. }
768 | EventType::ConnectivityChanged
769 | EventType::SelfavatarChanged
770 | EventType::WebxdcStatusUpdate { .. }
771 | EventType::WebxdcInstanceDeleted { .. }
772 | EventType::AccountsBackgroundFetchDone
773 | EventType::ChatEphemeralTimerModified { .. }
774 | EventType::ChatDeleted { .. }
775 | EventType::IncomingMsgBunch
776 | EventType::ChatlistItemChanged { .. }
777 | EventType::ChatlistChanged
778 | EventType::AccountsChanged
779 | EventType::AccountsItemChanged
780 | EventType::WebxdcRealtimeAdvertisementReceived { .. }
781 | EventType::EventChannelOverflow { .. } => ptr::null_mut(),
782 EventType::ConfigureProgress { comment, .. } => {
783 if let Some(comment) = comment {
784 comment.to_c_string().unwrap_or_default().into_raw()
785 } else {
786 ptr::null_mut()
787 }
788 }
789 EventType::ImexFileWritten(file) => {
790 let data2 = file.to_c_string().unwrap_or_default();
791 data2.into_raw()
792 }
793 EventType::ConfigSynced { key } => {
794 let data2 = key.to_string().to_c_string().unwrap_or_default();
795 data2.into_raw()
796 }
797 EventType::WebxdcRealtimeData { data, .. } => {
798 let ptr = libc::malloc(data.len());
799 libc::memcpy(ptr, data.as_ptr() as *mut libc::c_void, data.len());
800 ptr as *mut libc::c_char
801 }
802 EventType::IncomingReaction { reaction, .. } => reaction
803 .as_str()
804 .to_c_string()
805 .unwrap_or_default()
806 .into_raw(),
807 EventType::IncomingWebxdcNotify { text, .. } => {
808 text.to_c_string().unwrap_or_default().into_raw()
809 }
810 #[allow(unreachable_patterns)]
811 #[cfg(test)]
812 _ => unreachable!("This is just to silence a rust_analyzer false-positive"),
813 }
814}
815
816#[no_mangle]
817pub unsafe extern "C" fn dc_event_get_account_id(event: *mut dc_event_t) -> u32 {
818 if event.is_null() {
819 eprintln!("ignoring careless call to dc_event_get_account_id()");
820 return 0;
821 }
822
823 (*event).id
824}
825
826pub type dc_event_emitter_t = EventEmitter;
827
828#[no_mangle]
829pub unsafe extern "C" fn dc_get_event_emitter(
830 context: *mut dc_context_t,
831) -> *mut dc_event_emitter_t {
832 if context.is_null() {
833 eprintln!("ignoring careless call to dc_get_event_emitter()");
834 return ptr::null_mut();
835 }
836 let ctx = &*context;
837 Box::into_raw(Box::new(ctx.get_event_emitter()))
838}
839
840#[no_mangle]
841pub unsafe extern "C" fn dc_event_emitter_unref(emitter: *mut dc_event_emitter_t) {
842 if emitter.is_null() {
843 eprintln!("ignoring careless call to dc_event_emitter_unref()");
844 return;
845 }
846
847 drop(Box::from_raw(emitter));
848}
849
850#[no_mangle]
851pub unsafe extern "C" fn dc_get_next_event(events: *mut dc_event_emitter_t) -> *mut dc_event_t {
852 if events.is_null() {
853 eprintln!("ignoring careless call to dc_get_next_event()");
854 return ptr::null_mut();
855 }
856 let events = &*events;
857
858 block_on(async move {
859 events
860 .recv()
861 .await
862 .map(|ev| Box::into_raw(Box::new(ev)))
863 .unwrap_or_else(ptr::null_mut)
864 })
865}
866
867#[no_mangle]
868pub unsafe extern "C" fn dc_stop_io(context: *mut dc_context_t) {
869 if context.is_null() {
870 eprintln!("ignoring careless call to dc_stop_io()");
871 return;
872 }
873 let ctx = &*context;
874
875 block_on(async move {
876 ctx.stop_io().await;
877 })
878}
879
880#[no_mangle]
881pub unsafe extern "C" fn dc_maybe_network(context: *mut dc_context_t) {
882 if context.is_null() {
883 eprintln!("ignoring careless call to dc_maybe_network()");
884 return;
885 }
886 let ctx = &*context;
887
888 block_on(async move { ctx.maybe_network().await })
889}
890
891#[no_mangle]
892pub unsafe extern "C" fn dc_preconfigure_keypair(
893 context: *mut dc_context_t,
894 secret_data: *const libc::c_char,
895) -> i32 {
896 if context.is_null() {
897 eprintln!("ignoring careless call to dc_preconfigure_keypair()");
898 return 0;
899 }
900 let ctx = &*context;
901 let secret_data = to_string_lossy(secret_data);
902 block_on(preconfigure_keypair(ctx, &secret_data))
903 .context("Failed to save keypair")
904 .log_err(ctx)
905 .is_ok() as libc::c_int
906}
907
908#[no_mangle]
909pub unsafe extern "C" fn dc_get_chatlist(
910 context: *mut dc_context_t,
911 flags: libc::c_int,
912 query_str: *const libc::c_char,
913 query_id: u32,
914) -> *mut dc_chatlist_t {
915 if context.is_null() {
916 eprintln!("ignoring careless call to dc_get_chatlist()");
917 return ptr::null_mut();
918 }
919 let ctx = &*context;
920 let qs = to_opt_string_lossy(query_str);
921
922 let qi = if query_id == 0 {
923 None
924 } else {
925 Some(ContactId::new(query_id))
926 };
927
928 block_on(async move {
929 match chatlist::Chatlist::try_load(ctx, flags as usize, qs.as_deref(), qi)
930 .await
931 .context("Failed to get chatlist")
932 .log_err(ctx)
933 {
934 Ok(list) => {
935 let ffi_list = ChatlistWrapper { context, list };
936 Box::into_raw(Box::new(ffi_list))
937 }
938 Err(_) => ptr::null_mut(),
939 }
940 })
941}
942
943#[no_mangle]
944pub unsafe extern "C" fn dc_create_chat_by_contact_id(
945 context: *mut dc_context_t,
946 contact_id: u32,
947) -> u32 {
948 if context.is_null() {
949 eprintln!("ignoring careless call to dc_create_chat_by_contact_id()");
950 return 0;
951 }
952 let ctx = &*context;
953
954 block_on(async move {
955 ChatId::create_for_contact(ctx, ContactId::new(contact_id))
956 .await
957 .context("Failed to create chat from contact_id")
958 .log_err(ctx)
959 .map(|id| id.to_u32())
960 .unwrap_or(0)
961 })
962}
963
964#[no_mangle]
965pub unsafe extern "C" fn dc_get_chat_id_by_contact_id(
966 context: *mut dc_context_t,
967 contact_id: u32,
968) -> u32 {
969 if context.is_null() {
970 eprintln!("ignoring careless call to dc_get_chat_id_by_contact_id()");
971 return 0;
972 }
973 let ctx = &*context;
974
975 block_on(async move {
976 ChatId::lookup_by_contact(ctx, ContactId::new(contact_id))
977 .await
978 .context("Failed to get chat for contact_id")
979 .log_err(ctx)
980 .unwrap_or_default() .map(|id| id.to_u32())
982 .unwrap_or(0) })
984}
985
986#[no_mangle]
987pub unsafe extern "C" fn dc_send_msg(
988 context: *mut dc_context_t,
989 chat_id: u32,
990 msg: *mut dc_msg_t,
991) -> u32 {
992 if context.is_null() || msg.is_null() {
993 eprintln!("ignoring careless call to dc_send_msg()");
994 return 0;
995 }
996 let ctx = &mut *context;
997 let ffi_msg = &mut *msg;
998
999 block_on(async move {
1000 chat::send_msg(ctx, ChatId::new(chat_id), &mut ffi_msg.message)
1001 .await
1002 .unwrap_or_log_default(ctx, "Failed to send message")
1003 })
1004 .to_u32()
1005}
1006
1007#[no_mangle]
1008pub unsafe extern "C" fn dc_send_msg_sync(
1009 context: *mut dc_context_t,
1010 chat_id: u32,
1011 msg: *mut dc_msg_t,
1012) -> u32 {
1013 if context.is_null() || msg.is_null() {
1014 eprintln!("ignoring careless call to dc_send_msg_sync()");
1015 return 0;
1016 }
1017 let ctx = &mut *context;
1018 let ffi_msg = &mut *msg;
1019
1020 block_on(async move {
1021 chat::send_msg_sync(ctx, ChatId::new(chat_id), &mut ffi_msg.message)
1022 .await
1023 .unwrap_or_log_default(ctx, "Failed to send message")
1024 })
1025 .to_u32()
1026}
1027
1028#[no_mangle]
1029pub unsafe extern "C" fn dc_send_text_msg(
1030 context: *mut dc_context_t,
1031 chat_id: u32,
1032 text_to_send: *const libc::c_char,
1033) -> u32 {
1034 if context.is_null() || text_to_send.is_null() {
1035 eprintln!("ignoring careless call to dc_send_text_msg()");
1036 return 0;
1037 }
1038 let ctx = &*context;
1039 let text_to_send = to_string_lossy(text_to_send);
1040
1041 block_on(async move {
1042 chat::send_text_msg(ctx, ChatId::new(chat_id), text_to_send)
1043 .await
1044 .map(|msg_id| msg_id.to_u32())
1045 .unwrap_or_log_default(ctx, "Failed to send text message")
1046 })
1047}
1048
1049#[no_mangle]
1050pub unsafe extern "C" fn dc_send_edit_request(
1051 context: *mut dc_context_t,
1052 msg_id: u32,
1053 new_text: *const libc::c_char,
1054) {
1055 if context.is_null() || new_text.is_null() {
1056 eprintln!("ignoring careless call to dc_send_edit_request()");
1057 return;
1058 }
1059 let ctx = &*context;
1060 let new_text = to_string_lossy(new_text);
1061
1062 block_on(chat::send_edit_request(ctx, MsgId::new(msg_id), new_text))
1063 .unwrap_or_log_default(ctx, "Failed to send text edit")
1064}
1065
1066#[no_mangle]
1067pub unsafe extern "C" fn dc_send_delete_request(
1068 context: *mut dc_context_t,
1069 msg_ids: *const u32,
1070 msg_cnt: libc::c_int,
1071) {
1072 if context.is_null() || msg_ids.is_null() || msg_cnt <= 0 {
1073 eprintln!("ignoring careless call to dc_send_delete_request()");
1074 return;
1075 }
1076 let ctx = &*context;
1077 let msg_ids = convert_and_prune_message_ids(msg_ids, msg_cnt);
1078
1079 block_on(message::delete_msgs_ex(ctx, &msg_ids, true))
1080 .context("failed dc_send_delete_request() call")
1081 .log_err(ctx)
1082 .ok();
1083}
1084
1085#[no_mangle]
1086pub unsafe extern "C" fn dc_send_videochat_invitation(
1087 context: *mut dc_context_t,
1088 chat_id: u32,
1089) -> u32 {
1090 if context.is_null() {
1091 eprintln!("ignoring careless call to dc_send_videochat_invitation()");
1092 return 0;
1093 }
1094 let ctx = &*context;
1095
1096 block_on(async move {
1097 chat::send_videochat_invitation(ctx, ChatId::new(chat_id))
1098 .await
1099 .map(|msg_id| msg_id.to_u32())
1100 .unwrap_or_log_default(ctx, "Failed to send video chat invitation")
1101 })
1102}
1103
1104#[no_mangle]
1105pub unsafe extern "C" fn dc_send_webxdc_status_update(
1106 context: *mut dc_context_t,
1107 msg_id: u32,
1108 json: *const libc::c_char,
1109 _descr: *const libc::c_char,
1110) -> libc::c_int {
1111 if context.is_null() {
1112 eprintln!("ignoring careless call to dc_send_webxdc_status_update()");
1113 return 0;
1114 }
1115 let ctx = &*context;
1116
1117 block_on(ctx.send_webxdc_status_update(MsgId::new(msg_id), &to_string_lossy(json)))
1118 .context("Failed to send webxdc update")
1119 .log_err(ctx)
1120 .is_ok() as libc::c_int
1121}
1122
1123#[no_mangle]
1124pub unsafe extern "C" fn dc_get_webxdc_status_updates(
1125 context: *mut dc_context_t,
1126 msg_id: u32,
1127 last_known_serial: u32,
1128) -> *mut libc::c_char {
1129 if context.is_null() {
1130 eprintln!("ignoring careless call to dc_get_webxdc_status_updates()");
1131 return "".strdup();
1132 }
1133 let ctx = &*context;
1134
1135 block_on(ctx.get_webxdc_status_updates(
1136 MsgId::new(msg_id),
1137 StatusUpdateSerial::new(last_known_serial),
1138 ))
1139 .unwrap_or_else(|_| "".to_string())
1140 .strdup()
1141}
1142
1143#[no_mangle]
1144pub unsafe extern "C" fn dc_set_webxdc_integration(
1145 context: *mut dc_context_t,
1146 file: *const libc::c_char,
1147) {
1148 if context.is_null() || file.is_null() {
1149 eprintln!("ignoring careless call to dc_set_webxdc_integration()");
1150 return;
1151 }
1152 let ctx = &*context;
1153 block_on(ctx.set_webxdc_integration(&to_string_lossy(file)))
1154 .log_err(ctx)
1155 .unwrap_or_default();
1156}
1157
1158#[no_mangle]
1159pub unsafe extern "C" fn dc_init_webxdc_integration(
1160 context: *mut dc_context_t,
1161 chat_id: u32,
1162) -> u32 {
1163 if context.is_null() {
1164 eprintln!("ignoring careless call to dc_init_webxdc_integration()");
1165 return 0;
1166 }
1167 let ctx = &*context;
1168 let chat_id = if chat_id == 0 {
1169 None
1170 } else {
1171 Some(ChatId::new(chat_id))
1172 };
1173
1174 block_on(ctx.init_webxdc_integration(chat_id))
1175 .log_err(ctx)
1176 .map(|msg_id| msg_id.map(|id| id.to_u32()).unwrap_or_default())
1177 .unwrap_or(0)
1178}
1179
1180#[no_mangle]
1181pub unsafe extern "C" fn dc_set_draft(
1182 context: *mut dc_context_t,
1183 chat_id: u32,
1184 msg: *mut dc_msg_t,
1185) {
1186 if context.is_null() {
1187 eprintln!("ignoring careless call to dc_set_draft()");
1188 return;
1189 }
1190 let ctx = &*context;
1191 let msg = if msg.is_null() {
1192 None
1193 } else {
1194 let ffi_msg: &mut MessageWrapper = &mut *msg;
1195 Some(&mut ffi_msg.message)
1196 };
1197
1198 block_on(async move {
1199 ChatId::new(chat_id)
1200 .set_draft(ctx, msg)
1201 .await
1202 .unwrap_or_log_default(ctx, "failed to set draft");
1203 });
1204}
1205
1206#[no_mangle]
1207pub unsafe extern "C" fn dc_add_device_msg(
1208 context: *mut dc_context_t,
1209 label: *const libc::c_char,
1210 msg: *mut dc_msg_t,
1211) -> u32 {
1212 if context.is_null() || (label.is_null() && msg.is_null()) {
1213 eprintln!("ignoring careless call to dc_add_device_msg()");
1214 return 0;
1215 }
1216 let ctx = &mut *context;
1217 let msg = if msg.is_null() {
1218 None
1219 } else {
1220 let ffi_msg: &mut MessageWrapper = &mut *msg;
1221 Some(&mut ffi_msg.message)
1222 };
1223
1224 block_on(async move {
1225 chat::add_device_msg(ctx, to_opt_string_lossy(label).as_deref(), msg)
1226 .await
1227 .unwrap_or_log_default(ctx, "Failed to add device message")
1228 })
1229 .to_u32()
1230}
1231
1232#[no_mangle]
1233pub unsafe extern "C" fn dc_was_device_msg_ever_added(
1234 context: *mut dc_context_t,
1235 label: *const libc::c_char,
1236) -> libc::c_int {
1237 if context.is_null() || label.is_null() {
1238 eprintln!("ignoring careless call to dc_was_device_msg_ever_added()");
1239 return 0;
1240 }
1241 let ctx = &mut *context;
1242
1243 block_on(async move {
1244 chat::was_device_msg_ever_added(ctx, &to_string_lossy(label))
1245 .await
1246 .unwrap_or(false) as libc::c_int
1247 })
1248}
1249
1250#[no_mangle]
1251pub unsafe extern "C" fn dc_get_draft(context: *mut dc_context_t, chat_id: u32) -> *mut dc_msg_t {
1252 if context.is_null() {
1253 eprintln!("ignoring careless call to dc_get_draft()");
1254 return ptr::null_mut(); }
1256 let ctx = &*context;
1257
1258 block_on(async move {
1259 match ChatId::new(chat_id).get_draft(ctx).await {
1260 Ok(Some(draft)) => {
1261 let ffi_msg = MessageWrapper {
1262 context,
1263 message: draft,
1264 };
1265 Box::into_raw(Box::new(ffi_msg))
1266 }
1267 Ok(None) => ptr::null_mut(),
1268 Err(err) => {
1269 error!(ctx, "Failed to get draft for chat #{chat_id}: {err:#}");
1270 ptr::null_mut()
1271 }
1272 }
1273 })
1274}
1275
1276#[no_mangle]
1277pub unsafe extern "C" fn dc_get_chat_msgs(
1278 context: *mut dc_context_t,
1279 chat_id: u32,
1280 flags: u32,
1281 _marker1before: u32,
1282) -> *mut dc_array::dc_array_t {
1283 if context.is_null() {
1284 eprintln!("ignoring careless call to dc_get_chat_msgs()");
1285 return ptr::null_mut();
1286 }
1287 let ctx = &*context;
1288
1289 let info_only = (flags & DC_GCM_INFO_ONLY) != 0;
1290 let add_daymarker = (flags & DC_GCM_ADDDAYMARKER) != 0;
1291 block_on(async move {
1292 Box::into_raw(Box::new(
1293 chat::get_chat_msgs_ex(
1294 ctx,
1295 ChatId::new(chat_id),
1296 MessageListOptions {
1297 info_only,
1298 add_daymarker,
1299 },
1300 )
1301 .await
1302 .unwrap_or_log_default(ctx, "failed to get chat msgs")
1303 .into(),
1304 ))
1305 })
1306}
1307
1308#[no_mangle]
1309pub unsafe extern "C" fn dc_get_msg_cnt(context: *mut dc_context_t, chat_id: u32) -> libc::c_int {
1310 if context.is_null() {
1311 eprintln!("ignoring careless call to dc_get_msg_cnt()");
1312 return 0;
1313 }
1314 let ctx = &*context;
1315
1316 block_on(async move {
1317 ChatId::new(chat_id)
1318 .get_msg_cnt(ctx)
1319 .await
1320 .unwrap_or_log_default(ctx, "failed to get msg count") as libc::c_int
1321 })
1322}
1323
1324#[no_mangle]
1325pub unsafe extern "C" fn dc_get_fresh_msg_cnt(
1326 context: *mut dc_context_t,
1327 chat_id: u32,
1328) -> libc::c_int {
1329 if context.is_null() {
1330 eprintln!("ignoring careless call to dc_get_fresh_msg_cnt()");
1331 return 0;
1332 }
1333 let ctx = &*context;
1334
1335 block_on(async move {
1336 ChatId::new(chat_id)
1337 .get_fresh_msg_cnt(ctx)
1338 .await
1339 .unwrap_or_log_default(ctx, "failed to get fresh msg cnt") as libc::c_int
1340 })
1341}
1342
1343#[no_mangle]
1344pub unsafe extern "C" fn dc_get_similar_chatlist(
1345 context: *mut dc_context_t,
1346 chat_id: u32,
1347) -> *mut dc_chatlist_t {
1348 if context.is_null() {
1349 eprintln!("ignoring careless call to dc_get_similar_chatlist()");
1350 return ptr::null_mut();
1351 }
1352 let ctx = &*context;
1353
1354 let chat_id = ChatId::new(chat_id);
1355 match block_on(chat_id.get_similar_chatlist(ctx))
1356 .context("failed to get similar chatlist")
1357 .log_err(ctx)
1358 {
1359 Ok(list) => {
1360 let ffi_list = ChatlistWrapper { context, list };
1361 Box::into_raw(Box::new(ffi_list))
1362 }
1363 Err(_) => ptr::null_mut(),
1364 }
1365}
1366
1367#[no_mangle]
1368pub unsafe extern "C" fn dc_estimate_deletion_cnt(
1369 context: *mut dc_context_t,
1370 from_server: libc::c_int,
1371 seconds: i64,
1372) -> libc::c_int {
1373 if context.is_null() || seconds < 0 {
1374 eprintln!("ignoring careless call to dc_estimate_deletion_cnt()");
1375 return 0;
1376 }
1377 let ctx = &*context;
1378 block_on(async move {
1379 message::estimate_deletion_cnt(ctx, from_server != 0, seconds)
1380 .await
1381 .unwrap_or(0) as libc::c_int
1382 })
1383}
1384
1385#[no_mangle]
1386pub unsafe extern "C" fn dc_get_fresh_msgs(
1387 context: *mut dc_context_t,
1388) -> *mut dc_array::dc_array_t {
1389 if context.is_null() {
1390 eprintln!("ignoring careless call to dc_get_fresh_msgs()");
1391 return ptr::null_mut();
1392 }
1393 let ctx = &*context;
1394
1395 block_on(async move {
1396 let arr = dc_array_t::from(
1397 ctx.get_fresh_msgs()
1398 .await
1399 .context("Failed to get fresh messages")
1400 .log_err(ctx)
1401 .unwrap_or_default()
1402 .iter()
1403 .map(|msg_id| msg_id.to_u32())
1404 .collect::<Vec<u32>>(),
1405 );
1406 Box::into_raw(Box::new(arr))
1407 })
1408}
1409
1410#[no_mangle]
1411pub unsafe extern "C" fn dc_get_next_msgs(context: *mut dc_context_t) -> *mut dc_array::dc_array_t {
1412 if context.is_null() {
1413 eprintln!("ignoring careless call to dc_get_next_msgs()");
1414 return ptr::null_mut();
1415 }
1416 let ctx = &*context;
1417
1418 let msg_ids = block_on(ctx.get_next_msgs())
1419 .context("failed to get next messages")
1420 .log_err(ctx)
1421 .unwrap_or_default();
1422 let arr = dc_array_t::from(
1423 msg_ids
1424 .iter()
1425 .map(|msg_id| msg_id.to_u32())
1426 .collect::<Vec<u32>>(),
1427 );
1428 Box::into_raw(Box::new(arr))
1429}
1430
1431#[no_mangle]
1432pub unsafe extern "C" fn dc_wait_next_msgs(
1433 context: *mut dc_context_t,
1434) -> *mut dc_array::dc_array_t {
1435 if context.is_null() {
1436 eprintln!("ignoring careless call to dc_wait_next_msgs()");
1437 return ptr::null_mut();
1438 }
1439 let ctx = &*context;
1440
1441 let msg_ids = block_on(ctx.wait_next_msgs())
1442 .context("failed to wait for next messages")
1443 .log_err(ctx)
1444 .unwrap_or_default();
1445 let arr = dc_array_t::from(
1446 msg_ids
1447 .iter()
1448 .map(|msg_id| msg_id.to_u32())
1449 .collect::<Vec<u32>>(),
1450 );
1451 Box::into_raw(Box::new(arr))
1452}
1453
1454#[no_mangle]
1455pub unsafe extern "C" fn dc_marknoticed_chat(context: *mut dc_context_t, chat_id: u32) {
1456 if context.is_null() {
1457 eprintln!("ignoring careless call to dc_marknoticed_chat()");
1458 return;
1459 }
1460 let ctx = &*context;
1461
1462 block_on(async move {
1463 chat::marknoticed_chat(ctx, ChatId::new(chat_id))
1464 .await
1465 .context("Failed marknoticed chat")
1466 .log_err(ctx)
1467 .unwrap_or(())
1468 })
1469}
1470
1471fn from_prim<S, T>(s: S) -> Option<T>
1472where
1473 T: FromPrimitive,
1474 S: Into<i64>,
1475{
1476 FromPrimitive::from_i64(s.into())
1477}
1478
1479#[no_mangle]
1480pub unsafe extern "C" fn dc_get_chat_media(
1481 context: *mut dc_context_t,
1482 chat_id: u32,
1483 msg_type: libc::c_int,
1484 or_msg_type2: libc::c_int,
1485 or_msg_type3: libc::c_int,
1486) -> *mut dc_array::dc_array_t {
1487 if context.is_null() {
1488 eprintln!("ignoring careless call to dc_get_chat_media()");
1489 return ptr::null_mut();
1490 }
1491 let ctx = &*context;
1492 let chat_id = if chat_id == 0 {
1493 None
1494 } else {
1495 Some(ChatId::new(chat_id))
1496 };
1497 let msg_type = from_prim(msg_type).expect(&format!("invalid msg_type = {msg_type}"));
1498 let or_msg_type2 =
1499 from_prim(or_msg_type2).expect(&format!("incorrect or_msg_type2 = {or_msg_type2}"));
1500 let or_msg_type3 =
1501 from_prim(or_msg_type3).expect(&format!("incorrect or_msg_type3 = {or_msg_type3}"));
1502
1503 block_on(async move {
1504 Box::into_raw(Box::new(
1505 chat::get_chat_media(ctx, chat_id, msg_type, or_msg_type2, or_msg_type3)
1506 .await
1507 .unwrap_or_log_default(ctx, "Failed get_chat_media")
1508 .into(),
1509 ))
1510 })
1511}
1512
1513#[no_mangle]
1514pub unsafe extern "C" fn dc_set_chat_visibility(
1515 context: *mut dc_context_t,
1516 chat_id: u32,
1517 archive: libc::c_int,
1518) {
1519 if context.is_null() {
1520 eprintln!("ignoring careless call to dc_set_chat_visibility()");
1521 return;
1522 }
1523 let ctx = &*context;
1524 let visibility = match archive {
1525 0 => ChatVisibility::Normal,
1526 1 => ChatVisibility::Archived,
1527 2 => ChatVisibility::Pinned,
1528 _ => {
1529 warn!(
1530 ctx,
1531 "ignoring careless call to dc_set_chat_visibility(): unknown archived state",
1532 );
1533 return;
1534 }
1535 };
1536
1537 block_on(async move {
1538 ChatId::new(chat_id)
1539 .set_visibility(ctx, visibility)
1540 .await
1541 .context("Failed setting chat visibility")
1542 .log_err(ctx)
1543 .unwrap_or(())
1544 })
1545}
1546
1547#[no_mangle]
1548pub unsafe extern "C" fn dc_delete_chat(context: *mut dc_context_t, chat_id: u32) {
1549 if context.is_null() {
1550 eprintln!("ignoring careless call to dc_delete_chat()");
1551 return;
1552 }
1553 let ctx = &*context;
1554
1555 block_on(async move {
1556 ChatId::new(chat_id)
1557 .delete(ctx)
1558 .await
1559 .context("Failed chat delete")
1560 .log_err(ctx)
1561 .ok();
1562 })
1563}
1564
1565#[no_mangle]
1566pub unsafe extern "C" fn dc_block_chat(context: *mut dc_context_t, chat_id: u32) {
1567 if context.is_null() {
1568 eprintln!("ignoring careless call to dc_block_chat()");
1569 return;
1570 }
1571 let ctx = &*context;
1572
1573 block_on(async move {
1574 ChatId::new(chat_id)
1575 .block(ctx)
1576 .await
1577 .context("Failed chat block")
1578 .log_err(ctx)
1579 .ok();
1580 })
1581}
1582
1583#[no_mangle]
1584pub unsafe extern "C" fn dc_accept_chat(context: *mut dc_context_t, chat_id: u32) {
1585 if context.is_null() {
1586 eprintln!("ignoring careless call to dc_accept_chat()");
1587 return;
1588 }
1589 let ctx = &*context;
1590
1591 block_on(async move {
1592 ChatId::new(chat_id)
1593 .accept(ctx)
1594 .await
1595 .context("Failed chat accept")
1596 .log_err(ctx)
1597 .ok();
1598 })
1599}
1600
1601#[no_mangle]
1602pub unsafe extern "C" fn dc_get_chat_contacts(
1603 context: *mut dc_context_t,
1604 chat_id: u32,
1605) -> *mut dc_array::dc_array_t {
1606 if context.is_null() {
1607 eprintln!("ignoring careless call to dc_get_chat_contacts()");
1608 return ptr::null_mut();
1609 }
1610 let ctx = &*context;
1611
1612 block_on(async move {
1613 let arr = dc_array_t::from(
1614 chat::get_chat_contacts(ctx, ChatId::new(chat_id))
1615 .await
1616 .unwrap_or_log_default(ctx, "Failed get_chat_contacts")
1617 .iter()
1618 .map(|id| id.to_u32())
1619 .collect::<Vec<u32>>(),
1620 );
1621 Box::into_raw(Box::new(arr))
1622 })
1623}
1624
1625#[no_mangle]
1626pub unsafe extern "C" fn dc_search_msgs(
1627 context: *mut dc_context_t,
1628 chat_id: u32,
1629 query: *const libc::c_char,
1630) -> *mut dc_array::dc_array_t {
1631 if context.is_null() || query.is_null() {
1632 eprintln!("ignoring careless call to dc_search_msgs()");
1633 return ptr::null_mut();
1634 }
1635 let ctx = &*context;
1636 let chat_id = if chat_id == 0 {
1637 None
1638 } else {
1639 Some(ChatId::new(chat_id))
1640 };
1641
1642 block_on(async move {
1643 let arr = dc_array_t::from(
1644 ctx.search_msgs(chat_id, &to_string_lossy(query))
1645 .await
1646 .unwrap_or_log_default(ctx, "Failed search_msgs")
1647 .iter()
1648 .map(|msg_id| msg_id.to_u32())
1649 .collect::<Vec<u32>>(),
1650 );
1651 Box::into_raw(Box::new(arr))
1652 })
1653}
1654
1655#[no_mangle]
1656pub unsafe extern "C" fn dc_get_chat(context: *mut dc_context_t, chat_id: u32) -> *mut dc_chat_t {
1657 if context.is_null() {
1658 eprintln!("ignoring careless call to dc_get_chat()");
1659 return ptr::null_mut();
1660 }
1661 let ctx = &*context;
1662 let context: Context = ctx.clone();
1663
1664 block_on(async move {
1665 match chat::Chat::load_from_db(ctx, ChatId::new(chat_id)).await {
1666 Ok(chat) => {
1667 let ffi_chat = ChatWrapper { context, chat };
1668 Box::into_raw(Box::new(ffi_chat))
1669 }
1670 Err(_) => ptr::null_mut(),
1671 }
1672 })
1673}
1674
1675#[no_mangle]
1676pub unsafe extern "C" fn dc_create_group_chat(
1677 context: *mut dc_context_t,
1678 protect: libc::c_int,
1679 name: *const libc::c_char,
1680) -> u32 {
1681 if context.is_null() || name.is_null() {
1682 eprintln!("ignoring careless call to dc_create_group_chat()");
1683 return 0;
1684 }
1685 let ctx = &*context;
1686 let protect = if let Some(s) = ProtectionStatus::from_i32(protect) {
1687 s
1688 } else {
1689 warn!(ctx, "bad protect-value for dc_create_group_chat()");
1690 return 0;
1691 };
1692
1693 block_on(async move {
1694 chat::create_group_chat(ctx, protect, &to_string_lossy(name))
1695 .await
1696 .context("Failed to create group chat")
1697 .log_err(ctx)
1698 .map(|id| id.to_u32())
1699 .unwrap_or(0)
1700 })
1701}
1702
1703#[no_mangle]
1704pub unsafe extern "C" fn dc_create_broadcast_list(context: *mut dc_context_t) -> u32 {
1705 if context.is_null() {
1706 eprintln!("ignoring careless call to dc_create_broadcast_list()");
1707 return 0;
1708 }
1709 let ctx = &*context;
1710 block_on(chat::create_broadcast_list(ctx))
1711 .context("Failed to create broadcast list")
1712 .log_err(ctx)
1713 .map(|id| id.to_u32())
1714 .unwrap_or(0)
1715}
1716
1717#[no_mangle]
1718pub unsafe extern "C" fn dc_is_contact_in_chat(
1719 context: *mut dc_context_t,
1720 chat_id: u32,
1721 contact_id: u32,
1722) -> libc::c_int {
1723 if context.is_null() {
1724 eprintln!("ignoring careless call to dc_is_contact_in_chat()");
1725 return 0;
1726 }
1727 let ctx = &*context;
1728
1729 block_on(chat::is_contact_in_chat(
1730 ctx,
1731 ChatId::new(chat_id),
1732 ContactId::new(contact_id),
1733 ))
1734 .context("is_contact_in_chat failed")
1735 .log_err(ctx)
1736 .unwrap_or_default() as libc::c_int
1737}
1738
1739#[no_mangle]
1740pub unsafe extern "C" fn dc_add_contact_to_chat(
1741 context: *mut dc_context_t,
1742 chat_id: u32,
1743 contact_id: u32,
1744) -> libc::c_int {
1745 if context.is_null() {
1746 eprintln!("ignoring careless call to dc_add_contact_to_chat()");
1747 return 0;
1748 }
1749 let ctx = &*context;
1750
1751 block_on(chat::add_contact_to_chat(
1752 ctx,
1753 ChatId::new(chat_id),
1754 ContactId::new(contact_id),
1755 ))
1756 .context("Failed to add contact")
1757 .log_err(ctx)
1758 .is_ok() as libc::c_int
1759}
1760
1761#[no_mangle]
1762pub unsafe extern "C" fn dc_remove_contact_from_chat(
1763 context: *mut dc_context_t,
1764 chat_id: u32,
1765 contact_id: u32,
1766) -> libc::c_int {
1767 if context.is_null() {
1768 eprintln!("ignoring careless call to dc_remove_contact_from_chat()");
1769 return 0;
1770 }
1771 let ctx = &*context;
1772
1773 block_on(chat::remove_contact_from_chat(
1774 ctx,
1775 ChatId::new(chat_id),
1776 ContactId::new(contact_id),
1777 ))
1778 .context("Failed to remove contact")
1779 .log_err(ctx)
1780 .is_ok() as libc::c_int
1781}
1782
1783#[no_mangle]
1784pub unsafe extern "C" fn dc_set_chat_name(
1785 context: *mut dc_context_t,
1786 chat_id: u32,
1787 name: *const libc::c_char,
1788) -> libc::c_int {
1789 if context.is_null() || chat_id <= constants::DC_CHAT_ID_LAST_SPECIAL.to_u32() || name.is_null()
1790 {
1791 eprintln!("ignoring careless call to dc_set_chat_name()");
1792 return 0;
1793 }
1794 let ctx = &*context;
1795
1796 block_on(async move {
1797 chat::set_chat_name(ctx, ChatId::new(chat_id), &to_string_lossy(name))
1798 .await
1799 .map(|_| 1)
1800 .unwrap_or_log_default(ctx, "Failed to set chat name")
1801 })
1802}
1803
1804#[no_mangle]
1805pub unsafe extern "C" fn dc_set_chat_profile_image(
1806 context: *mut dc_context_t,
1807 chat_id: u32,
1808 image: *const libc::c_char,
1809) -> libc::c_int {
1810 if context.is_null() || chat_id <= constants::DC_CHAT_ID_LAST_SPECIAL.to_u32() {
1811 eprintln!("ignoring careless call to dc_set_chat_profile_image()");
1812 return 0;
1813 }
1814 let ctx = &*context;
1815
1816 block_on(async move {
1817 chat::set_chat_profile_image(ctx, ChatId::new(chat_id), &to_string_lossy(image))
1818 .await
1819 .map(|_| 1)
1820 .unwrap_or_log_default(ctx, "Failed to set profile image")
1821 })
1822}
1823
1824#[no_mangle]
1825pub unsafe extern "C" fn dc_set_chat_mute_duration(
1826 context: *mut dc_context_t,
1827 chat_id: u32,
1828 duration: i64,
1829) -> libc::c_int {
1830 if context.is_null() {
1831 eprintln!("ignoring careless call to dc_set_chat_mute_duration()");
1832 return 0;
1833 }
1834 let ctx = &*context;
1835 let muteDuration = match duration {
1836 0 => MuteDuration::NotMuted,
1837 -1 => MuteDuration::Forever,
1838 n if n > 0 => SystemTime::now()
1839 .checked_add(Duration::from_secs(duration as u64))
1840 .map_or(MuteDuration::Forever, MuteDuration::Until),
1841 _ => {
1842 warn!(
1843 ctx,
1844 "dc_chat_set_mute_duration(): Can not use negative duration other than -1",
1845 );
1846 return 0;
1847 }
1848 };
1849
1850 block_on(async move {
1851 chat::set_muted(ctx, ChatId::new(chat_id), muteDuration)
1852 .await
1853 .map(|_| 1)
1854 .unwrap_or_log_default(ctx, "Failed to set mute duration")
1855 })
1856}
1857
1858#[no_mangle]
1859pub unsafe extern "C" fn dc_get_chat_encrinfo(
1860 context: *mut dc_context_t,
1861 chat_id: u32,
1862) -> *mut libc::c_char {
1863 if context.is_null() {
1864 eprintln!("ignoring careless call to dc_get_chat_encrinfo()");
1865 return "".strdup();
1866 }
1867 let ctx = &*context;
1868
1869 block_on(async move {
1870 ChatId::new(chat_id)
1871 .get_encryption_info(ctx)
1872 .await
1873 .map(|s| s.strdup())
1874 .unwrap_or_else(|e| {
1875 error!(ctx, "{e:#}");
1876 ptr::null_mut()
1877 })
1878 })
1879}
1880
1881#[no_mangle]
1882pub unsafe extern "C" fn dc_get_chat_ephemeral_timer(
1883 context: *mut dc_context_t,
1884 chat_id: u32,
1885) -> u32 {
1886 if context.is_null() {
1887 eprintln!("ignoring careless call to dc_get_chat_ephemeral_timer()");
1888 return 0;
1889 }
1890 let ctx = &*context;
1891
1892 block_on(async move { ChatId::new(chat_id).get_ephemeral_timer(ctx).await })
1898 .context("Failed to get ephemeral timer")
1899 .log_err(ctx)
1900 .unwrap_or_default()
1901 .to_u32()
1902}
1903
1904#[no_mangle]
1905pub unsafe extern "C" fn dc_set_chat_ephemeral_timer(
1906 context: *mut dc_context_t,
1907 chat_id: u32,
1908 timer: u32,
1909) -> libc::c_int {
1910 if context.is_null() {
1911 eprintln!("ignoring careless call to dc_set_chat_ephemeral_timer()");
1912 return 0;
1913 }
1914 let ctx = &*context;
1915
1916 block_on(async move {
1917 ChatId::new(chat_id)
1918 .set_ephemeral_timer(ctx, EphemeralTimer::from_u32(timer))
1919 .await
1920 .context("Failed to set ephemeral timer")
1921 .log_err(ctx)
1922 .is_ok() as libc::c_int
1923 })
1924}
1925
1926#[no_mangle]
1927pub unsafe extern "C" fn dc_get_msg_info(
1928 context: *mut dc_context_t,
1929 msg_id: u32,
1930) -> *mut libc::c_char {
1931 if context.is_null() {
1932 eprintln!("ignoring careless call to dc_get_msg_info()");
1933 return "".strdup();
1934 }
1935 let ctx = &*context;
1936 let msg_id = MsgId::new(msg_id);
1937 block_on(msg_id.get_info(ctx))
1938 .unwrap_or_log_default(ctx, "failed to get msg id")
1939 .strdup()
1940}
1941
1942#[no_mangle]
1943pub unsafe extern "C" fn dc_get_msg_html(
1944 context: *mut dc_context_t,
1945 msg_id: u32,
1946) -> *mut libc::c_char {
1947 if context.is_null() {
1948 eprintln!("ignoring careless call to dc_get_msg_html()");
1949 return ptr::null_mut();
1950 }
1951 let ctx = &*context;
1952
1953 block_on(MsgId::new(msg_id).get_html(ctx))
1954 .unwrap_or_log_default(ctx, "Failed get_msg_html")
1955 .strdup()
1956}
1957
1958#[no_mangle]
1959pub unsafe extern "C" fn dc_delete_msgs(
1960 context: *mut dc_context_t,
1961 msg_ids: *const u32,
1962 msg_cnt: libc::c_int,
1963) {
1964 if context.is_null() || msg_ids.is_null() || msg_cnt <= 0 {
1965 eprintln!("ignoring careless call to dc_delete_msgs()");
1966 return;
1967 }
1968 let ctx = &*context;
1969 let msg_ids = convert_and_prune_message_ids(msg_ids, msg_cnt);
1970
1971 block_on(message::delete_msgs(ctx, &msg_ids))
1972 .context("failed dc_delete_msgs() call")
1973 .log_err(ctx)
1974 .ok();
1975}
1976
1977#[no_mangle]
1978pub unsafe extern "C" fn dc_forward_msgs(
1979 context: *mut dc_context_t,
1980 msg_ids: *const u32,
1981 msg_cnt: libc::c_int,
1982 chat_id: u32,
1983) {
1984 if context.is_null()
1985 || msg_ids.is_null()
1986 || msg_cnt <= 0
1987 || chat_id <= constants::DC_CHAT_ID_LAST_SPECIAL.to_u32()
1988 {
1989 eprintln!("ignoring careless call to dc_forward_msgs()");
1990 return;
1991 }
1992 let msg_ids = convert_and_prune_message_ids(msg_ids, msg_cnt);
1993 let ctx = &*context;
1994
1995 block_on(async move {
1996 chat::forward_msgs(ctx, &msg_ids[..], ChatId::new(chat_id))
1997 .await
1998 .unwrap_or_log_default(ctx, "Failed to forward message")
1999 })
2000}
2001
2002#[no_mangle]
2003pub unsafe extern "C" fn dc_save_msgs(
2004 context: *mut dc_context_t,
2005 msg_ids: *const u32,
2006 msg_cnt: libc::c_int,
2007) {
2008 if context.is_null() || msg_ids.is_null() || msg_cnt <= 0 {
2009 eprintln!("ignoring careless call to dc_save_msgs()");
2010 return;
2011 }
2012 let msg_ids = convert_and_prune_message_ids(msg_ids, msg_cnt);
2013 let ctx = &*context;
2014
2015 block_on(async move {
2016 chat::save_msgs(ctx, &msg_ids[..])
2017 .await
2018 .unwrap_or_log_default(ctx, "Failed to save message")
2019 })
2020}
2021
2022#[no_mangle]
2023pub unsafe extern "C" fn dc_resend_msgs(
2024 context: *mut dc_context_t,
2025 msg_ids: *const u32,
2026 msg_cnt: libc::c_int,
2027) -> libc::c_int {
2028 if context.is_null() || msg_ids.is_null() || msg_cnt <= 0 {
2029 eprintln!("ignoring careless call to dc_resend_msgs()");
2030 return 0;
2031 }
2032 let ctx = &*context;
2033 let msg_ids = convert_and_prune_message_ids(msg_ids, msg_cnt);
2034
2035 if let Err(err) = block_on(chat::resend_msgs(ctx, &msg_ids)) {
2036 error!(ctx, "Resending failed: {err:#}");
2037 0
2038 } else {
2039 1
2040 }
2041}
2042
2043#[no_mangle]
2044pub unsafe extern "C" fn dc_markseen_msgs(
2045 context: *mut dc_context_t,
2046 msg_ids: *const u32,
2047 msg_cnt: libc::c_int,
2048) {
2049 if context.is_null() || msg_ids.is_null() || msg_cnt <= 0 {
2050 eprintln!("ignoring careless call to dc_markseen_msgs()");
2051 return;
2052 }
2053 let msg_ids = convert_and_prune_message_ids(msg_ids, msg_cnt);
2054 let ctx = &*context;
2055
2056 block_on(message::markseen_msgs(ctx, msg_ids))
2057 .context("failed dc_markseen_msgs() call")
2058 .log_err(ctx)
2059 .ok();
2060}
2061
2062#[no_mangle]
2063pub unsafe extern "C" fn dc_get_msg(context: *mut dc_context_t, msg_id: u32) -> *mut dc_msg_t {
2064 if context.is_null() {
2065 eprintln!("ignoring careless call to dc_get_msg()");
2066 return ptr::null_mut();
2067 }
2068 let ctx = &*context;
2069
2070 block_on(async move {
2071 let message = match message::Message::load_from_db(ctx, MsgId::new(msg_id)).await {
2072 Ok(msg) => msg,
2073 Err(e) => {
2074 if msg_id <= constants::DC_MSG_ID_LAST_SPECIAL {
2075 warn!(
2077 ctx,
2078 "dc_get_msg called with special msg_id={msg_id}, returning empty msg"
2079 );
2080 message::Message::new(Viewtype::default())
2081 } else {
2082 warn!(ctx, "dc_get_msg could not retrieve msg_id {msg_id}: {e:#}");
2083 return ptr::null_mut();
2084 }
2085 }
2086 };
2087 let ffi_msg = MessageWrapper { context, message };
2088 Box::into_raw(Box::new(ffi_msg))
2089 })
2090}
2091
2092#[no_mangle]
2093pub unsafe extern "C" fn dc_download_full_msg(context: *mut dc_context_t, msg_id: u32) {
2094 if context.is_null() {
2095 eprintln!("ignoring careless call to dc_download_full_msg()");
2096 return;
2097 }
2098 let ctx = &*context;
2099 block_on(MsgId::new(msg_id).download_full(ctx))
2100 .context("Failed to download message fully.")
2101 .log_err(ctx)
2102 .ok();
2103}
2104
2105#[no_mangle]
2106pub unsafe extern "C" fn dc_may_be_valid_addr(addr: *const libc::c_char) -> libc::c_int {
2107 if addr.is_null() {
2108 eprintln!("ignoring careless call to dc_may_be_valid_addr()");
2109 return 0;
2110 }
2111
2112 contact::may_be_valid_addr(&to_string_lossy(addr)) as libc::c_int
2113}
2114
2115#[no_mangle]
2116pub unsafe extern "C" fn dc_lookup_contact_id_by_addr(
2117 context: *mut dc_context_t,
2118 addr: *const libc::c_char,
2119) -> u32 {
2120 if context.is_null() || addr.is_null() {
2121 eprintln!("ignoring careless call to dc_lookup_contact_id_by_addr()");
2122 return 0;
2123 }
2124 let ctx = &*context;
2125
2126 block_on(async move {
2127 Contact::lookup_id_by_addr(ctx, &to_string_lossy(addr), Origin::IncomingReplyTo)
2128 .await
2129 .unwrap_or_log_default(ctx, "failed to lookup id")
2130 .map(|id| id.to_u32())
2131 .unwrap_or_default()
2132 })
2133}
2134
2135#[no_mangle]
2136pub unsafe extern "C" fn dc_create_contact(
2137 context: *mut dc_context_t,
2138 name: *const libc::c_char,
2139 addr: *const libc::c_char,
2140) -> u32 {
2141 if context.is_null() || addr.is_null() {
2142 eprintln!("ignoring careless call to dc_create_contact()");
2143 return 0;
2144 }
2145 let ctx = &*context;
2146 let name = to_string_lossy(name);
2147
2148 block_on(Contact::create(ctx, &name, &to_string_lossy(addr)))
2149 .context("Cannot create contact")
2150 .log_err(ctx)
2151 .map(|id| id.to_u32())
2152 .unwrap_or(0)
2153}
2154
2155#[no_mangle]
2156pub unsafe extern "C" fn dc_add_address_book(
2157 context: *mut dc_context_t,
2158 addr_book: *const libc::c_char,
2159) -> libc::c_int {
2160 if context.is_null() || addr_book.is_null() {
2161 eprintln!("ignoring careless call to dc_add_address_book()");
2162 return 0;
2163 }
2164 let ctx = &*context;
2165
2166 block_on(async move {
2167 match Contact::add_address_book(ctx, &to_string_lossy(addr_book)).await {
2168 Ok(cnt) => cnt as libc::c_int,
2169 Err(_) => 0,
2170 }
2171 })
2172}
2173
2174#[no_mangle]
2175pub unsafe extern "C" fn dc_make_vcard(
2176 context: *mut dc_context_t,
2177 contact_id: u32,
2178) -> *mut libc::c_char {
2179 if context.is_null() {
2180 eprintln!("ignoring careless call to dc_make_vcard()");
2181 return ptr::null_mut();
2182 }
2183 let ctx = &*context;
2184 let contact_id = ContactId::new(contact_id);
2185
2186 block_on(contact::make_vcard(ctx, &[contact_id]))
2187 .unwrap_or_log_default(ctx, "dc_make_vcard failed")
2188 .strdup()
2189}
2190
2191#[no_mangle]
2192pub unsafe extern "C" fn dc_import_vcard(
2193 context: *mut dc_context_t,
2194 vcard: *const libc::c_char,
2195) -> *mut dc_array::dc_array_t {
2196 if context.is_null() || vcard.is_null() {
2197 eprintln!("ignoring careless call to dc_import_vcard()");
2198 return ptr::null_mut();
2199 }
2200 let ctx = &*context;
2201
2202 match block_on(contact::import_vcard(ctx, &to_string_lossy(vcard)))
2203 .context("dc_import_vcard failed")
2204 .log_err(ctx)
2205 {
2206 Ok(contact_ids) => Box::into_raw(Box::new(dc_array_t::from(
2207 contact_ids
2208 .iter()
2209 .map(|id| id.to_u32())
2210 .collect::<Vec<u32>>(),
2211 ))),
2212 Err(_) => ptr::null_mut(),
2213 }
2214}
2215
2216#[no_mangle]
2217pub unsafe extern "C" fn dc_get_contacts(
2218 context: *mut dc_context_t,
2219 flags: u32,
2220 query: *const libc::c_char,
2221) -> *mut dc_array::dc_array_t {
2222 if context.is_null() {
2223 eprintln!("ignoring careless call to dc_get_contacts()");
2224 return ptr::null_mut();
2225 }
2226 let ctx = &*context;
2227 let query = to_opt_string_lossy(query);
2228
2229 block_on(async move {
2230 match Contact::get_all(ctx, flags, query.as_deref()).await {
2231 Ok(contacts) => Box::into_raw(Box::new(dc_array_t::from(
2232 contacts.iter().map(|id| id.to_u32()).collect::<Vec<u32>>(),
2233 ))),
2234 Err(_) => ptr::null_mut(),
2235 }
2236 })
2237}
2238
2239#[no_mangle]
2240pub unsafe extern "C" fn dc_get_blocked_cnt(context: *mut dc_context_t) -> libc::c_int {
2241 if context.is_null() {
2242 eprintln!("ignoring careless call to dc_get_blocked_cnt()");
2243 return 0;
2244 }
2245 let ctx = &*context;
2246
2247 block_on(async move {
2248 Contact::get_all_blocked(ctx)
2249 .await
2250 .unwrap_or_log_default(ctx, "failed to get blocked count")
2251 .len() as libc::c_int
2252 })
2253}
2254
2255#[no_mangle]
2256pub unsafe extern "C" fn dc_get_blocked_contacts(
2257 context: *mut dc_context_t,
2258) -> *mut dc_array::dc_array_t {
2259 if context.is_null() {
2260 eprintln!("ignoring careless call to dc_get_blocked_contacts()");
2261 return ptr::null_mut();
2262 }
2263 let ctx = &*context;
2264
2265 block_on(async move {
2266 Box::into_raw(Box::new(dc_array_t::from(
2267 Contact::get_all_blocked(ctx)
2268 .await
2269 .context("Can't get blocked contacts")
2270 .log_err(ctx)
2271 .unwrap_or_default()
2272 .iter()
2273 .map(|id| id.to_u32())
2274 .collect::<Vec<u32>>(),
2275 )))
2276 })
2277}
2278
2279#[no_mangle]
2280pub unsafe extern "C" fn dc_block_contact(
2281 context: *mut dc_context_t,
2282 contact_id: u32,
2283 block: libc::c_int,
2284) {
2285 let contact_id = ContactId::new(contact_id);
2286 if context.is_null() || contact_id.is_special() {
2287 eprintln!("ignoring careless call to dc_block_contact()");
2288 return;
2289 }
2290 let ctx = &*context;
2291 block_on(async move {
2292 if block == 0 {
2293 Contact::unblock(ctx, contact_id)
2294 .await
2295 .context("Can't unblock contact")
2296 .log_err(ctx)
2297 .ok();
2298 } else {
2299 Contact::block(ctx, contact_id)
2300 .await
2301 .context("Can't block contact")
2302 .log_err(ctx)
2303 .ok();
2304 }
2305 });
2306}
2307
2308#[no_mangle]
2309pub unsafe extern "C" fn dc_get_contact_encrinfo(
2310 context: *mut dc_context_t,
2311 contact_id: u32,
2312) -> *mut libc::c_char {
2313 if context.is_null() {
2314 eprintln!("ignoring careless call to dc_get_contact_encrinfo()");
2315 return "".strdup();
2316 }
2317 let ctx = &*context;
2318
2319 block_on(async move {
2320 Contact::get_encrinfo(ctx, ContactId::new(contact_id))
2321 .await
2322 .map(|s| s.strdup())
2323 .unwrap_or_else(|e| {
2324 error!(ctx, "{e:#}");
2325 ptr::null_mut()
2326 })
2327 })
2328}
2329
2330#[no_mangle]
2331pub unsafe extern "C" fn dc_delete_contact(
2332 context: *mut dc_context_t,
2333 contact_id: u32,
2334) -> libc::c_int {
2335 let contact_id = ContactId::new(contact_id);
2336 if context.is_null() || contact_id.is_special() {
2337 eprintln!("ignoring careless call to dc_delete_contact()");
2338 return 0;
2339 }
2340 let ctx = &*context;
2341
2342 block_on(async move {
2343 match Contact::delete(ctx, contact_id).await {
2344 Ok(_) => 1,
2345 Err(err) => {
2346 error!(ctx, "cannot delete contact: {err:#}");
2347 0
2348 }
2349 }
2350 })
2351}
2352
2353#[no_mangle]
2354pub unsafe extern "C" fn dc_get_contact(
2355 context: *mut dc_context_t,
2356 contact_id: u32,
2357) -> *mut dc_contact_t {
2358 if context.is_null() {
2359 eprintln!("ignoring careless call to dc_get_contact()");
2360 return ptr::null_mut();
2361 }
2362 let ctx = &*context;
2363
2364 block_on(async move {
2365 Contact::get_by_id(ctx, ContactId::new(contact_id))
2366 .await
2367 .map(|contact| Box::into_raw(Box::new(ContactWrapper { context, contact })))
2368 .unwrap_or_else(|_| ptr::null_mut())
2369 })
2370}
2371
2372fn spawn_imex(ctx: Context, what: imex::ImexMode, param1: String, passphrase: Option<String>) {
2373 spawn(async move {
2374 imex::imex(&ctx, what, param1.as_ref(), passphrase)
2375 .await
2376 .context("IMEX failed")
2377 .log_err(&ctx)
2378 });
2379}
2380
2381#[no_mangle]
2382pub unsafe extern "C" fn dc_imex(
2383 context: *mut dc_context_t,
2384 what_raw: libc::c_int,
2385 param1: *const libc::c_char,
2386 param2: *const libc::c_char,
2387) {
2388 if context.is_null() {
2389 eprintln!("ignoring careless call to dc_imex()");
2390 return;
2391 }
2392 let what = match imex::ImexMode::from_i32(what_raw) {
2393 Some(what) => what,
2394 None => {
2395 eprintln!("ignoring invalid argument {what_raw} to dc_imex");
2396 return;
2397 }
2398 };
2399 let passphrase = to_opt_string_lossy(param2);
2400
2401 let ctx = &*context;
2402
2403 if let Some(param1) = to_opt_string_lossy(param1) {
2404 spawn_imex(ctx.clone(), what, param1, passphrase);
2405 } else {
2406 eprintln!("dc_imex called without a valid directory");
2407 }
2408}
2409
2410#[no_mangle]
2411pub unsafe extern "C" fn dc_imex_has_backup(
2412 context: *mut dc_context_t,
2413 dir: *const libc::c_char,
2414) -> *mut libc::c_char {
2415 if context.is_null() || dir.is_null() {
2416 eprintln!("ignoring careless call to dc_imex_has_backup()");
2417 return ptr::null_mut(); }
2419 let ctx = &*context;
2420
2421 block_on(async move {
2422 match imex::has_backup(ctx, to_string_lossy(dir).as_ref()).await {
2423 Ok(res) => res.strdup(),
2424 Err(err) => {
2425 warn!(ctx, "dc_imex_has_backup: {err:#}");
2428 ptr::null_mut()
2429 }
2430 }
2431 })
2432}
2433
2434#[no_mangle]
2435pub unsafe extern "C" fn dc_initiate_key_transfer(context: *mut dc_context_t) -> *mut libc::c_char {
2436 if context.is_null() {
2437 eprintln!("ignoring careless call to dc_initiate_key_transfer()");
2438 return ptr::null_mut(); }
2440 let ctx = &*context;
2441
2442 block_on(async move {
2443 match imex::initiate_key_transfer(ctx).await {
2444 Ok(res) => res.strdup(),
2445 Err(err) => {
2446 error!(ctx, "dc_initiate_key_transfer(): {err:#}");
2447 ptr::null_mut()
2448 }
2449 }
2450 })
2451}
2452
2453#[no_mangle]
2454pub unsafe extern "C" fn dc_continue_key_transfer(
2455 context: *mut dc_context_t,
2456 msg_id: u32,
2457 setup_code: *const libc::c_char,
2458) -> libc::c_int {
2459 if context.is_null() || msg_id <= constants::DC_MSG_ID_LAST_SPECIAL || setup_code.is_null() {
2460 eprintln!("ignoring careless call to dc_continue_key_transfer()");
2461 return 0;
2462 }
2463 let ctx = &*context;
2464
2465 block_on(async move {
2466 match imex::continue_key_transfer(ctx, MsgId::new(msg_id), &to_string_lossy(setup_code))
2467 .await
2468 {
2469 Ok(()) => 1,
2470 Err(err) => {
2471 warn!(ctx, "dc_continue_key_transfer: {err:#}");
2472 0
2473 }
2474 }
2475 })
2476}
2477
2478#[no_mangle]
2479pub unsafe extern "C" fn dc_stop_ongoing_process(context: *mut dc_context_t) {
2480 if context.is_null() {
2481 eprintln!("ignoring careless call to dc_stop_ongoing_process()");
2482 return;
2483 }
2484 let ctx = &*context;
2485 block_on(ctx.stop_ongoing());
2486}
2487
2488#[no_mangle]
2489pub unsafe extern "C" fn dc_check_qr(
2490 context: *mut dc_context_t,
2491 qr: *const libc::c_char,
2492) -> *mut dc_lot_t {
2493 if context.is_null() || qr.is_null() {
2494 eprintln!("ignoring careless call to dc_check_qr()");
2495 return ptr::null_mut();
2496 }
2497 let ctx = &*context;
2498
2499 let lot = match block_on(qr::check_qr(ctx, &to_string_lossy(qr))) {
2500 Ok(qr) => qr.into(),
2501 Err(err) => err.into(),
2502 };
2503 Box::into_raw(Box::new(lot))
2504}
2505
2506#[no_mangle]
2507pub unsafe extern "C" fn dc_get_securejoin_qr(
2508 context: *mut dc_context_t,
2509 chat_id: u32,
2510) -> *mut libc::c_char {
2511 if context.is_null() {
2512 eprintln!("ignoring careless call to dc_get_securejoin_qr()");
2513 return "".strdup();
2514 }
2515 let ctx = &*context;
2516 let chat_id = if chat_id == 0 {
2517 None
2518 } else {
2519 Some(ChatId::new(chat_id))
2520 };
2521
2522 block_on(securejoin::get_securejoin_qr(ctx, chat_id))
2523 .unwrap_or_else(|_| "".to_string())
2524 .strdup()
2525}
2526
2527#[no_mangle]
2528pub unsafe extern "C" fn dc_get_securejoin_qr_svg(
2529 context: *mut dc_context_t,
2530 chat_id: u32,
2531) -> *mut libc::c_char {
2532 if context.is_null() {
2533 eprintln!("ignoring careless call to generate_verification_qr()");
2534 return "".strdup();
2535 }
2536 let ctx = &*context;
2537 let chat_id = if chat_id == 0 {
2538 None
2539 } else {
2540 Some(ChatId::new(chat_id))
2541 };
2542
2543 block_on(get_securejoin_qr_svg(ctx, chat_id))
2544 .unwrap_or_else(|_| "".to_string())
2545 .strdup()
2546}
2547
2548#[no_mangle]
2549pub unsafe extern "C" fn dc_join_securejoin(
2550 context: *mut dc_context_t,
2551 qr: *const libc::c_char,
2552) -> u32 {
2553 if context.is_null() || qr.is_null() {
2554 eprintln!("ignoring careless call to dc_join_securejoin()");
2555 return 0;
2556 }
2557 let ctx = &*context;
2558
2559 block_on(async move {
2560 securejoin::join_securejoin(ctx, &to_string_lossy(qr))
2561 .await
2562 .map(|chatid| chatid.to_u32())
2563 .context("failed dc_join_securejoin() call")
2564 .log_err(ctx)
2565 .unwrap_or_default()
2566 })
2567}
2568
2569#[no_mangle]
2570pub unsafe extern "C" fn dc_send_locations_to_chat(
2571 context: *mut dc_context_t,
2572 chat_id: u32,
2573 seconds: libc::c_int,
2574) {
2575 if context.is_null() || chat_id <= constants::DC_CHAT_ID_LAST_SPECIAL.to_u32() || seconds < 0 {
2576 eprintln!("ignoring careless call to dc_send_locations_to_chat()");
2577 return;
2578 }
2579 let ctx = &*context;
2580
2581 block_on(location::send_locations_to_chat(
2582 ctx,
2583 ChatId::new(chat_id),
2584 seconds as i64,
2585 ))
2586 .context("Failed dc_send_locations_to_chat()")
2587 .log_err(ctx)
2588 .ok();
2589}
2590
2591#[no_mangle]
2592pub unsafe extern "C" fn dc_is_sending_locations_to_chat(
2593 context: *mut dc_context_t,
2594 chat_id: u32,
2595) -> libc::c_int {
2596 if context.is_null() {
2597 eprintln!("ignoring careless call to dc_is_sending_locations_to_chat()");
2598 return 0;
2599 }
2600 let ctx = &*context;
2601 let chat_id = if chat_id == 0 {
2602 None
2603 } else {
2604 Some(ChatId::new(chat_id))
2605 };
2606
2607 block_on(location::is_sending_locations_to_chat(ctx, chat_id))
2608 .unwrap_or_log_default(ctx, "Failed dc_is_sending_locations_to_chat()") as libc::c_int
2609}
2610
2611#[no_mangle]
2612pub unsafe extern "C" fn dc_set_location(
2613 context: *mut dc_context_t,
2614 latitude: libc::c_double,
2615 longitude: libc::c_double,
2616 accuracy: libc::c_double,
2617) -> libc::c_int {
2618 if context.is_null() {
2619 eprintln!("ignoring careless call to dc_set_location()");
2620 return 0;
2621 }
2622 let ctx = &*context;
2623
2624 block_on(async move {
2625 location::set(ctx, latitude, longitude, accuracy)
2626 .await
2627 .log_err(ctx)
2628 .unwrap_or_default()
2629 }) as libc::c_int
2630}
2631
2632#[no_mangle]
2633pub unsafe extern "C" fn dc_get_locations(
2634 context: *mut dc_context_t,
2635 chat_id: u32,
2636 contact_id: u32,
2637 timestamp_begin: i64,
2638 timestamp_end: i64,
2639) -> *mut dc_array::dc_array_t {
2640 if context.is_null() {
2641 eprintln!("ignoring careless call to dc_get_locations()");
2642 return ptr::null_mut();
2643 }
2644 let ctx = &*context;
2645 let chat_id = if chat_id == 0 {
2646 None
2647 } else {
2648 Some(ChatId::new(chat_id))
2649 };
2650 let contact_id = if contact_id == 0 {
2651 None
2652 } else {
2653 Some(contact_id)
2654 };
2655
2656 block_on(async move {
2657 let res = location::get_range(ctx, chat_id, contact_id, timestamp_begin, timestamp_end)
2658 .await
2659 .unwrap_or_log_default(ctx, "Failed get_locations");
2660 Box::into_raw(Box::new(dc_array_t::from(res)))
2661 })
2662}
2663
2664#[no_mangle]
2665pub unsafe extern "C" fn dc_delete_all_locations(context: *mut dc_context_t) {
2666 if context.is_null() {
2667 eprintln!("ignoring careless call to dc_delete_all_locations()");
2668 return;
2669 }
2670 let ctx = &*context;
2671
2672 block_on(async move {
2673 location::delete_all(ctx)
2674 .await
2675 .context("Failed to delete locations")
2676 .log_err(ctx)
2677 .ok()
2678 });
2679}
2680
2681#[no_mangle]
2682pub unsafe extern "C" fn dc_create_qr_svg(payload: *const libc::c_char) -> *mut libc::c_char {
2683 if payload.is_null() {
2684 eprintln!("ignoring careless call to dc_create_qr_svg()");
2685 return "".strdup();
2686 }
2687
2688 create_qr_svg(&to_string_lossy(payload))
2689 .unwrap_or_else(|_| "".to_string())
2690 .strdup()
2691}
2692
2693#[no_mangle]
2694pub unsafe extern "C" fn dc_get_last_error(context: *mut dc_context_t) -> *mut libc::c_char {
2695 if context.is_null() {
2696 eprintln!("ignoring careless call to dc_get_last_error()");
2697 return "".strdup();
2698 }
2699 let ctx = &*context;
2700 ctx.get_last_error().strdup()
2701}
2702
2703pub type dc_array_t = dc_array::dc_array_t;
2706
2707#[no_mangle]
2708pub unsafe extern "C" fn dc_array_unref(a: *mut dc_array::dc_array_t) {
2709 if a.is_null() {
2710 eprintln!("ignoring careless call to dc_array_unref()");
2711 return;
2712 }
2713
2714 drop(Box::from_raw(a));
2715}
2716
2717#[no_mangle]
2718pub unsafe extern "C" fn dc_array_get_cnt(array: *const dc_array_t) -> libc::size_t {
2719 if array.is_null() {
2720 eprintln!("ignoring careless call to dc_array_get_cnt()");
2721 return 0;
2722 }
2723
2724 (*array).len()
2725}
2726#[no_mangle]
2727pub unsafe extern "C" fn dc_array_get_id(array: *const dc_array_t, index: libc::size_t) -> u32 {
2728 if array.is_null() {
2729 eprintln!("ignoring careless call to dc_array_get_id()");
2730 return 0;
2731 }
2732
2733 (*array).get_id(index)
2734}
2735#[no_mangle]
2736pub unsafe extern "C" fn dc_array_get_latitude(
2737 array: *const dc_array_t,
2738 index: libc::size_t,
2739) -> libc::c_double {
2740 if array.is_null() {
2741 eprintln!("ignoring careless call to dc_array_get_latitude()");
2742 return 0.0;
2743 }
2744
2745 (*array).get_location(index).latitude
2746}
2747#[no_mangle]
2748pub unsafe extern "C" fn dc_array_get_longitude(
2749 array: *const dc_array_t,
2750 index: libc::size_t,
2751) -> libc::c_double {
2752 if array.is_null() {
2753 eprintln!("ignoring careless call to dc_array_get_longitude()");
2754 return 0.0;
2755 }
2756
2757 (*array).get_location(index).longitude
2758}
2759#[no_mangle]
2760pub unsafe extern "C" fn dc_array_get_accuracy(
2761 array: *const dc_array_t,
2762 index: libc::size_t,
2763) -> libc::c_double {
2764 if array.is_null() {
2765 eprintln!("ignoring careless call to dc_array_get_accuracy()");
2766 return 0.0;
2767 }
2768
2769 (*array).get_location(index).accuracy
2770}
2771#[no_mangle]
2772pub unsafe extern "C" fn dc_array_get_timestamp(
2773 array: *const dc_array_t,
2774 index: libc::size_t,
2775) -> i64 {
2776 if array.is_null() {
2777 eprintln!("ignoring careless call to dc_array_get_timestamp()");
2778 return 0;
2779 }
2780
2781 (*array).get_timestamp(index).unwrap_or_default()
2782}
2783#[no_mangle]
2784pub unsafe extern "C" fn dc_array_get_chat_id(
2785 array: *const dc_array_t,
2786 index: libc::size_t,
2787) -> libc::c_uint {
2788 if array.is_null() {
2789 eprintln!("ignoring careless call to dc_array_get_chat_id()");
2790 return 0;
2791 }
2792 (*array).get_location(index).chat_id.to_u32()
2793}
2794#[no_mangle]
2795pub unsafe extern "C" fn dc_array_get_contact_id(
2796 array: *const dc_array_t,
2797 index: libc::size_t,
2798) -> libc::c_uint {
2799 if array.is_null() {
2800 eprintln!("ignoring careless call to dc_array_get_contact_id()");
2801 return 0;
2802 }
2803
2804 (*array).get_location(index).contact_id.to_u32()
2805}
2806#[no_mangle]
2807pub unsafe extern "C" fn dc_array_get_msg_id(
2808 array: *const dc_array_t,
2809 index: libc::size_t,
2810) -> libc::c_uint {
2811 if array.is_null() {
2812 eprintln!("ignoring careless call to dc_array_get_msg_id()");
2813 return 0;
2814 }
2815
2816 (*array).get_location(index).msg_id
2817}
2818#[no_mangle]
2819pub unsafe extern "C" fn dc_array_get_marker(
2820 array: *const dc_array_t,
2821 index: libc::size_t,
2822) -> *mut libc::c_char {
2823 if array.is_null() {
2824 eprintln!("ignoring careless call to dc_array_get_marker()");
2825 return std::ptr::null_mut(); }
2827
2828 if let Some(s) = (*array).get_marker(index) {
2829 s.strdup()
2830 } else {
2831 std::ptr::null_mut()
2832 }
2833}
2834
2835#[no_mangle]
2836pub unsafe extern "C" fn dc_array_search_id(
2837 array: *const dc_array_t,
2838 needle: libc::c_uint,
2839 ret_index: *mut libc::size_t,
2840) -> libc::c_int {
2841 if array.is_null() {
2842 eprintln!("ignoring careless call to dc_array_search_id()");
2843 return 0;
2844 }
2845
2846 if let Some(i) = (*array).search_id(needle) {
2847 if !ret_index.is_null() {
2848 *ret_index = i
2849 }
2850 1
2851 } else {
2852 0
2853 }
2854}
2855
2856#[no_mangle]
2861pub unsafe fn dc_array_is_independent(
2862 array: *const dc_array_t,
2863 index: libc::size_t,
2864) -> libc::c_int {
2865 if array.is_null() {
2866 eprintln!("ignoring careless call to dc_array_is_independent()");
2867 return 0;
2868 }
2869
2870 (*array).get_location(index).independent as libc::c_int
2871}
2872
2873pub struct ChatlistWrapper {
2883 context: *const dc_context_t,
2884 list: chatlist::Chatlist,
2885}
2886
2887pub type dc_chatlist_t = ChatlistWrapper;
2888
2889#[no_mangle]
2890pub unsafe extern "C" fn dc_chatlist_unref(chatlist: *mut dc_chatlist_t) {
2891 if chatlist.is_null() {
2892 eprintln!("ignoring careless call to dc_chatlist_unref()");
2893 return;
2894 }
2895 drop(Box::from_raw(chatlist));
2896}
2897
2898#[no_mangle]
2899pub unsafe extern "C" fn dc_chatlist_get_cnt(chatlist: *mut dc_chatlist_t) -> libc::size_t {
2900 if chatlist.is_null() {
2901 eprintln!("ignoring careless call to dc_chatlist_get_cnt()");
2902 return 0;
2903 }
2904 let ffi_list = &*chatlist;
2905 ffi_list.list.len() as libc::size_t
2906}
2907
2908#[no_mangle]
2909pub unsafe extern "C" fn dc_chatlist_get_chat_id(
2910 chatlist: *mut dc_chatlist_t,
2911 index: libc::size_t,
2912) -> u32 {
2913 if chatlist.is_null() {
2914 eprintln!("ignoring careless call to dc_chatlist_get_chat_id()");
2915 return 0;
2916 }
2917 let ffi_list = &*chatlist;
2918 let ctx = &*ffi_list.context;
2919 match ffi_list.list.get_chat_id(index) {
2920 Ok(chat_id) => chat_id.to_u32(),
2921 Err(err) => {
2922 warn!(ctx, "get_chat_id failed: {err:#}");
2923 0
2924 }
2925 }
2926}
2927
2928#[no_mangle]
2929pub unsafe extern "C" fn dc_chatlist_get_msg_id(
2930 chatlist: *mut dc_chatlist_t,
2931 index: libc::size_t,
2932) -> u32 {
2933 if chatlist.is_null() {
2934 eprintln!("ignoring careless call to dc_chatlist_get_msg_id()");
2935 return 0;
2936 }
2937 let ffi_list = &*chatlist;
2938 let ctx = &*ffi_list.context;
2939 match ffi_list.list.get_msg_id(index) {
2940 Ok(msg_id) => msg_id.map_or(0, |msg_id| msg_id.to_u32()),
2941 Err(err) => {
2942 warn!(ctx, "get_msg_id failed: {err:#}");
2943 0
2944 }
2945 }
2946}
2947
2948#[no_mangle]
2949pub unsafe extern "C" fn dc_chatlist_get_summary(
2950 chatlist: *mut dc_chatlist_t,
2951 index: libc::size_t,
2952 chat: *mut dc_chat_t,
2953) -> *mut dc_lot_t {
2954 if chatlist.is_null() {
2955 eprintln!("ignoring careless call to dc_chatlist_get_summary()");
2956 return ptr::null_mut();
2957 }
2958 let maybe_chat = if chat.is_null() {
2959 None
2960 } else {
2961 let ffi_chat = &*chat;
2962 Some(&ffi_chat.chat)
2963 };
2964 let ffi_list = &*chatlist;
2965 let ctx = &*ffi_list.context;
2966
2967 block_on(async move {
2968 let summary = ffi_list
2969 .list
2970 .get_summary(ctx, index, maybe_chat)
2971 .await
2972 .context("get_summary failed")
2973 .log_err(ctx)
2974 .unwrap_or_default();
2975 Box::into_raw(Box::new(summary.into()))
2976 })
2977}
2978
2979#[no_mangle]
2980pub unsafe extern "C" fn dc_chatlist_get_summary2(
2981 context: *mut dc_context_t,
2982 chat_id: u32,
2983 msg_id: u32,
2984) -> *mut dc_lot_t {
2985 if context.is_null() {
2986 eprintln!("ignoring careless call to dc_chatlist_get_summary2()");
2987 return ptr::null_mut();
2988 }
2989 let ctx = &*context;
2990 let msg_id = if msg_id == 0 {
2991 None
2992 } else {
2993 Some(MsgId::new(msg_id))
2994 };
2995 let summary = block_on(Chatlist::get_summary2(
2996 ctx,
2997 ChatId::new(chat_id),
2998 msg_id,
2999 None,
3000 ))
3001 .context("get_summary2 failed")
3002 .log_err(ctx)
3003 .unwrap_or_default();
3004 Box::into_raw(Box::new(summary.into()))
3005}
3006
3007#[no_mangle]
3008pub unsafe extern "C" fn dc_chatlist_get_context(
3009 chatlist: *mut dc_chatlist_t,
3010) -> *const dc_context_t {
3011 if chatlist.is_null() {
3012 eprintln!("ignoring careless call to dc_chatlist_get_context()");
3013 return ptr::null_mut();
3014 }
3015 let ffi_list = &*chatlist;
3016 ffi_list.context
3017}
3018
3019pub struct ChatWrapper {
3029 context: Context,
3030 chat: chat::Chat,
3031}
3032
3033pub type dc_chat_t = ChatWrapper;
3034
3035#[no_mangle]
3036pub unsafe extern "C" fn dc_chat_unref(chat: *mut dc_chat_t) {
3037 if chat.is_null() {
3038 eprintln!("ignoring careless call to dc_chat_unref()");
3039 return;
3040 }
3041
3042 drop(Box::from_raw(chat));
3043}
3044
3045#[no_mangle]
3046pub unsafe extern "C" fn dc_chat_get_id(chat: *mut dc_chat_t) -> u32 {
3047 if chat.is_null() {
3048 eprintln!("ignoring careless call to dc_chat_get_id()");
3049 return 0;
3050 }
3051 let ffi_chat = &*chat;
3052 ffi_chat.chat.get_id().to_u32()
3053}
3054
3055#[no_mangle]
3056pub unsafe extern "C" fn dc_chat_get_type(chat: *mut dc_chat_t) -> libc::c_int {
3057 if chat.is_null() {
3058 eprintln!("ignoring careless call to dc_chat_get_type()");
3059 return 0;
3060 }
3061 let ffi_chat = &*chat;
3062 ffi_chat.chat.get_type() as libc::c_int
3063}
3064
3065#[no_mangle]
3066pub unsafe extern "C" fn dc_chat_get_name(chat: *mut dc_chat_t) -> *mut libc::c_char {
3067 if chat.is_null() {
3068 eprintln!("ignoring careless call to dc_chat_get_name()");
3069 return "".strdup();
3070 }
3071 let ffi_chat = &*chat;
3072 ffi_chat.chat.get_name().strdup()
3073}
3074
3075#[no_mangle]
3076pub unsafe extern "C" fn dc_chat_get_mailinglist_addr(chat: *mut dc_chat_t) -> *mut libc::c_char {
3077 if chat.is_null() {
3078 eprintln!("ignoring careless call to dc_chat_get_mailinglist_addr()");
3079 return "".strdup();
3080 }
3081 let ffi_chat = &*chat;
3082 ffi_chat
3083 .chat
3084 .get_mailinglist_addr()
3085 .unwrap_or_default()
3086 .strdup()
3087}
3088
3089#[no_mangle]
3090pub unsafe extern "C" fn dc_chat_get_profile_image(chat: *mut dc_chat_t) -> *mut libc::c_char {
3091 if chat.is_null() {
3092 eprintln!("ignoring careless call to dc_chat_get_profile_image()");
3093 return ptr::null_mut(); }
3095 let ffi_chat = &*chat;
3096
3097 block_on(async move {
3098 match ffi_chat.chat.get_profile_image(&ffi_chat.context).await {
3099 Ok(Some(p)) => p.to_string_lossy().strdup(),
3100 Ok(None) => ptr::null_mut(),
3101 Err(err) => {
3102 error!(ffi_chat.context, "failed to get profile image: {err:#}");
3103 ptr::null_mut()
3104 }
3105 }
3106 })
3107}
3108
3109#[no_mangle]
3110pub unsafe extern "C" fn dc_chat_get_color(chat: *mut dc_chat_t) -> u32 {
3111 if chat.is_null() {
3112 eprintln!("ignoring careless call to dc_chat_get_color()");
3113 return 0;
3114 }
3115 let ffi_chat = &*chat;
3116
3117 block_on(ffi_chat.chat.get_color(&ffi_chat.context))
3118 .unwrap_or_log_default(&ffi_chat.context, "Failed get_color")
3119}
3120
3121#[no_mangle]
3122pub unsafe extern "C" fn dc_chat_get_visibility(chat: *mut dc_chat_t) -> libc::c_int {
3123 if chat.is_null() {
3124 eprintln!("ignoring careless call to dc_chat_get_visibility()");
3125 return 0;
3126 }
3127 let ffi_chat = &*chat;
3128 match ffi_chat.chat.visibility {
3129 ChatVisibility::Normal => 0,
3130 ChatVisibility::Archived => 1,
3131 ChatVisibility::Pinned => 2,
3132 }
3133}
3134
3135#[no_mangle]
3136pub unsafe extern "C" fn dc_chat_is_contact_request(chat: *mut dc_chat_t) -> libc::c_int {
3137 if chat.is_null() {
3138 eprintln!("ignoring careless call to dc_chat_is_contact_request()");
3139 return 0;
3140 }
3141 let ffi_chat = &*chat;
3142 ffi_chat.chat.is_contact_request() as libc::c_int
3143}
3144
3145#[no_mangle]
3146pub unsafe extern "C" fn dc_chat_is_unpromoted(chat: *mut dc_chat_t) -> libc::c_int {
3147 if chat.is_null() {
3148 eprintln!("ignoring careless call to dc_chat_is_unpromoted()");
3149 return 0;
3150 }
3151 let ffi_chat = &*chat;
3152 ffi_chat.chat.is_unpromoted() as libc::c_int
3153}
3154
3155#[no_mangle]
3156pub unsafe extern "C" fn dc_chat_is_self_talk(chat: *mut dc_chat_t) -> libc::c_int {
3157 if chat.is_null() {
3158 eprintln!("ignoring careless call to dc_chat_is_self_talk()");
3159 return 0;
3160 }
3161 let ffi_chat = &*chat;
3162 ffi_chat.chat.is_self_talk() as libc::c_int
3163}
3164
3165#[no_mangle]
3166pub unsafe extern "C" fn dc_chat_is_device_talk(chat: *mut dc_chat_t) -> libc::c_int {
3167 if chat.is_null() {
3168 eprintln!("ignoring careless call to dc_chat_is_device_talk()");
3169 return 0;
3170 }
3171 let ffi_chat = &*chat;
3172 ffi_chat.chat.is_device_talk() as libc::c_int
3173}
3174
3175#[no_mangle]
3176pub unsafe extern "C" fn dc_chat_can_send(chat: *mut dc_chat_t) -> libc::c_int {
3177 if chat.is_null() {
3178 eprintln!("ignoring careless call to dc_chat_can_send()");
3179 return 0;
3180 }
3181 let ffi_chat = &*chat;
3182 block_on(ffi_chat.chat.can_send(&ffi_chat.context))
3183 .context("can_send failed")
3184 .log_err(&ffi_chat.context)
3185 .unwrap_or_default() as libc::c_int
3186}
3187
3188#[no_mangle]
3189pub unsafe extern "C" fn dc_chat_is_protected(chat: *mut dc_chat_t) -> libc::c_int {
3190 if chat.is_null() {
3191 eprintln!("ignoring careless call to dc_chat_is_protected()");
3192 return 0;
3193 }
3194 let ffi_chat = &*chat;
3195 ffi_chat.chat.is_protected() as libc::c_int
3196}
3197
3198#[no_mangle]
3199pub unsafe extern "C" fn dc_chat_is_protection_broken(chat: *mut dc_chat_t) -> libc::c_int {
3200 if chat.is_null() {
3201 eprintln!("ignoring careless call to dc_chat_is_protection_broken()");
3202 return 0;
3203 }
3204 let ffi_chat = &*chat;
3205 ffi_chat.chat.is_protection_broken() as libc::c_int
3206}
3207
3208#[no_mangle]
3209pub unsafe extern "C" fn dc_chat_is_sending_locations(chat: *mut dc_chat_t) -> libc::c_int {
3210 if chat.is_null() {
3211 eprintln!("ignoring careless call to dc_chat_is_sending_locations()");
3212 return 0;
3213 }
3214 let ffi_chat = &*chat;
3215 ffi_chat.chat.is_sending_locations() as libc::c_int
3216}
3217
3218#[no_mangle]
3219pub unsafe extern "C" fn dc_chat_is_muted(chat: *mut dc_chat_t) -> libc::c_int {
3220 if chat.is_null() {
3221 eprintln!("ignoring careless call to dc_chat_is_muted()");
3222 return 0;
3223 }
3224 let ffi_chat = &*chat;
3225 ffi_chat.chat.is_muted() as libc::c_int
3226}
3227
3228#[no_mangle]
3229pub unsafe extern "C" fn dc_chat_get_remaining_mute_duration(chat: *mut dc_chat_t) -> i64 {
3230 if chat.is_null() {
3231 eprintln!("ignoring careless call to dc_chat_get_remaining_mute_duration()");
3232 return 0;
3233 }
3234 let ffi_chat = &*chat;
3235 if !ffi_chat.chat.is_muted() {
3236 return 0;
3237 }
3238 match ffi_chat.chat.mute_duration {
3240 MuteDuration::NotMuted => 0,
3241 MuteDuration::Forever => -1,
3242 MuteDuration::Until(when) => when
3243 .duration_since(SystemTime::now())
3244 .map(|d| d.as_secs() as i64)
3245 .unwrap_or(0),
3246 }
3247}
3248
3249#[no_mangle]
3250pub unsafe extern "C" fn dc_chat_get_info_json(
3251 context: *mut dc_context_t,
3252 chat_id: u32,
3253) -> *mut libc::c_char {
3254 if context.is_null() {
3255 eprintln!("ignoring careless call to dc_chat_get_info_json()");
3256 return "".strdup();
3257 }
3258 let ctx = &*context;
3259
3260 block_on(async move {
3261 let chat = match chat::Chat::load_from_db(ctx, ChatId::new(chat_id)).await {
3262 Ok(chat) => chat,
3263 Err(err) => {
3264 error!(ctx, "dc_get_chat_info_json() failed to load chat: {err:#}");
3265 return "".strdup();
3266 }
3267 };
3268 let info = match chat.get_info(ctx).await {
3269 Ok(info) => info,
3270 Err(err) => {
3271 error!(
3272 ctx,
3273 "dc_get_chat_info_json() failed to get chat info: {err:#}"
3274 );
3275 return "".strdup();
3276 }
3277 };
3278 serde_json::to_string(&info)
3279 .unwrap_or_log_default(ctx, "dc_get_chat_info_json() failed to serialise to json")
3280 .strdup()
3281 })
3282}
3283
3284pub struct MessageWrapper {
3294 context: *const dc_context_t,
3295 message: message::Message,
3296}
3297
3298pub type dc_msg_t = MessageWrapper;
3299
3300#[no_mangle]
3301pub unsafe extern "C" fn dc_msg_new(
3302 context: *mut dc_context_t,
3303 viewtype: libc::c_int,
3304) -> *mut dc_msg_t {
3305 if context.is_null() {
3306 eprintln!("ignoring careless call to dc_msg_new()");
3307 return ptr::null_mut();
3308 }
3309 let context = &*context;
3310 let viewtype = from_prim(viewtype).expect(&format!("invalid viewtype = {viewtype}"));
3311 let msg = MessageWrapper {
3312 context,
3313 message: message::Message::new(viewtype),
3314 };
3315 Box::into_raw(Box::new(msg))
3316}
3317
3318#[no_mangle]
3319pub unsafe extern "C" fn dc_msg_unref(msg: *mut dc_msg_t) {
3320 if msg.is_null() {
3321 eprintln!("ignoring careless call to dc_msg_unref()");
3322 return;
3323 }
3324
3325 drop(Box::from_raw(msg));
3326}
3327
3328#[no_mangle]
3329pub unsafe extern "C" fn dc_msg_get_id(msg: *mut dc_msg_t) -> u32 {
3330 if msg.is_null() {
3331 eprintln!("ignoring careless call to dc_msg_get_id()");
3332 return 0;
3333 }
3334 let ffi_msg = &*msg;
3335 ffi_msg.message.get_id().to_u32()
3336}
3337
3338#[no_mangle]
3339pub unsafe extern "C" fn dc_msg_get_from_id(msg: *mut dc_msg_t) -> u32 {
3340 if msg.is_null() {
3341 eprintln!("ignoring careless call to dc_msg_get_from_id()");
3342 return 0;
3343 }
3344 let ffi_msg = &*msg;
3345 ffi_msg.message.get_from_id().to_u32()
3346}
3347
3348#[no_mangle]
3349pub unsafe extern "C" fn dc_msg_get_chat_id(msg: *mut dc_msg_t) -> u32 {
3350 if msg.is_null() {
3351 eprintln!("ignoring careless call to dc_msg_get_chat_id()");
3352 return 0;
3353 }
3354 let ffi_msg = &*msg;
3355 ffi_msg.message.get_chat_id().to_u32()
3356}
3357
3358#[no_mangle]
3359pub unsafe extern "C" fn dc_msg_get_viewtype(msg: *mut dc_msg_t) -> libc::c_int {
3360 if msg.is_null() {
3361 eprintln!("ignoring careless call to dc_msg_get_viewtype()");
3362 return 0;
3363 }
3364 let ffi_msg = &*msg;
3365 ffi_msg
3366 .message
3367 .get_viewtype()
3368 .to_i64()
3369 .expect("impossible: Viewtype -> i64 conversion failed") as libc::c_int
3370}
3371
3372#[no_mangle]
3373pub unsafe extern "C" fn dc_msg_get_state(msg: *mut dc_msg_t) -> libc::c_int {
3374 if msg.is_null() {
3375 eprintln!("ignoring careless call to dc_msg_get_state()");
3376 return 0;
3377 }
3378 let ffi_msg = &*msg;
3379 ffi_msg.message.get_state() as libc::c_int
3380}
3381
3382#[no_mangle]
3383pub unsafe extern "C" fn dc_msg_get_download_state(msg: *mut dc_msg_t) -> libc::c_int {
3384 if msg.is_null() {
3385 eprintln!("ignoring careless call to dc_msg_get_download_state()");
3386 return 0;
3387 }
3388 let ffi_msg = &*msg;
3389 ffi_msg.message.download_state() as libc::c_int
3390}
3391
3392#[no_mangle]
3393pub unsafe extern "C" fn dc_msg_get_timestamp(msg: *mut dc_msg_t) -> i64 {
3394 if msg.is_null() {
3395 eprintln!("ignoring careless call to dc_msg_get_received_timestamp()");
3396 return 0;
3397 }
3398 let ffi_msg = &*msg;
3399 ffi_msg.message.get_timestamp()
3400}
3401
3402#[no_mangle]
3403pub unsafe extern "C" fn dc_msg_get_received_timestamp(msg: *mut dc_msg_t) -> i64 {
3404 if msg.is_null() {
3405 eprintln!("ignoring careless call to dc_msg_get_received_timestamp()");
3406 return 0;
3407 }
3408 let ffi_msg = &*msg;
3409 ffi_msg.message.get_received_timestamp()
3410}
3411
3412#[no_mangle]
3413pub unsafe extern "C" fn dc_msg_get_sort_timestamp(msg: *mut dc_msg_t) -> i64 {
3414 if msg.is_null() {
3415 eprintln!("ignoring careless call to dc_msg_get_sort_timestamp()");
3416 return 0;
3417 }
3418 let ffi_msg = &*msg;
3419 ffi_msg.message.get_sort_timestamp()
3420}
3421
3422#[no_mangle]
3423pub unsafe extern "C" fn dc_msg_get_text(msg: *mut dc_msg_t) -> *mut libc::c_char {
3424 if msg.is_null() {
3425 eprintln!("ignoring careless call to dc_msg_get_text()");
3426 return "".strdup();
3427 }
3428 let ffi_msg = &*msg;
3429 ffi_msg.message.get_text().strdup()
3430}
3431
3432#[no_mangle]
3433pub unsafe extern "C" fn dc_msg_get_subject(msg: *mut dc_msg_t) -> *mut libc::c_char {
3434 if msg.is_null() {
3435 eprintln!("ignoring careless call to dc_msg_get_subject()");
3436 return "".strdup();
3437 }
3438 let ffi_msg = &*msg;
3439 ffi_msg.message.get_subject().strdup()
3440}
3441
3442#[no_mangle]
3443pub unsafe extern "C" fn dc_msg_get_file(msg: *mut dc_msg_t) -> *mut libc::c_char {
3444 if msg.is_null() {
3445 eprintln!("ignoring careless call to dc_msg_get_file()");
3446 return "".strdup();
3447 }
3448 let ffi_msg = &*msg;
3449 let ctx = &*ffi_msg.context;
3450 ffi_msg
3451 .message
3452 .get_file(ctx)
3453 .map(|p| p.to_string_lossy().strdup())
3454 .unwrap_or_else(|| "".strdup())
3455}
3456
3457#[no_mangle]
3458pub unsafe extern "C" fn dc_msg_save_file(
3459 msg: *mut dc_msg_t,
3460 path: *const libc::c_char,
3461) -> libc::c_int {
3462 if msg.is_null() || path.is_null() {
3463 eprintln!("ignoring careless call to dc_msg_save_file()");
3464 return 0;
3465 }
3466 let ffi_msg = &*msg;
3467 let ctx = &*ffi_msg.context;
3468 let path = to_string_lossy(path);
3469 let r = block_on(
3470 ffi_msg
3471 .message
3472 .save_file(ctx, &std::path::PathBuf::from(path)),
3473 );
3474 match r {
3475 Ok(()) => 1,
3476 Err(_) => {
3477 r.context("Failed to save file from message")
3478 .log_err(ctx)
3479 .unwrap_or_default();
3480 0
3481 }
3482 }
3483}
3484
3485#[no_mangle]
3486pub unsafe extern "C" fn dc_msg_get_filename(msg: *mut dc_msg_t) -> *mut libc::c_char {
3487 if msg.is_null() {
3488 eprintln!("ignoring careless call to dc_msg_get_filename()");
3489 return "".strdup();
3490 }
3491 let ffi_msg = &*msg;
3492 ffi_msg.message.get_filename().unwrap_or_default().strdup()
3493}
3494
3495#[no_mangle]
3496pub unsafe extern "C" fn dc_msg_get_webxdc_blob(
3497 msg: *mut dc_msg_t,
3498 filename: *const libc::c_char,
3499 ret_bytes: *mut libc::size_t,
3500) -> *mut libc::c_char {
3501 if msg.is_null() || filename.is_null() || ret_bytes.is_null() {
3502 eprintln!("ignoring careless call to dc_msg_get_webxdc_blob()");
3503 return ptr::null_mut();
3504 }
3505 let ffi_msg = &*msg;
3506 let ctx = &*ffi_msg.context;
3507 let blob = block_on(async move {
3508 ffi_msg
3509 .message
3510 .get_webxdc_blob(ctx, &to_string_lossy(filename))
3511 .await
3512 });
3513 match blob {
3514 Ok(blob) => {
3515 *ret_bytes = blob.len();
3516 let ptr = libc::malloc(*ret_bytes);
3517 libc::memcpy(ptr, blob.as_ptr() as *mut libc::c_void, *ret_bytes);
3518 ptr as *mut libc::c_char
3519 }
3520 Err(err) => {
3521 eprintln!("failed read blob from archive: {err}");
3522 ptr::null_mut()
3523 }
3524 }
3525}
3526
3527#[no_mangle]
3528pub unsafe extern "C" fn dc_msg_get_webxdc_info(msg: *mut dc_msg_t) -> *mut libc::c_char {
3529 if msg.is_null() {
3530 eprintln!("ignoring careless call to dc_msg_get_webxdc_info()");
3531 return "".strdup();
3532 }
3533 let ffi_msg = &*msg;
3534 let ctx = &*ffi_msg.context;
3535
3536 block_on(async move {
3537 let info = match ffi_msg.message.get_webxdc_info(ctx).await {
3538 Ok(info) => info,
3539 Err(err) => {
3540 error!(ctx, "dc_msg_get_webxdc_info() failed to get info: {err:#}");
3541 return "".strdup();
3542 }
3543 };
3544 serde_json::to_string(&info)
3545 .unwrap_or_log_default(ctx, "dc_msg_get_webxdc_info() failed to serialise to json")
3546 .strdup()
3547 })
3548}
3549
3550#[no_mangle]
3551pub unsafe extern "C" fn dc_msg_get_filemime(msg: *mut dc_msg_t) -> *mut libc::c_char {
3552 if msg.is_null() {
3553 eprintln!("ignoring careless call to dc_msg_get_filemime()");
3554 return "".strdup();
3555 }
3556 let ffi_msg = &*msg;
3557 if let Some(x) = ffi_msg.message.get_filemime() {
3558 x.strdup()
3559 } else {
3560 "".strdup()
3561 }
3562}
3563
3564#[no_mangle]
3565pub unsafe extern "C" fn dc_msg_get_filebytes(msg: *mut dc_msg_t) -> u64 {
3566 if msg.is_null() {
3567 eprintln!("ignoring careless call to dc_msg_get_filebytes()");
3568 return 0;
3569 }
3570 let ffi_msg = &*msg;
3571 let ctx = &*ffi_msg.context;
3572
3573 block_on(ffi_msg.message.get_filebytes(ctx))
3574 .unwrap_or_log_default(ctx, "Cannot get file size")
3575 .unwrap_or_default()
3576}
3577
3578#[no_mangle]
3579pub unsafe extern "C" fn dc_msg_get_width(msg: *mut dc_msg_t) -> libc::c_int {
3580 if msg.is_null() {
3581 eprintln!("ignoring careless call to dc_msg_get_width()");
3582 return 0;
3583 }
3584 let ffi_msg = &*msg;
3585 ffi_msg.message.get_width()
3586}
3587
3588#[no_mangle]
3589pub unsafe extern "C" fn dc_msg_get_height(msg: *mut dc_msg_t) -> libc::c_int {
3590 if msg.is_null() {
3591 eprintln!("ignoring careless call to dc_msg_get_height()");
3592 return 0;
3593 }
3594 let ffi_msg = &*msg;
3595 ffi_msg.message.get_height()
3596}
3597
3598#[no_mangle]
3599pub unsafe extern "C" fn dc_msg_get_duration(msg: *mut dc_msg_t) -> libc::c_int {
3600 if msg.is_null() {
3601 eprintln!("ignoring careless call to dc_msg_get_duration()");
3602 return 0;
3603 }
3604 let ffi_msg = &*msg;
3605 ffi_msg.message.get_duration()
3606}
3607
3608#[no_mangle]
3609pub unsafe extern "C" fn dc_msg_get_showpadlock(msg: *mut dc_msg_t) -> libc::c_int {
3610 if msg.is_null() {
3611 eprintln!("ignoring careless call to dc_msg_get_showpadlock()");
3612 return 0;
3613 }
3614 let ffi_msg = &*msg;
3615 ffi_msg.message.get_showpadlock() as libc::c_int
3616}
3617
3618#[no_mangle]
3619pub unsafe extern "C" fn dc_msg_is_bot(msg: *mut dc_msg_t) -> libc::c_int {
3620 if msg.is_null() {
3621 eprintln!("ignoring careless call to dc_msg_is_bot()");
3622 return 0;
3623 }
3624 let ffi_msg = &*msg;
3625 ffi_msg.message.is_bot() as libc::c_int
3626}
3627
3628#[no_mangle]
3629pub unsafe extern "C" fn dc_msg_get_ephemeral_timer(msg: *mut dc_msg_t) -> u32 {
3630 if msg.is_null() {
3631 eprintln!("ignoring careless call to dc_msg_get_ephemeral_timer()");
3632 return 0;
3633 }
3634 let ffi_msg = &*msg;
3635 ffi_msg.message.get_ephemeral_timer().to_u32()
3636}
3637
3638#[no_mangle]
3639pub unsafe extern "C" fn dc_msg_get_ephemeral_timestamp(msg: *mut dc_msg_t) -> i64 {
3640 if msg.is_null() {
3641 eprintln!("ignoring careless call to dc_msg_get_ephemeral_timer()");
3642 return 0;
3643 }
3644 let ffi_msg = &*msg;
3645 ffi_msg.message.get_ephemeral_timestamp()
3646}
3647
3648#[no_mangle]
3649pub unsafe extern "C" fn dc_msg_get_summary(
3650 msg: *mut dc_msg_t,
3651 chat: *mut dc_chat_t,
3652) -> *mut dc_lot_t {
3653 if msg.is_null() {
3654 eprintln!("ignoring careless call to dc_msg_get_summary()");
3655 return ptr::null_mut();
3656 }
3657 let maybe_chat = if chat.is_null() {
3658 None
3659 } else {
3660 let ffi_chat = &*chat;
3661 Some(&ffi_chat.chat)
3662 };
3663 let ffi_msg = &mut *msg;
3664 let ctx = &*ffi_msg.context;
3665
3666 let summary = block_on(ffi_msg.message.get_summary(ctx, maybe_chat))
3667 .context("dc_msg_get_summary failed")
3668 .log_err(ctx)
3669 .unwrap_or_default();
3670 Box::into_raw(Box::new(summary.into()))
3671}
3672
3673#[no_mangle]
3674pub unsafe extern "C" fn dc_msg_get_summarytext(
3675 msg: *mut dc_msg_t,
3676 approx_characters: libc::c_int,
3677) -> *mut libc::c_char {
3678 if msg.is_null() {
3679 eprintln!("ignoring careless call to dc_msg_get_summarytext()");
3680 return "".strdup();
3681 }
3682 let ffi_msg = &mut *msg;
3683 let ctx = &*ffi_msg.context;
3684
3685 let summary = block_on(ffi_msg.message.get_summary(ctx, None))
3686 .context("dc_msg_get_summarytext failed")
3687 .log_err(ctx)
3688 .unwrap_or_default();
3689 match usize::try_from(approx_characters) {
3690 Ok(chars) => summary.truncated_text(chars).strdup(),
3691 Err(_) => summary.text.strdup(),
3692 }
3693}
3694
3695#[no_mangle]
3696pub unsafe extern "C" fn dc_msg_get_override_sender_name(msg: *mut dc_msg_t) -> *mut libc::c_char {
3697 if msg.is_null() {
3698 eprintln!("ignoring careless call to dc_msg_get_override_sender_name()");
3699 return "".strdup();
3700 }
3701 let ffi_msg = &mut *msg;
3702
3703 ffi_msg.message.get_override_sender_name().strdup()
3704}
3705
3706#[no_mangle]
3707pub unsafe extern "C" fn dc_msg_has_deviating_timestamp(msg: *mut dc_msg_t) -> libc::c_int {
3708 if msg.is_null() {
3709 eprintln!("ignoring careless call to dc_msg_has_deviating_timestamp()");
3710 return 0;
3711 }
3712 let ffi_msg = &*msg;
3713 ffi_msg.message.has_deviating_timestamp().into()
3714}
3715
3716#[no_mangle]
3717pub unsafe extern "C" fn dc_msg_has_location(msg: *mut dc_msg_t) -> libc::c_int {
3718 if msg.is_null() {
3719 eprintln!("ignoring careless call to dc_msg_has_location()");
3720 return 0;
3721 }
3722 let ffi_msg = &*msg;
3723 ffi_msg.message.has_location() as libc::c_int
3724}
3725
3726#[no_mangle]
3727pub unsafe extern "C" fn dc_msg_is_sent(msg: *mut dc_msg_t) -> libc::c_int {
3728 if msg.is_null() {
3729 eprintln!("ignoring careless call to dc_msg_is_sent()");
3730 return 0;
3731 }
3732 let ffi_msg = &*msg;
3733 ffi_msg.message.is_sent().into()
3734}
3735
3736#[no_mangle]
3737pub unsafe extern "C" fn dc_msg_is_forwarded(msg: *mut dc_msg_t) -> libc::c_int {
3738 if msg.is_null() {
3739 eprintln!("ignoring careless call to dc_msg_is_forwarded()");
3740 return 0;
3741 }
3742 let ffi_msg = &*msg;
3743 ffi_msg.message.is_forwarded().into()
3744}
3745
3746#[no_mangle]
3747pub unsafe extern "C" fn dc_msg_is_edited(msg: *mut dc_msg_t) -> libc::c_int {
3748 if msg.is_null() {
3749 eprintln!("ignoring careless call to dc_msg_is_edited()");
3750 return 0;
3751 }
3752 let ffi_msg = &*msg;
3753 ffi_msg.message.is_edited().into()
3754}
3755
3756#[no_mangle]
3757pub unsafe extern "C" fn dc_msg_is_info(msg: *mut dc_msg_t) -> libc::c_int {
3758 if msg.is_null() {
3759 eprintln!("ignoring careless call to dc_msg_is_info()");
3760 return 0;
3761 }
3762 let ffi_msg = &*msg;
3763 ffi_msg.message.is_info().into()
3764}
3765
3766#[no_mangle]
3767pub unsafe extern "C" fn dc_msg_get_info_type(msg: *mut dc_msg_t) -> libc::c_int {
3768 if msg.is_null() {
3769 eprintln!("ignoring careless call to dc_msg_get_info_type()");
3770 return 0;
3771 }
3772 let ffi_msg = &*msg;
3773 ffi_msg.message.get_info_type() as libc::c_int
3774}
3775
3776#[no_mangle]
3777pub unsafe extern "C" fn dc_msg_get_info_contact_id(msg: *mut dc_msg_t) -> u32 {
3778 if msg.is_null() {
3779 eprintln!("ignoring careless call to dc_msg_get_info_contact_id()");
3780 return 0;
3781 }
3782 let ffi_msg = &*msg;
3783 let context = &*ffi_msg.context;
3784 block_on(ffi_msg.message.get_info_contact_id(context))
3785 .unwrap_or_default()
3786 .map(|id| id.to_u32())
3787 .unwrap_or_default()
3788}
3789
3790#[no_mangle]
3791pub unsafe extern "C" fn dc_msg_get_webxdc_href(msg: *mut dc_msg_t) -> *mut libc::c_char {
3792 if msg.is_null() {
3793 eprintln!("ignoring careless call to dc_msg_get_webxdc_href()");
3794 return "".strdup();
3795 }
3796
3797 let ffi_msg = &*msg;
3798 ffi_msg.message.get_webxdc_href().strdup()
3799}
3800
3801#[no_mangle]
3802pub unsafe extern "C" fn dc_msg_is_setupmessage(msg: *mut dc_msg_t) -> libc::c_int {
3803 if msg.is_null() {
3804 eprintln!("ignoring careless call to dc_msg_is_setupmessage()");
3805 return 0;
3806 }
3807 let ffi_msg = &*msg;
3808 ffi_msg.message.is_setupmessage().into()
3809}
3810
3811#[no_mangle]
3812pub unsafe extern "C" fn dc_msg_has_html(msg: *mut dc_msg_t) -> libc::c_int {
3813 if msg.is_null() {
3814 eprintln!("ignoring careless call to dc_msg_has_html()");
3815 return 0;
3816 }
3817 let ffi_msg = &*msg;
3818 ffi_msg.message.has_html().into()
3819}
3820
3821#[no_mangle]
3822pub unsafe extern "C" fn dc_msg_get_videochat_url(msg: *mut dc_msg_t) -> *mut libc::c_char {
3823 if msg.is_null() {
3824 eprintln!("ignoring careless call to dc_msg_get_videochat_url()");
3825 return "".strdup();
3826 }
3827 let ffi_msg = &*msg;
3828
3829 ffi_msg
3830 .message
3831 .get_videochat_url()
3832 .unwrap_or_default()
3833 .strdup()
3834}
3835
3836#[no_mangle]
3837pub unsafe extern "C" fn dc_msg_get_videochat_type(msg: *mut dc_msg_t) -> libc::c_int {
3838 if msg.is_null() {
3839 eprintln!("ignoring careless call to dc_msg_get_videochat_type()");
3840 return 0;
3841 }
3842 let ffi_msg = &*msg;
3843 ffi_msg.message.get_videochat_type().unwrap_or_default() as i32
3844}
3845
3846#[no_mangle]
3847pub unsafe extern "C" fn dc_msg_get_setupcodebegin(msg: *mut dc_msg_t) -> *mut libc::c_char {
3848 if msg.is_null() {
3849 eprintln!("ignoring careless call to dc_msg_get_setupcodebegin()");
3850 return "".strdup();
3851 }
3852 let ffi_msg = &*msg;
3853 let ctx = &*ffi_msg.context;
3854
3855 block_on(ffi_msg.message.get_setupcodebegin(ctx))
3856 .unwrap_or_default()
3857 .strdup()
3858}
3859
3860#[no_mangle]
3861pub unsafe extern "C" fn dc_msg_set_text(msg: *mut dc_msg_t, text: *const libc::c_char) {
3862 if msg.is_null() {
3863 eprintln!("ignoring careless call to dc_msg_set_text()");
3864 return;
3865 }
3866 let ffi_msg = &mut *msg;
3867 ffi_msg.message.set_text(to_string_lossy(text))
3868}
3869
3870#[no_mangle]
3871pub unsafe extern "C" fn dc_msg_set_html(msg: *mut dc_msg_t, html: *const libc::c_char) {
3872 if msg.is_null() {
3873 eprintln!("ignoring careless call to dc_msg_set_html()");
3874 return;
3875 }
3876 let ffi_msg = &mut *msg;
3877 ffi_msg.message.set_html(to_opt_string_lossy(html))
3878}
3879
3880#[no_mangle]
3881pub unsafe extern "C" fn dc_msg_set_subject(msg: *mut dc_msg_t, subject: *const libc::c_char) {
3882 if msg.is_null() {
3883 eprintln!("ignoring careless call to dc_msg_get_subject()");
3884 return;
3885 }
3886 let ffi_msg = &mut *msg;
3887 ffi_msg.message.set_subject(to_string_lossy(subject));
3888}
3889
3890#[no_mangle]
3891pub unsafe extern "C" fn dc_msg_set_override_sender_name(
3892 msg: *mut dc_msg_t,
3893 name: *const libc::c_char,
3894) {
3895 if msg.is_null() {
3896 eprintln!("ignoring careless call to dc_msg_set_override_sender_name()");
3897 return;
3898 }
3899 let ffi_msg = &mut *msg;
3900 ffi_msg
3901 .message
3902 .set_override_sender_name(to_opt_string_lossy(name))
3903}
3904
3905#[no_mangle]
3906pub unsafe extern "C" fn dc_msg_set_file_and_deduplicate(
3907 msg: *mut dc_msg_t,
3908 file: *const libc::c_char,
3909 name: *const libc::c_char,
3910 filemime: *const libc::c_char,
3911) {
3912 if msg.is_null() || file.is_null() {
3913 eprintln!("ignoring careless call to dc_msg_set_file_and_deduplicate()");
3914 return;
3915 }
3916 let ffi_msg = &mut *msg;
3917 let ctx = &*ffi_msg.context;
3918
3919 ffi_msg
3920 .message
3921 .set_file_and_deduplicate(
3922 ctx,
3923 as_path(file),
3924 to_opt_string_lossy(name).as_deref(),
3925 to_opt_string_lossy(filemime).as_deref(),
3926 )
3927 .context("Failed to set file")
3928 .log_err(&*ffi_msg.context)
3929 .ok();
3930}
3931
3932#[no_mangle]
3933pub unsafe extern "C" fn dc_msg_set_dimension(
3934 msg: *mut dc_msg_t,
3935 width: libc::c_int,
3936 height: libc::c_int,
3937) {
3938 if msg.is_null() {
3939 eprintln!("ignoring careless call to dc_msg_set_dimension()");
3940 return;
3941 }
3942 let ffi_msg = &mut *msg;
3943 ffi_msg.message.set_dimension(width, height)
3944}
3945
3946#[no_mangle]
3947pub unsafe extern "C" fn dc_msg_set_duration(msg: *mut dc_msg_t, duration: libc::c_int) {
3948 if msg.is_null() {
3949 eprintln!("ignoring careless call to dc_msg_set_duration()");
3950 return;
3951 }
3952 let ffi_msg = &mut *msg;
3953 ffi_msg.message.set_duration(duration)
3954}
3955
3956#[no_mangle]
3957pub unsafe extern "C" fn dc_msg_set_location(
3958 msg: *mut dc_msg_t,
3959 latitude: libc::c_double,
3960 longitude: libc::c_double,
3961) {
3962 if msg.is_null() {
3963 eprintln!("ignoring careless call to dc_msg_set_location()");
3964 return;
3965 }
3966 let ffi_msg = &mut *msg;
3967 ffi_msg.message.set_location(latitude, longitude)
3968}
3969
3970#[no_mangle]
3971pub unsafe extern "C" fn dc_msg_latefiling_mediasize(
3972 msg: *mut dc_msg_t,
3973 width: libc::c_int,
3974 height: libc::c_int,
3975 duration: libc::c_int,
3976) {
3977 if msg.is_null() {
3978 eprintln!("ignoring careless call to dc_msg_latefiling_mediasize()");
3979 return;
3980 }
3981 let ffi_msg = &mut *msg;
3982 let ctx = &*ffi_msg.context;
3983
3984 block_on({
3985 ffi_msg
3986 .message
3987 .latefiling_mediasize(ctx, width, height, duration)
3988 })
3989 .context("Cannot set media size")
3990 .log_err(ctx)
3991 .ok();
3992}
3993
3994#[no_mangle]
3995pub unsafe extern "C" fn dc_msg_get_error(msg: *mut dc_msg_t) -> *mut libc::c_char {
3996 if msg.is_null() {
3997 eprintln!("ignoring careless call to dc_msg_get_error()");
3998 return ptr::null_mut();
3999 }
4000 let ffi_msg = &*msg;
4001 match ffi_msg.message.error() {
4002 Some(error) => error.strdup(),
4003 None => ptr::null_mut(),
4004 }
4005}
4006
4007#[no_mangle]
4008pub unsafe extern "C" fn dc_msg_set_quote(msg: *mut dc_msg_t, quote: *const dc_msg_t) {
4009 if msg.is_null() {
4010 eprintln!("ignoring careless call to dc_msg_set_quote()");
4011 return;
4012 }
4013 let ffi_msg = &mut *msg;
4014 let quote_msg = if quote.is_null() {
4015 None
4016 } else {
4017 let ffi_quote = &*quote;
4018 if ffi_msg.context != ffi_quote.context {
4019 eprintln!("ignoring attempt to quote message from a different context");
4020 return;
4021 }
4022 Some(&ffi_quote.message)
4023 };
4024
4025 block_on(async move {
4026 ffi_msg
4027 .message
4028 .set_quote(&*ffi_msg.context, quote_msg)
4029 .await
4030 .context("failed to set quote")
4031 .log_err(&*ffi_msg.context)
4032 .ok();
4033 });
4034}
4035
4036#[no_mangle]
4037pub unsafe extern "C" fn dc_msg_get_quoted_text(msg: *const dc_msg_t) -> *mut libc::c_char {
4038 if msg.is_null() {
4039 eprintln!("ignoring careless call to dc_msg_get_quoted_text()");
4040 return ptr::null_mut();
4041 }
4042 let ffi_msg: &MessageWrapper = &*msg;
4043 ffi_msg
4044 .message
4045 .quoted_text()
4046 .map_or_else(ptr::null_mut, |s| s.strdup())
4047}
4048
4049#[no_mangle]
4050pub unsafe extern "C" fn dc_msg_get_quoted_msg(msg: *const dc_msg_t) -> *mut dc_msg_t {
4051 if msg.is_null() {
4052 eprintln!("ignoring careless call to dc_get_quoted_msg()");
4053 return ptr::null_mut();
4054 }
4055 let ffi_msg: &MessageWrapper = &*msg;
4056 let context = &*ffi_msg.context;
4057 let res = block_on(async move {
4058 ffi_msg
4059 .message
4060 .quoted_message(context)
4061 .await
4062 .context("failed to get quoted message")
4063 .log_err(context)
4064 .unwrap_or(None)
4065 });
4066
4067 match res {
4068 Some(message) => Box::into_raw(Box::new(MessageWrapper { context, message })),
4069 None => ptr::null_mut(),
4070 }
4071}
4072
4073#[no_mangle]
4074pub unsafe extern "C" fn dc_msg_get_parent(msg: *const dc_msg_t) -> *mut dc_msg_t {
4075 if msg.is_null() {
4076 eprintln!("ignoring careless call to dc_msg_get_parent()");
4077 return ptr::null_mut();
4078 }
4079 let ffi_msg: &MessageWrapper = &*msg;
4080 let context = &*ffi_msg.context;
4081 let res = block_on(async move {
4082 ffi_msg
4083 .message
4084 .parent(context)
4085 .await
4086 .context("failed to get parent message")
4087 .log_err(context)
4088 .unwrap_or(None)
4089 });
4090
4091 match res {
4092 Some(message) => Box::into_raw(Box::new(MessageWrapper { context, message })),
4093 None => ptr::null_mut(),
4094 }
4095}
4096
4097#[no_mangle]
4098pub unsafe extern "C" fn dc_msg_get_original_msg_id(msg: *const dc_msg_t) -> u32 {
4099 if msg.is_null() {
4100 eprintln!("ignoring careless call to dc_msg_get_original_msg_id()");
4101 return 0;
4102 }
4103 let ffi_msg: &MessageWrapper = &*msg;
4104 let context = &*ffi_msg.context;
4105 block_on(async move {
4106 ffi_msg
4107 .message
4108 .get_original_msg_id(context)
4109 .await
4110 .context("failed to get original message")
4111 .log_err(context)
4112 .unwrap_or_default()
4113 .map(|id| id.to_u32())
4114 .unwrap_or(0)
4115 })
4116}
4117
4118#[no_mangle]
4119pub unsafe extern "C" fn dc_msg_get_saved_msg_id(msg: *const dc_msg_t) -> u32 {
4120 if msg.is_null() {
4121 eprintln!("ignoring careless call to dc_msg_get_saved_msg_id()");
4122 return 0;
4123 }
4124 let ffi_msg: &MessageWrapper = &*msg;
4125 let context = &*ffi_msg.context;
4126 block_on(async move {
4127 ffi_msg
4128 .message
4129 .get_saved_msg_id(context)
4130 .await
4131 .context("failed to get original message")
4132 .log_err(context)
4133 .unwrap_or_default()
4134 .map(|id| id.to_u32())
4135 .unwrap_or(0)
4136 })
4137}
4138
4139#[no_mangle]
4140pub unsafe extern "C" fn dc_msg_force_plaintext(msg: *mut dc_msg_t) {
4141 if msg.is_null() {
4142 eprintln!("ignoring careless call to dc_msg_force_plaintext()");
4143 return;
4144 }
4145 let ffi_msg = &mut *msg;
4146 ffi_msg.message.force_plaintext();
4147}
4148
4149pub struct ContactWrapper {
4159 context: *const dc_context_t,
4160 contact: contact::Contact,
4161}
4162
4163pub type dc_contact_t = ContactWrapper;
4164
4165#[no_mangle]
4166pub unsafe extern "C" fn dc_contact_unref(contact: *mut dc_contact_t) {
4167 if contact.is_null() {
4168 eprintln!("ignoring careless call to dc_contact_unref()");
4169 return;
4170 }
4171 drop(Box::from_raw(contact));
4172}
4173
4174#[no_mangle]
4175pub unsafe extern "C" fn dc_contact_get_id(contact: *mut dc_contact_t) -> u32 {
4176 if contact.is_null() {
4177 eprintln!("ignoring careless call to dc_contact_get_id()");
4178 return 0;
4179 }
4180 let ffi_contact = &*contact;
4181 ffi_contact.contact.get_id().to_u32()
4182}
4183
4184#[no_mangle]
4185pub unsafe extern "C" fn dc_contact_get_addr(contact: *mut dc_contact_t) -> *mut libc::c_char {
4186 if contact.is_null() {
4187 eprintln!("ignoring careless call to dc_contact_get_addr()");
4188 return "".strdup();
4189 }
4190 let ffi_contact = &*contact;
4191 ffi_contact.contact.get_addr().strdup()
4192}
4193
4194#[no_mangle]
4195pub unsafe extern "C" fn dc_contact_get_name(contact: *mut dc_contact_t) -> *mut libc::c_char {
4196 if contact.is_null() {
4197 eprintln!("ignoring careless call to dc_contact_get_name()");
4198 return "".strdup();
4199 }
4200 let ffi_contact = &*contact;
4201 ffi_contact.contact.get_name().strdup()
4202}
4203
4204#[no_mangle]
4205pub unsafe extern "C" fn dc_contact_get_auth_name(contact: *mut dc_contact_t) -> *mut libc::c_char {
4206 if contact.is_null() {
4207 eprintln!("ignoring careless call to dc_contact_get_auth_name()");
4208 return "".strdup();
4209 }
4210 let ffi_contact = &*contact;
4211 ffi_contact.contact.get_authname().strdup()
4212}
4213
4214#[no_mangle]
4215pub unsafe extern "C" fn dc_contact_get_display_name(
4216 contact: *mut dc_contact_t,
4217) -> *mut libc::c_char {
4218 if contact.is_null() {
4219 eprintln!("ignoring careless call to dc_contact_get_display_name()");
4220 return "".strdup();
4221 }
4222 let ffi_contact = &*contact;
4223 ffi_contact.contact.get_display_name().strdup()
4224}
4225
4226#[no_mangle]
4227pub unsafe extern "C" fn dc_contact_get_name_n_addr(
4228 contact: *mut dc_contact_t,
4229) -> *mut libc::c_char {
4230 if contact.is_null() {
4231 eprintln!("ignoring careless call to dc_contact_get_name_n_addr()");
4232 return "".strdup();
4233 }
4234 let ffi_contact = &*contact;
4235 ffi_contact.contact.get_name_n_addr().strdup()
4236}
4237
4238#[no_mangle]
4239pub unsafe extern "C" fn dc_contact_get_profile_image(
4240 contact: *mut dc_contact_t,
4241) -> *mut libc::c_char {
4242 if contact.is_null() {
4243 eprintln!("ignoring careless call to dc_contact_get_profile_image()");
4244 return ptr::null_mut(); }
4246 let ffi_contact = &*contact;
4247 let ctx = &*ffi_contact.context;
4248
4249 block_on(async move {
4250 ffi_contact
4251 .contact
4252 .get_profile_image(ctx)
4253 .await
4254 .unwrap_or_log_default(ctx, "failed to get profile image")
4255 .map(|p| p.to_string_lossy().strdup())
4256 .unwrap_or_else(std::ptr::null_mut)
4257 })
4258}
4259
4260#[no_mangle]
4261pub unsafe extern "C" fn dc_contact_get_color(contact: *mut dc_contact_t) -> u32 {
4262 if contact.is_null() {
4263 eprintln!("ignoring careless call to dc_contact_get_color()");
4264 return 0;
4265 }
4266 let ffi_contact = &*contact;
4267 ffi_contact.contact.get_color()
4268}
4269
4270#[no_mangle]
4271pub unsafe extern "C" fn dc_contact_get_status(contact: *mut dc_contact_t) -> *mut libc::c_char {
4272 if contact.is_null() {
4273 eprintln!("ignoring careless call to dc_contact_get_status()");
4274 return "".strdup();
4275 }
4276 let ffi_contact = &*contact;
4277 ffi_contact.contact.get_status().strdup()
4278}
4279
4280#[no_mangle]
4281pub unsafe extern "C" fn dc_contact_get_last_seen(contact: *mut dc_contact_t) -> i64 {
4282 if contact.is_null() {
4283 eprintln!("ignoring careless call to dc_contact_get_last_seen()");
4284 return 0;
4285 }
4286 let ffi_contact = &*contact;
4287 ffi_contact.contact.last_seen()
4288}
4289
4290#[no_mangle]
4291pub unsafe extern "C" fn dc_contact_was_seen_recently(contact: *mut dc_contact_t) -> libc::c_int {
4292 if contact.is_null() {
4293 eprintln!("ignoring careless call to dc_contact_was_seen_recently()");
4294 return 0;
4295 }
4296 let ffi_contact = &*contact;
4297 ffi_contact.contact.was_seen_recently() as libc::c_int
4298}
4299
4300#[no_mangle]
4301pub unsafe extern "C" fn dc_contact_is_blocked(contact: *mut dc_contact_t) -> libc::c_int {
4302 if contact.is_null() {
4303 eprintln!("ignoring careless call to dc_contact_is_blocked()");
4304 return 0;
4305 }
4306 let ffi_contact = &*contact;
4307 ffi_contact.contact.is_blocked() as libc::c_int
4308}
4309
4310#[no_mangle]
4311pub unsafe extern "C" fn dc_contact_is_verified(contact: *mut dc_contact_t) -> libc::c_int {
4312 if contact.is_null() {
4313 eprintln!("ignoring careless call to dc_contact_is_verified()");
4314 return 0;
4315 }
4316 let ffi_contact = &*contact;
4317 let ctx = &*ffi_contact.context;
4318
4319 if block_on(ffi_contact.contact.is_verified(ctx))
4320 .context("is_verified failed")
4321 .log_err(ctx)
4322 .unwrap_or_default()
4323 {
4324 2
4327 } else {
4328 0
4329 }
4330}
4331
4332#[no_mangle]
4333pub unsafe extern "C" fn dc_contact_is_bot(contact: *mut dc_contact_t) -> libc::c_int {
4334 if contact.is_null() {
4335 eprintln!("ignoring careless call to dc_contact_is_bot()");
4336 return 0;
4337 }
4338 (*contact).contact.is_bot() as libc::c_int
4339}
4340
4341#[no_mangle]
4342pub unsafe extern "C" fn dc_contact_get_verifier_id(contact: *mut dc_contact_t) -> u32 {
4343 if contact.is_null() {
4344 eprintln!("ignoring careless call to dc_contact_get_verifier_id()");
4345 return 0;
4346 }
4347 let ffi_contact = &*contact;
4348 let ctx = &*ffi_contact.context;
4349 let verifier_contact_id = block_on(ffi_contact.contact.get_verifier_id(ctx))
4350 .context("failed to get verifier")
4351 .log_err(ctx)
4352 .unwrap_or_default()
4353 .unwrap_or_default();
4354
4355 verifier_contact_id.to_u32()
4356}
4357pub type dc_lot_t = lot::Lot;
4360
4361#[no_mangle]
4362pub unsafe extern "C" fn dc_lot_unref(lot: *mut dc_lot_t) {
4363 if lot.is_null() {
4364 eprintln!("ignoring careless call to dc_lot_unref()");
4365 return;
4366 }
4367
4368 drop(Box::from_raw(lot));
4369}
4370
4371#[no_mangle]
4372pub unsafe extern "C" fn dc_lot_get_text1(lot: *mut dc_lot_t) -> *mut libc::c_char {
4373 if lot.is_null() {
4374 eprintln!("ignoring careless call to dc_lot_get_text1()");
4375 return ptr::null_mut(); }
4377
4378 let lot = &*lot;
4379 lot.get_text1().strdup()
4380}
4381
4382#[no_mangle]
4383pub unsafe extern "C" fn dc_lot_get_text2(lot: *mut dc_lot_t) -> *mut libc::c_char {
4384 if lot.is_null() {
4385 eprintln!("ignoring careless call to dc_lot_get_text2()");
4386 return ptr::null_mut(); }
4388
4389 let lot = &*lot;
4390 lot.get_text2().strdup()
4391}
4392
4393#[no_mangle]
4394pub unsafe extern "C" fn dc_lot_get_text1_meaning(lot: *mut dc_lot_t) -> libc::c_int {
4395 if lot.is_null() {
4396 eprintln!("ignoring careless call to dc_lot_get_text1_meaning()");
4397 return 0;
4398 }
4399
4400 let lot = &*lot;
4401 lot.get_text1_meaning() as libc::c_int
4402}
4403
4404#[no_mangle]
4405pub unsafe extern "C" fn dc_lot_get_state(lot: *mut dc_lot_t) -> libc::c_int {
4406 if lot.is_null() {
4407 eprintln!("ignoring careless call to dc_lot_get_state()");
4408 return 0;
4409 }
4410
4411 let lot = &*lot;
4412 lot.get_state() as libc::c_int
4413}
4414
4415#[no_mangle]
4416pub unsafe extern "C" fn dc_lot_get_id(lot: *mut dc_lot_t) -> u32 {
4417 if lot.is_null() {
4418 eprintln!("ignoring careless call to dc_lot_get_id()");
4419 return 0;
4420 }
4421
4422 let lot = &*lot;
4423 lot.get_id()
4424}
4425
4426#[no_mangle]
4427pub unsafe extern "C" fn dc_lot_get_timestamp(lot: *mut dc_lot_t) -> i64 {
4428 if lot.is_null() {
4429 eprintln!("ignoring careless call to dc_lot_get_timestamp()");
4430 return 0;
4431 }
4432
4433 let lot = &*lot;
4434 lot.get_timestamp()
4435}
4436
4437#[no_mangle]
4438pub unsafe extern "C" fn dc_str_unref(s: *mut libc::c_char) {
4439 libc::free(s as *mut _)
4440}
4441
4442pub struct BackupProviderWrapper {
4443 context: *const dc_context_t,
4444 provider: BackupProvider,
4445}
4446
4447pub type dc_backup_provider_t = BackupProviderWrapper;
4448
4449#[no_mangle]
4450pub unsafe extern "C" fn dc_backup_provider_new(
4451 context: *mut dc_context_t,
4452) -> *mut dc_backup_provider_t {
4453 if context.is_null() {
4454 eprintln!("ignoring careless call to dc_backup_provider_new()");
4455 return ptr::null_mut();
4456 }
4457 let ctx = &*context;
4458 block_on(BackupProvider::prepare(ctx))
4459 .map(|provider| BackupProviderWrapper {
4460 context: ctx,
4461 provider,
4462 })
4463 .map(|ffi_provider| Box::into_raw(Box::new(ffi_provider)))
4464 .context("BackupProvider failed")
4465 .log_err(ctx)
4466 .set_last_error(ctx)
4467 .unwrap_or(ptr::null_mut())
4468}
4469
4470#[no_mangle]
4471pub unsafe extern "C" fn dc_backup_provider_get_qr(
4472 provider: *const dc_backup_provider_t,
4473) -> *mut libc::c_char {
4474 if provider.is_null() {
4475 eprintln!("ignoring careless call to dc_backup_provider_qr");
4476 return "".strdup();
4477 }
4478 let ffi_provider = &*provider;
4479 let ctx = &*ffi_provider.context;
4480 deltachat::qr::format_backup(&ffi_provider.provider.qr())
4481 .context("BackupProvider get_qr failed")
4482 .log_err(ctx)
4483 .set_last_error(ctx)
4484 .unwrap_or_default()
4485 .strdup()
4486}
4487
4488#[no_mangle]
4489pub unsafe extern "C" fn dc_backup_provider_get_qr_svg(
4490 provider: *const dc_backup_provider_t,
4491) -> *mut libc::c_char {
4492 if provider.is_null() {
4493 eprintln!("ignoring careless call to dc_backup_provider_qr_svg()");
4494 return "".strdup();
4495 }
4496 let ffi_provider = &*provider;
4497 let ctx = &*ffi_provider.context;
4498 let provider = &ffi_provider.provider;
4499 block_on(generate_backup_qr(ctx, &provider.qr()))
4500 .context("BackupProvider get_qr_svg failed")
4501 .log_err(ctx)
4502 .set_last_error(ctx)
4503 .unwrap_or_default()
4504 .strdup()
4505}
4506
4507#[no_mangle]
4508pub unsafe extern "C" fn dc_backup_provider_wait(provider: *mut dc_backup_provider_t) {
4509 if provider.is_null() {
4510 eprintln!("ignoring careless call to dc_backup_provider_wait()");
4511 return;
4512 }
4513 let ffi_provider = &mut *provider;
4514 let ctx = &*ffi_provider.context;
4515 let provider = &mut ffi_provider.provider;
4516 block_on(provider)
4517 .context("Failed to await backup provider")
4518 .log_err(ctx)
4519 .set_last_error(ctx)
4520 .ok();
4521}
4522
4523#[no_mangle]
4524pub unsafe extern "C" fn dc_backup_provider_unref(provider: *mut dc_backup_provider_t) {
4525 if provider.is_null() {
4526 eprintln!("ignoring careless call to dc_backup_provider_unref()");
4527 return;
4528 }
4529 drop(Box::from_raw(provider));
4530}
4531
4532#[no_mangle]
4533pub unsafe extern "C" fn dc_receive_backup(
4534 context: *mut dc_context_t,
4535 qr: *const libc::c_char,
4536) -> libc::c_int {
4537 if context.is_null() {
4538 eprintln!("ignoring careless call to dc_receive_backup()");
4539 return 0;
4540 }
4541 let ctx = &*context;
4542 let qr_text = to_string_lossy(qr);
4543 receive_backup(ctx.clone(), qr_text)
4544}
4545
4546fn receive_backup(ctx: Context, qr_text: String) -> libc::c_int {
4549 let qr = match block_on(qr::check_qr(&ctx, &qr_text))
4550 .context("Invalid QR code")
4551 .log_err(&ctx)
4552 .set_last_error(&ctx)
4553 {
4554 Ok(qr) => qr,
4555 Err(_) => return 0,
4556 };
4557 match block_on(imex::get_backup(&ctx, qr))
4558 .context("Get backup failed")
4559 .log_err(&ctx)
4560 .set_last_error(&ctx)
4561 {
4562 Ok(_) => 1,
4563 Err(_) => 0,
4564 }
4565}
4566
4567trait ResultExt<T, E> {
4568 fn unwrap_or_log_default(self, context: &context::Context, message: &str) -> T;
4573}
4574
4575impl<T: Default, E: std::fmt::Display> ResultExt<T, E> for Result<T, E> {
4576 fn unwrap_or_log_default(self, context: &context::Context, message: &str) -> T {
4577 match self {
4578 Ok(t) => t,
4579 Err(err) => {
4580 error!(context, "{message}: {err:#}");
4581 Default::default()
4582 }
4583 }
4584 }
4585}
4586
4587trait ResultLastError<T, E>
4588where
4589 E: std::fmt::Display,
4590{
4591 fn set_last_error(self, context: &context::Context) -> Result<T, E>;
4623}
4624
4625impl<T, E> ResultLastError<T, E> for Result<T, E>
4626where
4627 E: std::fmt::Display,
4628{
4629 fn set_last_error(self, context: &context::Context) -> Result<T, E> {
4630 if let Err(ref err) = self {
4631 context.set_last_error(&format!("{err:#}"));
4632 }
4633 self
4634 }
4635}
4636
4637fn convert_and_prune_message_ids(msg_ids: *const u32, msg_cnt: libc::c_int) -> Vec<MsgId> {
4638 let ids = unsafe { std::slice::from_raw_parts(msg_ids, msg_cnt as usize) };
4639 let msg_ids: Vec<MsgId> = ids
4640 .iter()
4641 .filter(|id| **id > DC_MSG_ID_LAST_SPECIAL)
4642 .map(|id| MsgId::new(*id))
4643 .collect();
4644
4645 msg_ids
4646}
4647
4648pub type dc_provider_t = provider::Provider;
4651
4652#[no_mangle]
4653pub unsafe extern "C" fn dc_provider_new_from_email(
4654 context: *const dc_context_t,
4655 addr: *const libc::c_char,
4656) -> *const dc_provider_t {
4657 if context.is_null() || addr.is_null() {
4658 eprintln!("ignoring careless call to dc_provider_new_from_email()");
4659 return ptr::null();
4660 }
4661 let addr = to_string_lossy(addr);
4662
4663 let ctx = &*context;
4664
4665 match block_on(provider::get_provider_info_by_addr(
4666 ctx,
4667 addr.as_str(),
4668 true,
4669 ))
4670 .log_err(ctx)
4671 .unwrap_or_default()
4672 {
4673 Some(provider) => provider,
4674 None => ptr::null_mut(),
4675 }
4676}
4677
4678#[no_mangle]
4679pub unsafe extern "C" fn dc_provider_new_from_email_with_dns(
4680 context: *const dc_context_t,
4681 addr: *const libc::c_char,
4682) -> *const dc_provider_t {
4683 if context.is_null() || addr.is_null() {
4684 eprintln!("ignoring careless call to dc_provider_new_from_email_with_dns()");
4685 return ptr::null();
4686 }
4687 let addr = to_string_lossy(addr);
4688
4689 let ctx = &*context;
4690 let proxy_enabled = block_on(ctx.get_config_bool(config::Config::ProxyEnabled))
4691 .context("Can't get config")
4692 .log_err(ctx);
4693
4694 match proxy_enabled {
4695 Ok(proxy_enabled) => {
4696 match block_on(provider::get_provider_info_by_addr(
4697 ctx,
4698 addr.as_str(),
4699 proxy_enabled,
4700 ))
4701 .log_err(ctx)
4702 .unwrap_or_default()
4703 {
4704 Some(provider) => provider,
4705 None => ptr::null_mut(),
4706 }
4707 }
4708 Err(_) => ptr::null_mut(),
4709 }
4710}
4711
4712#[no_mangle]
4713pub unsafe extern "C" fn dc_provider_get_overview_page(
4714 provider: *const dc_provider_t,
4715) -> *mut libc::c_char {
4716 if provider.is_null() {
4717 eprintln!("ignoring careless call to dc_provider_get_overview_page()");
4718 return "".strdup();
4719 }
4720 let provider = &*provider;
4721 provider.overview_page.strdup()
4722}
4723
4724#[no_mangle]
4725pub unsafe extern "C" fn dc_provider_get_before_login_hint(
4726 provider: *const dc_provider_t,
4727) -> *mut libc::c_char {
4728 if provider.is_null() {
4729 eprintln!("ignoring careless call to dc_provider_get_before_login_hint()");
4730 return "".strdup();
4731 }
4732 let provider = &*provider;
4733 provider.before_login_hint.strdup()
4734}
4735
4736#[no_mangle]
4737pub unsafe extern "C" fn dc_provider_get_status(provider: *const dc_provider_t) -> libc::c_int {
4738 if provider.is_null() {
4739 eprintln!("ignoring careless call to dc_provider_get_status()");
4740 return 0;
4741 }
4742 let provider = &*provider;
4743 provider.status as libc::c_int
4744}
4745
4746#[no_mangle]
4747#[allow(clippy::needless_return)]
4748pub unsafe extern "C" fn dc_provider_unref(provider: *mut dc_provider_t) {
4749 if provider.is_null() {
4750 eprintln!("ignoring careless call to dc_provider_unref()");
4751 return;
4752 }
4753 }
4756
4757pub struct AccountsWrapper {
4762 inner: Arc<RwLock<Accounts>>,
4763}
4764
4765impl Deref for AccountsWrapper {
4766 type Target = Arc<RwLock<Accounts>>;
4767
4768 fn deref(&self) -> &Self::Target {
4769 &self.inner
4770 }
4771}
4772
4773impl AccountsWrapper {
4774 fn new(accounts: Accounts) -> Self {
4775 let inner = Arc::new(RwLock::new(accounts));
4776 Self { inner }
4777 }
4778}
4779
4780pub type dc_accounts_t = AccountsWrapper;
4782
4783#[no_mangle]
4784pub unsafe extern "C" fn dc_accounts_new(
4785 dir: *const libc::c_char,
4786 writable: libc::c_int,
4787) -> *mut dc_accounts_t {
4788 setup_panic!();
4789
4790 if dir.is_null() {
4791 eprintln!("ignoring careless call to dc_accounts_new()");
4792 return ptr::null_mut();
4793 }
4794
4795 let accs = block_on(Accounts::new(as_path(dir).into(), writable != 0));
4796
4797 match accs {
4798 Ok(accs) => Box::into_raw(Box::new(AccountsWrapper::new(accs))),
4799 Err(err) => {
4800 eprintln!("failed to create accounts: {err:#}");
4802 ptr::null_mut()
4803 }
4804 }
4805}
4806
4807#[no_mangle]
4811pub unsafe extern "C" fn dc_accounts_unref(accounts: *mut dc_accounts_t) {
4812 if accounts.is_null() {
4813 eprintln!("ignoring careless call to dc_accounts_unref()");
4814 return;
4815 }
4816 let _ = Box::from_raw(accounts);
4817}
4818
4819#[no_mangle]
4820pub unsafe extern "C" fn dc_accounts_get_account(
4821 accounts: *mut dc_accounts_t,
4822 id: u32,
4823) -> *mut dc_context_t {
4824 if accounts.is_null() {
4825 eprintln!("ignoring careless call to dc_accounts_get_account()");
4826 return ptr::null_mut();
4827 }
4828
4829 let accounts = &*accounts;
4830 block_on(accounts.read())
4831 .get_account(id)
4832 .map(|ctx| Box::into_raw(Box::new(ctx)))
4833 .unwrap_or_else(std::ptr::null_mut)
4834}
4835
4836#[no_mangle]
4837pub unsafe extern "C" fn dc_accounts_get_selected_account(
4838 accounts: *mut dc_accounts_t,
4839) -> *mut dc_context_t {
4840 if accounts.is_null() {
4841 eprintln!("ignoring careless call to dc_accounts_get_selected_account()");
4842 return ptr::null_mut();
4843 }
4844
4845 let accounts = &*accounts;
4846 block_on(accounts.read())
4847 .get_selected_account()
4848 .map(|ctx| Box::into_raw(Box::new(ctx)))
4849 .unwrap_or_else(std::ptr::null_mut)
4850}
4851
4852#[no_mangle]
4853pub unsafe extern "C" fn dc_accounts_select_account(
4854 accounts: *mut dc_accounts_t,
4855 id: u32,
4856) -> libc::c_int {
4857 if accounts.is_null() {
4858 eprintln!("ignoring careless call to dc_accounts_select_account()");
4859 return 0;
4860 }
4861
4862 let accounts = &*accounts;
4863 block_on(async move {
4864 let mut accounts = accounts.write().await;
4865 match accounts.select_account(id).await {
4866 Ok(()) => 1,
4867 Err(err) => {
4868 accounts.emit_event(EventType::Error(format!(
4869 "Failed to select account: {err:#}"
4870 )));
4871 0
4872 }
4873 }
4874 })
4875}
4876
4877#[no_mangle]
4878pub unsafe extern "C" fn dc_accounts_add_account(accounts: *mut dc_accounts_t) -> u32 {
4879 if accounts.is_null() {
4880 eprintln!("ignoring careless call to dc_accounts_add_account()");
4881 return 0;
4882 }
4883
4884 let accounts = &mut *accounts;
4885
4886 block_on(async move {
4887 let mut accounts = accounts.write().await;
4888 match accounts.add_account().await {
4889 Ok(id) => id,
4890 Err(err) => {
4891 accounts.emit_event(EventType::Error(format!("Failed to add account: {err:#}")));
4892 0
4893 }
4894 }
4895 })
4896}
4897
4898#[no_mangle]
4899pub unsafe extern "C" fn dc_accounts_add_closed_account(accounts: *mut dc_accounts_t) -> u32 {
4900 if accounts.is_null() {
4901 eprintln!("ignoring careless call to dc_accounts_add_closed_account()");
4902 return 0;
4903 }
4904
4905 let accounts = &mut *accounts;
4906
4907 block_on(async move {
4908 let mut accounts = accounts.write().await;
4909 match accounts.add_closed_account().await {
4910 Ok(id) => id,
4911 Err(err) => {
4912 accounts.emit_event(EventType::Error(format!("Failed to add account: {err:#}")));
4913 0
4914 }
4915 }
4916 })
4917}
4918
4919#[no_mangle]
4920pub unsafe extern "C" fn dc_accounts_remove_account(
4921 accounts: *mut dc_accounts_t,
4922 id: u32,
4923) -> libc::c_int {
4924 if accounts.is_null() {
4925 eprintln!("ignoring careless call to dc_accounts_remove_account()");
4926 return 0;
4927 }
4928
4929 let accounts = &mut *accounts;
4930
4931 block_on(async move {
4932 let mut accounts = accounts.write().await;
4933 match accounts.remove_account(id).await {
4934 Ok(()) => 1,
4935 Err(err) => {
4936 accounts.emit_event(EventType::Error(format!(
4937 "Failed to remove account: {err:#}"
4938 )));
4939 0
4940 }
4941 }
4942 })
4943}
4944
4945#[no_mangle]
4946pub unsafe extern "C" fn dc_accounts_migrate_account(
4947 accounts: *mut dc_accounts_t,
4948 dbfile: *const libc::c_char,
4949) -> u32 {
4950 if accounts.is_null() || dbfile.is_null() {
4951 eprintln!("ignoring careless call to dc_accounts_migrate_account()");
4952 return 0;
4953 }
4954
4955 let accounts = &mut *accounts;
4956 let dbfile = to_string_lossy(dbfile);
4957
4958 block_on(async move {
4959 let mut accounts = accounts.write().await;
4960 match accounts
4961 .migrate_account(std::path::PathBuf::from(dbfile))
4962 .await
4963 {
4964 Ok(id) => id,
4965 Err(err) => {
4966 accounts.emit_event(EventType::Error(format!(
4967 "Failed to migrate account: {err:#}"
4968 )));
4969 0
4970 }
4971 }
4972 })
4973}
4974
4975#[no_mangle]
4976pub unsafe extern "C" fn dc_accounts_get_all(accounts: *mut dc_accounts_t) -> *mut dc_array_t {
4977 if accounts.is_null() {
4978 eprintln!("ignoring careless call to dc_accounts_get_all()");
4979 return ptr::null_mut();
4980 }
4981
4982 let accounts = &*accounts;
4983 let list = block_on(accounts.read()).get_all();
4984 let array: dc_array_t = list.into();
4985
4986 Box::into_raw(Box::new(array))
4987}
4988
4989#[no_mangle]
4990pub unsafe extern "C" fn dc_accounts_start_io(accounts: *mut dc_accounts_t) {
4991 if accounts.is_null() {
4992 eprintln!("ignoring careless call to dc_accounts_start_io()");
4993 return;
4994 }
4995
4996 let accounts = &mut *accounts;
4997 block_on(async move { accounts.write().await.start_io().await });
4998}
4999
5000#[no_mangle]
5001pub unsafe extern "C" fn dc_accounts_stop_io(accounts: *mut dc_accounts_t) {
5002 if accounts.is_null() {
5003 eprintln!("ignoring careless call to dc_accounts_stop_io()");
5004 return;
5005 }
5006
5007 let accounts = &*accounts;
5008 block_on(async move { accounts.read().await.stop_io().await });
5009}
5010
5011#[no_mangle]
5012pub unsafe extern "C" fn dc_accounts_maybe_network(accounts: *mut dc_accounts_t) {
5013 if accounts.is_null() {
5014 eprintln!("ignoring careless call to dc_accounts_maybe_network()");
5015 return;
5016 }
5017
5018 let accounts = &*accounts;
5019 block_on(async move { accounts.read().await.maybe_network().await });
5020}
5021
5022#[no_mangle]
5023pub unsafe extern "C" fn dc_accounts_maybe_network_lost(accounts: *mut dc_accounts_t) {
5024 if accounts.is_null() {
5025 eprintln!("ignoring careless call to dc_accounts_maybe_network_lost()");
5026 return;
5027 }
5028
5029 let accounts = &*accounts;
5030 block_on(async move { accounts.read().await.maybe_network_lost().await });
5031}
5032
5033#[no_mangle]
5034pub unsafe extern "C" fn dc_accounts_background_fetch(
5035 accounts: *mut dc_accounts_t,
5036 timeout_in_seconds: u64,
5037) -> libc::c_int {
5038 if accounts.is_null() || timeout_in_seconds <= 2 {
5039 eprintln!("ignoring careless call to dc_accounts_background_fetch()");
5040 return 0;
5041 }
5042
5043 let accounts = &*accounts;
5044 let background_fetch_future = {
5045 let lock = block_on(accounts.read());
5046 lock.background_fetch(Duration::from_secs(timeout_in_seconds))
5047 };
5048 block_on(background_fetch_future);
5050 1
5051}
5052
5053#[no_mangle]
5054pub unsafe extern "C" fn dc_accounts_set_push_device_token(
5055 accounts: *mut dc_accounts_t,
5056 token: *const libc::c_char,
5057) {
5058 if accounts.is_null() {
5059 eprintln!("ignoring careless call to dc_accounts_set_push_device_token()");
5060 return;
5061 }
5062
5063 let accounts = &*accounts;
5064 let token = to_string_lossy(token);
5065
5066 block_on(async move {
5067 let accounts = accounts.read().await;
5068 if let Err(err) = accounts.set_push_device_token(&token).await {
5069 accounts.emit_event(EventType::Error(format!(
5070 "Failed to set notify token: {err:#}."
5071 )));
5072 }
5073 })
5074}
5075
5076#[no_mangle]
5077pub unsafe extern "C" fn dc_accounts_get_event_emitter(
5078 accounts: *mut dc_accounts_t,
5079) -> *mut dc_event_emitter_t {
5080 if accounts.is_null() {
5081 eprintln!("ignoring careless call to dc_accounts_get_event_emitter()");
5082 return ptr::null_mut();
5083 }
5084
5085 let accounts = &*accounts;
5086 let emitter = block_on(accounts.read()).get_event_emitter();
5087
5088 Box::into_raw(Box::new(emitter))
5089}
5090
5091pub struct dc_jsonrpc_instance_t {
5092 receiver: OutReceiver,
5093 handle: RpcSession<CommandApi>,
5094}
5095
5096#[no_mangle]
5097pub unsafe extern "C" fn dc_jsonrpc_init(
5098 account_manager: *mut dc_accounts_t,
5099) -> *mut dc_jsonrpc_instance_t {
5100 if account_manager.is_null() {
5101 eprintln!("ignoring careless call to dc_jsonrpc_init()");
5102 return ptr::null_mut();
5103 }
5104
5105 let account_manager = &*account_manager;
5106 let cmd_api = block_on(deltachat_jsonrpc::api::CommandApi::from_arc(
5107 account_manager.inner.clone(),
5108 ));
5109
5110 let (request_handle, receiver) = RpcClient::new();
5111 let handle = RpcSession::new(request_handle, cmd_api);
5112
5113 let instance = dc_jsonrpc_instance_t { receiver, handle };
5114
5115 Box::into_raw(Box::new(instance))
5116}
5117
5118#[no_mangle]
5119pub unsafe extern "C" fn dc_jsonrpc_unref(jsonrpc_instance: *mut dc_jsonrpc_instance_t) {
5120 if jsonrpc_instance.is_null() {
5121 eprintln!("ignoring careless call to dc_jsonrpc_unref()");
5122 return;
5123 }
5124 drop(Box::from_raw(jsonrpc_instance));
5125}
5126
5127fn spawn_handle_jsonrpc_request(handle: RpcSession<CommandApi>, request: String) {
5128 spawn(async move {
5129 handle.handle_incoming(&request).await;
5130 });
5131}
5132
5133#[no_mangle]
5134pub unsafe extern "C" fn dc_jsonrpc_request(
5135 jsonrpc_instance: *mut dc_jsonrpc_instance_t,
5136 request: *const libc::c_char,
5137) {
5138 if jsonrpc_instance.is_null() || request.is_null() {
5139 eprintln!("ignoring careless call to dc_jsonrpc_request()");
5140 return;
5141 }
5142
5143 let handle = &(*jsonrpc_instance).handle;
5144 let request = to_string_lossy(request);
5145 spawn_handle_jsonrpc_request(handle.clone(), request);
5146}
5147
5148#[no_mangle]
5149pub unsafe extern "C" fn dc_jsonrpc_next_response(
5150 jsonrpc_instance: *mut dc_jsonrpc_instance_t,
5151) -> *mut libc::c_char {
5152 if jsonrpc_instance.is_null() {
5153 eprintln!("ignoring careless call to dc_jsonrpc_next_response()");
5154 return ptr::null_mut();
5155 }
5156 let api = &*jsonrpc_instance;
5157 block_on(api.receiver.recv())
5158 .map(|result| serde_json::to_string(&result).unwrap_or_default().strdup())
5159 .unwrap_or(ptr::null_mut())
5160}
5161
5162#[no_mangle]
5163pub unsafe extern "C" fn dc_jsonrpc_blocking_call(
5164 jsonrpc_instance: *mut dc_jsonrpc_instance_t,
5165 input: *const libc::c_char,
5166) -> *mut libc::c_char {
5167 if jsonrpc_instance.is_null() {
5168 eprintln!("ignoring careless call to dc_jsonrpc_blocking_call()");
5169 return ptr::null_mut();
5170 }
5171 let api = &*jsonrpc_instance;
5172 let input = to_string_lossy(input);
5173 let res = block_on(api.handle.process_incoming(&input));
5174 match res {
5175 Some(message) => {
5176 if let Ok(message) = serde_json::to_string(&message) {
5177 message.strdup()
5178 } else {
5179 ptr::null_mut()
5180 }
5181 }
5182 None => ptr::null_mut(),
5183 }
5184}