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