mirror of
https://github.com/chatmail/core.git
synced 2026-05-09 01:46:30 +03:00
add API to create QR codes from any data
This commit is contained in:
@@ -2791,6 +2791,22 @@ dc_array_t* dc_get_locations (dc_context_t* context, uint32_t cha
|
|||||||
void dc_delete_all_locations (dc_context_t* context);
|
void dc_delete_all_locations (dc_context_t* context);
|
||||||
|
|
||||||
|
|
||||||
|
// misc
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a QR code from any input data.
|
||||||
|
*
|
||||||
|
* The QR code is returned as a square SVG image.
|
||||||
|
*
|
||||||
|
* @memberof dc_context_t
|
||||||
|
* @param payload The content for the QR code.
|
||||||
|
* @return SVG image with the QR code.
|
||||||
|
* On errors, an empty string is returned.
|
||||||
|
* The returned string must be released using dc_str_unref() after usage.
|
||||||
|
*/
|
||||||
|
char* dc_create_qr_svg (const char* payload);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get last error string.
|
* Get last error string.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ use deltachat::ephemeral::Timer as EphemeralTimer;
|
|||||||
use deltachat::imex::BackupProvider;
|
use deltachat::imex::BackupProvider;
|
||||||
use deltachat::key::preconfigure_keypair;
|
use deltachat::key::preconfigure_keypair;
|
||||||
use deltachat::message::MsgId;
|
use deltachat::message::MsgId;
|
||||||
use deltachat::qr_code_generator::{generate_backup_qr, get_securejoin_qr_svg};
|
use deltachat::qr_code_generator::{create_qr_svg, generate_backup_qr, get_securejoin_qr_svg};
|
||||||
use deltachat::stock_str::StockMessage;
|
use deltachat::stock_str::StockMessage;
|
||||||
use deltachat::webxdc::StatusUpdateSerial;
|
use deltachat::webxdc::StatusUpdateSerial;
|
||||||
use deltachat::*;
|
use deltachat::*;
|
||||||
@@ -2594,6 +2594,18 @@ pub unsafe extern "C" fn dc_delete_all_locations(context: *mut dc_context_t) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn dc_create_qr_svg(payload: *const libc::c_char) -> *mut libc::c_char {
|
||||||
|
if payload.is_null() {
|
||||||
|
eprintln!("ignoring careless call to dc_create_qr_svg()");
|
||||||
|
return "".strdup();
|
||||||
|
}
|
||||||
|
|
||||||
|
create_qr_svg(&to_string_lossy(payload))
|
||||||
|
.unwrap_or_else(|_| "".to_string())
|
||||||
|
.strdup()
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn dc_get_last_error(context: *mut dc_context_t) -> *mut libc::c_char {
|
pub unsafe extern "C" fn dc_get_last_error(context: *mut dc_context_t) -> *mut libc::c_char {
|
||||||
if context.is_null() {
|
if context.is_null() {
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ use deltachat::mimeparser::SystemMessage;
|
|||||||
use deltachat::peer_channels::{send_webxdc_realtime_advertisement, send_webxdc_realtime_data};
|
use deltachat::peer_channels::{send_webxdc_realtime_advertisement, send_webxdc_realtime_data};
|
||||||
use deltachat::peerstate::*;
|
use deltachat::peerstate::*;
|
||||||
use deltachat::qr::*;
|
use deltachat::qr::*;
|
||||||
|
use deltachat::qr_code_generator::create_qr_svg;
|
||||||
use deltachat::reaction::send_reaction;
|
use deltachat::reaction::send_reaction;
|
||||||
use deltachat::receive_imf::*;
|
use deltachat::receive_imf::*;
|
||||||
use deltachat::sql;
|
use deltachat::sql;
|
||||||
@@ -425,6 +426,7 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu
|
|||||||
checkqr <qr-content>\n\
|
checkqr <qr-content>\n\
|
||||||
joinqr <qr-content>\n\
|
joinqr <qr-content>\n\
|
||||||
setqr <qr-content>\n\
|
setqr <qr-content>\n\
|
||||||
|
createqrsvg <qr-content>\n\
|
||||||
providerinfo <addr>\n\
|
providerinfo <addr>\n\
|
||||||
fileinfo <file>\n\
|
fileinfo <file>\n\
|
||||||
estimatedeletion <seconds>\n\
|
estimatedeletion <seconds>\n\
|
||||||
@@ -1249,6 +1251,13 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu
|
|||||||
Err(err) => println!("Cannot set config from QR code: {err:?}"),
|
Err(err) => println!("Cannot set config from QR code: {err:?}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
"createqrsvg" => {
|
||||||
|
ensure!(!arg1.is_empty(), "Argument <qr-content> missing.");
|
||||||
|
let svg = create_qr_svg(arg1)?;
|
||||||
|
let file = dirs::home_dir().unwrap_or_default().join("qr.svg");
|
||||||
|
fs::write(&file, svg).await?;
|
||||||
|
println!("{file:#?} written.");
|
||||||
|
}
|
||||||
"providerinfo" => {
|
"providerinfo" => {
|
||||||
ensure!(!arg1.is_empty(), "Argument <addr> missing.");
|
ensure!(!arg1.is_empty(), "Argument <addr> missing.");
|
||||||
let proxy_enabled = context
|
let proxy_enabled = context
|
||||||
|
|||||||
@@ -240,12 +240,13 @@ const CONTACT_COMMANDS: [&str; 9] = [
|
|||||||
"unblock",
|
"unblock",
|
||||||
"listblocked",
|
"listblocked",
|
||||||
];
|
];
|
||||||
const MISC_COMMANDS: [&str; 11] = [
|
const MISC_COMMANDS: [&str; 12] = [
|
||||||
"getqr",
|
"getqr",
|
||||||
"getqrsvg",
|
"getqrsvg",
|
||||||
"getbadqr",
|
"getbadqr",
|
||||||
"checkqr",
|
"checkqr",
|
||||||
"joinqr",
|
"joinqr",
|
||||||
|
"createqrsvg",
|
||||||
"fileinfo",
|
"fileinfo",
|
||||||
"clear",
|
"clear",
|
||||||
"exit",
|
"exit",
|
||||||
|
|||||||
@@ -14,6 +14,65 @@ use crate::qr::{self, Qr};
|
|||||||
use crate::securejoin;
|
use crate::securejoin;
|
||||||
use crate::stock_str::{self, backup_transfer_qr};
|
use crate::stock_str::{self, backup_transfer_qr};
|
||||||
|
|
||||||
|
/// Create a QR code from any input data.
|
||||||
|
pub fn create_qr_svg(qrcode_content: &str) -> Result<String> {
|
||||||
|
let all_size = 512.0;
|
||||||
|
let qr_code_size = 416.0;
|
||||||
|
|
||||||
|
let qr = QrCode::encode_text(qrcode_content, QrCodeEcc::Medium)?;
|
||||||
|
let mut svg = String::with_capacity(28000);
|
||||||
|
let mut w = tagger::new(&mut svg);
|
||||||
|
|
||||||
|
w.elem("svg", |d| {
|
||||||
|
d.attr("xmlns", "http://www.w3.org/2000/svg")?;
|
||||||
|
d.attr("viewBox", format_args!("0 0 {all_size} {all_size}"))?;
|
||||||
|
d.attr("xmlns:xlink", "http://www.w3.org/1999/xlink")?; // required for enabling xlink:href on browsers
|
||||||
|
Ok(())
|
||||||
|
})?
|
||||||
|
.build(|w| {
|
||||||
|
// background
|
||||||
|
w.single("rect", |d| {
|
||||||
|
d.attr("x", 0)?;
|
||||||
|
d.attr("y", 0)?;
|
||||||
|
d.attr("width", all_size)?;
|
||||||
|
d.attr("height", all_size)?;
|
||||||
|
d.attr("style", "fill:#ffffff")?;
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
// QR code
|
||||||
|
w.elem("g", |d| {
|
||||||
|
d.attr(
|
||||||
|
"transform",
|
||||||
|
format!(
|
||||||
|
"translate({},{})",
|
||||||
|
(all_size - qr_code_size) / 2.0,
|
||||||
|
((all_size - qr_code_size) / 2.0)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
})?
|
||||||
|
.build(|w| {
|
||||||
|
w.single("path", |d| {
|
||||||
|
let mut path_data = String::with_capacity(0);
|
||||||
|
let scale = qr_code_size / qr.size() as f32;
|
||||||
|
|
||||||
|
for y in 0..qr.size() {
|
||||||
|
for x in 0..qr.size() {
|
||||||
|
if qr.get_module(x, y) {
|
||||||
|
path_data += &format!("M{x},{y}h1v1h-1z");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
d.attr("style", "fill:#000000")?;
|
||||||
|
d.attr("d", path_data)?;
|
||||||
|
d.attr("transform", format!("scale({scale})"))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(svg)
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns SVG of the QR code to join the group or verify contact.
|
/// Returns SVG of the QR code to join the group or verify contact.
|
||||||
///
|
///
|
||||||
/// If `chat_id` is `None`, returns verification QR code.
|
/// If `chat_id` is `None`, returns verification QR code.
|
||||||
|
|||||||
Reference in New Issue
Block a user