mirror of
https://github.com/chatmail/core.git
synced 2026-05-03 21:36:29 +03:00
implement ffi and use public sendme
This commit is contained in:
758
Cargo.lock
generated
758
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -152,6 +152,3 @@ vendored = [
|
||||
"rusqlite/bundled-sqlcipher-vendored-openssl",
|
||||
"reqwest/native-tls-vendored"
|
||||
]
|
||||
|
||||
[patch.'https://github.com/n0-computer/sendme']
|
||||
sendme = { path = "/home/flub/n0/sendme" }
|
||||
@@ -24,6 +24,7 @@ typedef struct _dc_provider dc_provider_t;
|
||||
typedef struct _dc_event dc_event_t;
|
||||
typedef struct _dc_event_emitter dc_event_emitter_t;
|
||||
typedef struct _dc_jsonrpc_instance dc_jsonrpc_instance_t;
|
||||
typedef struct _dc_backup_provider dc_backup_provider_t;
|
||||
|
||||
// Alias for backwards compatibility, use dc_event_emitter_t instead.
|
||||
typedef struct _dc_event_emitter dc_accounts_event_emitter_t;
|
||||
@@ -2295,6 +2296,7 @@ void dc_stop_ongoing_process (dc_context_t* context);
|
||||
#define DC_QR_FPR_MISMATCH 220 // id=contact
|
||||
#define DC_QR_FPR_WITHOUT_ADDR 230 // test1=formatted fingerprint
|
||||
#define DC_QR_ACCOUNT 250 // text1=domain
|
||||
#define DC_QR_BACKUP 251
|
||||
#define DC_QR_WEBRTC_INSTANCE 260 // text1=domain, text2=instance pattern
|
||||
#define DC_QR_ADDR 320 // id=contact
|
||||
#define DC_QR_TEXT 330 // text1=text
|
||||
@@ -2634,8 +2636,108 @@ char* dc_get_last_error (dc_context_t* context);
|
||||
void dc_str_unref (char* str);
|
||||
|
||||
|
||||
// TODO: add New stuff
|
||||
/**
|
||||
* @class dc_backup_provider_t
|
||||
*
|
||||
* Set up another device.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates an object for sending a backup to another device.
|
||||
*
|
||||
* The backup is sent to through a peer-to-peer channel which is bootstrapped
|
||||
* by a QR-code. The backup contains the entire state of the account
|
||||
* including credentials. This can be used to setup a new device.
|
||||
*
|
||||
* Once this function returns the backup is being offered to remove devices.
|
||||
* To wait until one device transferred the backup, use
|
||||
* dc_backup_provider_done(). Alternatively abort the operation using
|
||||
* dc_stop_ongoing_process().
|
||||
*
|
||||
* During execution of the job #DC_EVENT_IMEX_PROGRESS is sent out to indicate
|
||||
* state and progress.
|
||||
*
|
||||
* @memberof dc_backup_sender_t
|
||||
* @param context The context.
|
||||
* @param folder A Path to a temporary directory where the encrypted database
|
||||
* export will be created. The directory is not automatically cleaned
|
||||
* after the backup is sent.
|
||||
* @return Opaque object for sending the backup.
|
||||
* On errors, NULL is returned and dc_get_last_error()returns an error that
|
||||
* should be shown to the user.
|
||||
*/
|
||||
dc_backup_provider_t* dc_provide_backup (dc_context_t* context, const chat* folder);
|
||||
|
||||
|
||||
/**
|
||||
* Returns the QR code text that will offer the backup to other devices.
|
||||
*
|
||||
* The QR code contains a ticket which will validate the backup and provide
|
||||
* authentication for both the provider and the recipient.
|
||||
*
|
||||
* The scanning device should call the scanned text to dc_check_qr(). If
|
||||
* dc_check_qr() returns DC_QR_BACKUP the backup transfer can be started using
|
||||
* dc_get_backup().
|
||||
*
|
||||
* @memberof dc_backup_provider_t
|
||||
* @param context The context.
|
||||
* @param backup_provider The backup provider object as created by
|
||||
* dc_provide_backup().
|
||||
* @return The text that should be put in the QR code.
|
||||
* On errors and empty QR code is returned, NULL is never returned.
|
||||
* the returned string must be released using dc_str_unref() after usage.
|
||||
*/
|
||||
char* dc_backup_provider_qr (dc_context_t* context, const dc_backup_provider_t* backup_provider);
|
||||
|
||||
|
||||
/**
|
||||
* Returns the QR code SVG image that will offer the backup to other devices.
|
||||
*
|
||||
* This works like dc_backup_provider_qr() but returns the text of a rendered
|
||||
* SVG image containing the QR code.
|
||||
*
|
||||
* @memberof dc_backup_provider_t
|
||||
* @param context The context.
|
||||
* @param backup_provider The backup provider object as created by
|
||||
* dc_provide_backup().
|
||||
* @return The text that should be put in the QR code.
|
||||
* On errors and empty QR code is returned, NULL is never returned.
|
||||
* the returned string must be released using dc_str_unref() after usage.
|
||||
*/
|
||||
char * dc_backup_provider_qr_svg (dc_context_t* context, const dc_backup_provider_t* backup_provider);
|
||||
|
||||
/**
|
||||
* Waits for the sending to finish and frees the backup provider object.
|
||||
*
|
||||
* @memberof dc_backup_sender_t
|
||||
* @param context The context.
|
||||
* @param backup_sender The backup sender object as created by dc_send_backup().
|
||||
* If NULL is given nothing is done.
|
||||
*/
|
||||
void dc_backup_provider_done (dc_context_t* context, dc_backup_provider_t* backup_provider);
|
||||
|
||||
|
||||
/**
|
||||
* Gets a backup offered by a dc_backup_provider_t object on another device.
|
||||
*
|
||||
* This function is called on a device that scanned the QR code offered by
|
||||
* dc_backup_sender_qr() or dc_backup_sender_qr_svg(). Typically this is a
|
||||
* different device than that which provides the backup.
|
||||
*
|
||||
* While dc_receive_backup() returns immediately the started job make take a
|
||||
* while. Use dc_stop_ongoing_process() to abort it early.
|
||||
*
|
||||
* During execution of the job #DC_EVENT_IMEX_PROGRESS is sent out to indicate
|
||||
* state and progress.
|
||||
*
|
||||
* @param context The context.
|
||||
* @param qr The qr code text, dc_check_qr() must have returned DC_QR_BACKUP
|
||||
* on this text.
|
||||
* @return 0=failure, 1=success. Success only means the progress was started
|
||||
* correctly, final success or failure is via the #DC_EVENT_IMEX_PROGRESS
|
||||
* events.
|
||||
*/
|
||||
int dc_receive_backup (dc_context_t* context, const char* qr);
|
||||
|
||||
/**
|
||||
* @class dc_accounts_t
|
||||
|
||||
@@ -28,9 +28,10 @@ use deltachat::constants::DC_MSG_ID_LAST_SPECIAL;
|
||||
use deltachat::contact::{Contact, ContactId, Origin};
|
||||
use deltachat::context::Context;
|
||||
use deltachat::ephemeral::Timer as EphemeralTimer;
|
||||
use deltachat::imex::BackupProvider;
|
||||
use deltachat::key::DcKey;
|
||||
use deltachat::message::MsgId;
|
||||
use deltachat::qr_code_generator::get_securejoin_qr_svg;
|
||||
use deltachat::qr_code_generator::{generate_backup_qr, get_securejoin_qr_svg};
|
||||
use deltachat::reaction::{get_msg_reactions, send_reaction, Reactions};
|
||||
use deltachat::stock_str::StockMessage;
|
||||
use deltachat::stock_str::StockStrings;
|
||||
@@ -4130,6 +4131,102 @@ pub unsafe extern "C" fn dc_str_unref(s: *mut libc::c_char) {
|
||||
libc::free(s as *mut _)
|
||||
}
|
||||
|
||||
pub type dc_backup_provider_t = BackupProvider;
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_provide_backup(
|
||||
context: *mut dc_context_t,
|
||||
folder: *const libc::c_char,
|
||||
) -> *mut dc_backup_provider_t {
|
||||
if context.is_null() {
|
||||
eprintln!("ignoring careless call to dc_send_backup()");
|
||||
return ptr::null_mut();
|
||||
}
|
||||
let ctx = &*context;
|
||||
let dir = as_path(folder);
|
||||
block_on(async move {
|
||||
BackupProvider::prepare(ctx, dir)
|
||||
.await
|
||||
.map(|provider| Box::into_raw(Box::new(provider)))
|
||||
.log_err(ctx, "BackupProvider failed")
|
||||
.unwrap_or(ptr::null_mut())
|
||||
})
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_backup_provider_qr(
|
||||
_context: *mut dc_context_t,
|
||||
provider: *const dc_backup_provider_t,
|
||||
) -> *mut libc::c_char {
|
||||
let provider = &*provider;
|
||||
deltachat::qr::format_backup(provider.qr())
|
||||
.unwrap_or_default()
|
||||
.strdup()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_backup_provider_qr_svg(
|
||||
context: *mut dc_context_t,
|
||||
provider: *const dc_backup_provider_t,
|
||||
) -> *mut libc::c_char {
|
||||
if context.is_null() {
|
||||
eprintln!("ignoring careless call to dc_send_backup()");
|
||||
return ptr::null_mut();
|
||||
}
|
||||
let ctx = &*context;
|
||||
let provider = &*provider;
|
||||
block_on(async move {
|
||||
generate_backup_qr(ctx, provider.qr())
|
||||
.await
|
||||
.unwrap_or_default()
|
||||
.strdup()
|
||||
})
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_backup_provider_done(
|
||||
context: *mut dc_context_t,
|
||||
provider: *mut dc_backup_provider_t,
|
||||
) {
|
||||
if context.is_null() {
|
||||
eprintln!("ignoring careless call to dc_send_backup()");
|
||||
return;
|
||||
}
|
||||
let ctx = &*context;
|
||||
let provider = Box::from_raw(provider);
|
||||
block_on(async move {
|
||||
provider
|
||||
.join()
|
||||
.await
|
||||
.log_err(ctx, "Failed to join provider")
|
||||
.ok();
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_receive_backup(
|
||||
context: *mut dc_context_t,
|
||||
qr: *const libc::c_char,
|
||||
) -> libc::c_int {
|
||||
if context.is_null() {
|
||||
eprintln!("ignoring careless call to dc_send_backup()");
|
||||
return 0;
|
||||
}
|
||||
let ctx = &*context;
|
||||
let qr_text = to_string_lossy(qr);
|
||||
let qr = match block_on(qr::check_qr(ctx, &qr_text)).log_err(ctx, "Invalid QR code") {
|
||||
Ok(qr) => qr,
|
||||
Err(_) => return 0,
|
||||
};
|
||||
spawn(async move {
|
||||
imex::get_backup(ctx, qr)
|
||||
.await
|
||||
.log_err(ctx, "Get backup failed")
|
||||
.ok();
|
||||
});
|
||||
1
|
||||
}
|
||||
|
||||
trait ResultExt<T, E> {
|
||||
/// Like `log_err()`, but:
|
||||
/// - returns the default value instead of an Err value.
|
||||
|
||||
13
src/qr.rs
13
src/qr.rs
@@ -161,6 +161,19 @@ pub async fn check_qr(context: &Context, qr: &str) -> Result<Qr> {
|
||||
Ok(qrcode)
|
||||
}
|
||||
|
||||
/// Formats the text of the [`Qr::Backup`] variant.
|
||||
///
|
||||
/// This is the inverse of [`check_qr`] for that variant only.
|
||||
///
|
||||
/// TODO: Refactor this so all variants have a correct [`Display`] and transform `check_qr`
|
||||
/// into [`FromStr`].
|
||||
pub fn format_backup(qr: Qr) -> Result<String> {
|
||||
match qr {
|
||||
Qr::Backup { ticket } => Ok(format!("{DCBACKUP_SCHEME}{ticket}")),
|
||||
_ => Err(anyhow!("Not a backup QR code")),
|
||||
}
|
||||
}
|
||||
|
||||
/// scheme: `OPENPGP4FPR:FINGERPRINT#a=ADDR&n=NAME&i=INVITENUMBER&s=AUTH`
|
||||
/// or: `OPENPGP4FPR:FINGERPRINT#a=ADDR&g=GROUPNAME&x=GROUPID&i=INVITENUMBER&s=AUTH`
|
||||
/// or: `OPENPGP4FPR:FINGERPRINT#a=ADDR`
|
||||
|
||||
Reference in New Issue
Block a user