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