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