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