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