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