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