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