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