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