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