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