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