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