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