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