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