mirror of
https://github.com/chatmail/core.git
synced 2026-05-25 01:36:31 +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",
|
"rusqlite/bundled-sqlcipher-vendored-openssl",
|
||||||
"reqwest/native-tls-vendored"
|
"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 dc_event_t;
|
||||||
typedef struct _dc_event_emitter dc_event_emitter_t;
|
typedef struct _dc_event_emitter dc_event_emitter_t;
|
||||||
typedef struct _dc_jsonrpc_instance dc_jsonrpc_instance_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.
|
// Alias for backwards compatibility, use dc_event_emitter_t instead.
|
||||||
typedef struct _dc_event_emitter dc_accounts_event_emitter_t;
|
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_MISMATCH 220 // id=contact
|
||||||
#define DC_QR_FPR_WITHOUT_ADDR 230 // test1=formatted fingerprint
|
#define DC_QR_FPR_WITHOUT_ADDR 230 // test1=formatted fingerprint
|
||||||
#define DC_QR_ACCOUNT 250 // text1=domain
|
#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_WEBRTC_INSTANCE 260 // text1=domain, text2=instance pattern
|
||||||
#define DC_QR_ADDR 320 // id=contact
|
#define DC_QR_ADDR 320 // id=contact
|
||||||
#define DC_QR_TEXT 330 // text1=text
|
#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);
|
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
|
* @class dc_accounts_t
|
||||||
|
|||||||
@@ -28,9 +28,10 @@ use deltachat::constants::DC_MSG_ID_LAST_SPECIAL;
|
|||||||
use deltachat::contact::{Contact, ContactId, Origin};
|
use deltachat::contact::{Contact, ContactId, Origin};
|
||||||
use deltachat::context::Context;
|
use deltachat::context::Context;
|
||||||
use deltachat::ephemeral::Timer as EphemeralTimer;
|
use deltachat::ephemeral::Timer as EphemeralTimer;
|
||||||
|
use deltachat::imex::BackupProvider;
|
||||||
use deltachat::key::DcKey;
|
use deltachat::key::DcKey;
|
||||||
use deltachat::message::MsgId;
|
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::reaction::{get_msg_reactions, send_reaction, Reactions};
|
||||||
use deltachat::stock_str::StockMessage;
|
use deltachat::stock_str::StockMessage;
|
||||||
use deltachat::stock_str::StockStrings;
|
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 _)
|
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> {
|
trait ResultExt<T, E> {
|
||||||
/// Like `log_err()`, but:
|
/// Like `log_err()`, but:
|
||||||
/// - returns the default value instead of an Err value.
|
/// - 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)
|
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`
|
/// 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&g=GROUPNAME&x=GROUPID&i=INVITENUMBER&s=AUTH`
|
||||||
/// or: `OPENPGP4FPR:FINGERPRINT#a=ADDR`
|
/// or: `OPENPGP4FPR:FINGERPRINT#a=ADDR`
|
||||||
|
|||||||
Reference in New Issue
Block a user