deltachat/
lib.rs

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