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