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