mirror of
https://github.com/chatmail/core.git
synced 2026-09-22 13:01:21 +03:00
build: update all crates to Rust 2024 edition
Largest change is in the FFI crate.
With 2024 (but not 2021) edition unsafe code
inside unsafe functions should be marked separately
so we can mark exactly the code that is unsafe.
Some CFFI functions even have no unsafe code inside.
Most interesting change is that .strdup()
functions are not marked as unsafe anymore.
They are allocating memory and return raw pointers,
but there is nothing unsafe about it.
Only using the returned raw pointers is unsafe.
This way calls to .strdup() don't have to be marked
with unsafe{} blocks.
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "deltachat-contact-tools"
|
name = "deltachat-contact-tools"
|
||||||
version = "0.0.0" # No semver-stable versioning
|
version = "0.0.0" # No semver-stable versioning
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
description = "Contact-related tools, like parsing vcards and sanitizing name and address. Meant for internal use in the deltachat crate."
|
description = "Contact-related tools, like parsing vcards and sanitizing name and address. Meant for internal use in the deltachat crate."
|
||||||
license = "MPL-2.0"
|
license = "MPL-2.0"
|
||||||
|
|
||||||
|
|||||||
@@ -30,12 +30,12 @@
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
use anyhow::bail;
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
use anyhow::bail;
|
||||||
use regex::regex;
|
use regex::regex;
|
||||||
|
|
||||||
mod vcard;
|
mod vcard;
|
||||||
pub use vcard::{make_vcard, parse_vcard, VcardContact};
|
pub use vcard::{VcardContact, make_vcard, parse_vcard};
|
||||||
|
|
||||||
/// Valid contact address.
|
/// Valid contact address.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
|||||||
@@ -220,7 +220,10 @@ END:VCARD
|
|||||||
assert_eq!(contacts[0].addr, "bob@example.org".to_string());
|
assert_eq!(contacts[0].addr, "bob@example.org".to_string());
|
||||||
assert_eq!(contacts[0].authname, "Bob".to_string());
|
assert_eq!(contacts[0].authname, "Bob".to_string());
|
||||||
assert_eq!(contacts[0].key, None);
|
assert_eq!(contacts[0].key, None);
|
||||||
assert_eq!(contacts[0].profile_image.as_deref().unwrap(), "/9j/4AAQSkZJRgABAQAAAQABAAD/4gIoSUNDX1BST0ZJTEUAAQEAAAIYAAAAAAQwAABtbnRyUkdCIFhZWiAAAAAAAAAAAAAAAABhY3NwAAAAAAAAAAAAAAAAL8bRuAJYoZUYrI4ZY3VWwxw4Ay28AAGBISScmf/2Q==");
|
assert_eq!(
|
||||||
|
contacts[0].profile_image.as_deref().unwrap(),
|
||||||
|
"/9j/4AAQSkZJRgABAQAAAQABAAD/4gIoSUNDX1BST0ZJTEUAAQEAAAIYAAAAAAQwAABtbnRyUkdCIFhZWiAAAAAAAAAAAAAAAABhY3NwAAAAAAAAAAAAAAAAL8bRuAJYoZUYrI4ZY3VWwxw4Ay28AAGBISScmf/2Q=="
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,7 +247,10 @@ END:VCARD",
|
|||||||
assert_eq!(contacts.len(), 1);
|
assert_eq!(contacts.len(), 1);
|
||||||
assert_eq!(&contacts[0].addr, "alice@example.org");
|
assert_eq!(&contacts[0].addr, "alice@example.org");
|
||||||
assert_eq!(&contacts[0].authname, "Alice Wonderland");
|
assert_eq!(&contacts[0].authname, "Alice Wonderland");
|
||||||
assert_eq!(contacts[0].key.as_ref().unwrap(), "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
|
assert_eq!(
|
||||||
|
contacts[0].key.as_ref().unwrap(),
|
||||||
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||||
|
);
|
||||||
assert!(contacts[0].timestamp.is_err());
|
assert!(contacts[0].timestamp.is_err());
|
||||||
assert_eq!(contacts[0].profile_image, None);
|
assert_eq!(contacts[0].profile_image, None);
|
||||||
}
|
}
|
||||||
@@ -272,9 +278,15 @@ END:VCARD",
|
|||||||
assert_eq!(contacts.len(), 1);
|
assert_eq!(contacts.len(), 1);
|
||||||
assert_eq!(&contacts[0].addr, "alice@example.org");
|
assert_eq!(&contacts[0].addr, "alice@example.org");
|
||||||
assert_eq!(&contacts[0].authname, "Alice");
|
assert_eq!(&contacts[0].authname, "Alice");
|
||||||
assert_eq!(contacts[0].key.as_ref().unwrap(), "xsaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa==");
|
assert_eq!(
|
||||||
|
contacts[0].key.as_ref().unwrap(),
|
||||||
|
"xsaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa=="
|
||||||
|
);
|
||||||
assert!(contacts[0].timestamp.is_err());
|
assert!(contacts[0].timestamp.is_err());
|
||||||
assert_eq!(contacts[0].profile_image.as_ref().unwrap(), "/9aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Z");
|
assert_eq!(
|
||||||
|
contacts[0].profile_image.as_ref().unwrap(),
|
||||||
|
"/9aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Z"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
name = "deltachat_ffi"
|
name = "deltachat_ffi"
|
||||||
version = "2.58.0-dev"
|
version = "2.58.0-dev"
|
||||||
description = "Deltachat FFI"
|
description = "Deltachat FFI"
|
||||||
edition = "2018"
|
edition = "2024"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
license = "MPL-2.0"
|
license = "MPL-2.0"
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -17,13 +17,15 @@ use std::ptr;
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
unsafe fn dc_strdup(s: *const libc::c_char) -> *mut libc::c_char {
|
unsafe fn dc_strdup(s: *const libc::c_char) -> *mut libc::c_char {
|
||||||
let ret: *mut libc::c_char = if !s.is_null() {
|
unsafe {
|
||||||
libc::strdup(s)
|
let ret: *mut libc::c_char = if !s.is_null() {
|
||||||
} else {
|
libc::strdup(s)
|
||||||
libc::calloc(1, 1) as *mut libc::c_char
|
} else {
|
||||||
};
|
libc::calloc(1, 1) as *mut libc::c_char
|
||||||
assert!(!ret.is_null());
|
};
|
||||||
ret
|
assert!(!ret.is_null());
|
||||||
|
ret
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Error type for the [OsStrExt] trait
|
/// Error type for the [OsStrExt] trait
|
||||||
@@ -164,34 +166,40 @@ pub(crate) trait Strdup {
|
|||||||
/// This function will panic when the original string contains an
|
/// This function will panic when the original string contains an
|
||||||
/// interior null byte as this can not be represented in raw C
|
/// interior null byte as this can not be represented in raw C
|
||||||
/// strings.
|
/// strings.
|
||||||
unsafe fn strdup(&self) -> *mut libc::c_char;
|
fn strdup(&self) -> *mut libc::c_char;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Strdup for str {
|
impl Strdup for str {
|
||||||
unsafe fn strdup(&self) -> *mut libc::c_char {
|
fn strdup(&self) -> *mut libc::c_char {
|
||||||
let tmp = CString::new_lossy(self);
|
unsafe {
|
||||||
dc_strdup(tmp.as_ptr())
|
let tmp = CString::new_lossy(self);
|
||||||
|
dc_strdup(tmp.as_ptr())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Strdup for String {
|
impl Strdup for String {
|
||||||
unsafe fn strdup(&self) -> *mut libc::c_char {
|
fn strdup(&self) -> *mut libc::c_char {
|
||||||
let s: &str = self;
|
let s: &str = self;
|
||||||
s.strdup()
|
s.strdup()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Strdup for std::path::Path {
|
impl Strdup for std::path::Path {
|
||||||
unsafe fn strdup(&self) -> *mut libc::c_char {
|
fn strdup(&self) -> *mut libc::c_char {
|
||||||
let tmp = self.to_c_string().unwrap_or_else(|_| CString::default());
|
unsafe {
|
||||||
dc_strdup(tmp.as_ptr())
|
let tmp = self.to_c_string().unwrap_or_else(|_| CString::default());
|
||||||
|
dc_strdup(tmp.as_ptr())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Strdup for [u8] {
|
impl Strdup for [u8] {
|
||||||
unsafe fn strdup(&self) -> *mut libc::c_char {
|
fn strdup(&self) -> *mut libc::c_char {
|
||||||
let tmp = CString::new_lossy(self);
|
unsafe {
|
||||||
dc_strdup(tmp.as_ptr())
|
let tmp = CString::new_lossy(self);
|
||||||
|
dc_strdup(tmp.as_ptr())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,15 +217,15 @@ pub(crate) trait OptStrdup {
|
|||||||
/// Allocate a new raw C `*char` version of this string, or NULL.
|
/// Allocate a new raw C `*char` version of this string, or NULL.
|
||||||
///
|
///
|
||||||
/// See [Strdup::strdup] for details.
|
/// See [Strdup::strdup] for details.
|
||||||
unsafe fn strdup(&self) -> *mut libc::c_char;
|
fn strdup(&self) -> *mut libc::c_char;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: AsRef<str>> OptStrdup for Option<T> {
|
impl<T: AsRef<str>> OptStrdup for Option<T> {
|
||||||
unsafe fn strdup(&self) -> *mut libc::c_char {
|
fn strdup(&self) -> *mut libc::c_char {
|
||||||
match self {
|
match self {
|
||||||
Some(s) => {
|
Some(s) => {
|
||||||
let tmp = CString::new_lossy(s.as_ref());
|
let tmp = CString::new_lossy(s.as_ref());
|
||||||
dc_strdup(tmp.as_ptr())
|
unsafe { dc_strdup(tmp.as_ptr()) }
|
||||||
}
|
}
|
||||||
None => ptr::null_mut(),
|
None => ptr::null_mut(),
|
||||||
}
|
}
|
||||||
@@ -258,11 +266,9 @@ pub(crate) fn to_opt_string_lossy(s: *const libc::c_char) -> Option<String> {
|
|||||||
pub(crate) fn as_path<'a>(s: *const libc::c_char) -> &'a std::path::Path {
|
pub(crate) fn as_path<'a>(s: *const libc::c_char) -> &'a std::path::Path {
|
||||||
assert!(!s.is_null(), "cannot be used on null pointers");
|
assert!(!s.is_null(), "cannot be used on null pointers");
|
||||||
use std::os::unix::ffi::OsStrExt;
|
use std::os::unix::ffi::OsStrExt;
|
||||||
unsafe {
|
let c_str = unsafe { std::ffi::CStr::from_ptr(s) }.to_bytes();
|
||||||
let c_str = std::ffi::CStr::from_ptr(s).to_bytes();
|
let os_str = std::ffi::OsStr::from_bytes(c_str);
|
||||||
let os_str = std::ffi::OsStr::from_bytes(c_str);
|
std::path::Path::new(os_str)
|
||||||
std::path::Path::new(os_str)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// as_path() implementation for windows, documented above.
|
// as_path() implementation for windows, documented above.
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
name = "deltachat-jsonrpc"
|
name = "deltachat-jsonrpc"
|
||||||
version = "2.58.0-dev"
|
version = "2.58.0-dev"
|
||||||
description = "DeltaChat JSON-RPC API"
|
description = "DeltaChat JSON-RPC API"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
license = "MPL-2.0"
|
license = "MPL-2.0"
|
||||||
repository = "https://github.com/chatmail/core"
|
repository = "https://github.com/chatmail/core"
|
||||||
|
|
||||||
|
|||||||
@@ -5,26 +5,27 @@ use std::sync::Arc;
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::{collections::HashMap, str::FromStr};
|
use std::{collections::HashMap, str::FromStr};
|
||||||
|
|
||||||
use anyhow::{anyhow, bail, ensure, Context, Result};
|
use anyhow::{Context, Result, anyhow, bail, ensure};
|
||||||
|
use deltachat::EventEmitter;
|
||||||
pub use deltachat::accounts::Accounts;
|
pub use deltachat::accounts::Accounts;
|
||||||
use deltachat::blob::BlobObject;
|
use deltachat::blob::BlobObject;
|
||||||
use deltachat::calls::ice_servers;
|
use deltachat::calls::ice_servers;
|
||||||
use deltachat::chat::{
|
use deltachat::chat::{
|
||||||
self, add_contact_to_chat, forward_msgs, forward_msgs_2ctx, get_chat_media, get_chat_msgs,
|
self, Chat, ChatId, ChatItem, MessageListOptions, add_contact_to_chat, forward_msgs,
|
||||||
get_chat_msgs_ex, markfresh_chat, marknoticed_all_chats, marknoticed_chat,
|
forward_msgs_2ctx, get_chat_media, get_chat_msgs, get_chat_msgs_ex, markfresh_chat,
|
||||||
remove_contact_from_chat, Chat, ChatId, ChatItem, MessageListOptions,
|
marknoticed_all_chats, marknoticed_chat, remove_contact_from_chat,
|
||||||
};
|
};
|
||||||
use deltachat::chatlist::Chatlist;
|
use deltachat::chatlist::Chatlist;
|
||||||
use deltachat::config::{get_all_ui_config_keys, Config};
|
use deltachat::config::{Config, get_all_ui_config_keys};
|
||||||
use deltachat::constants::DC_MSG_ID_DAYMARKER;
|
use deltachat::constants::DC_MSG_ID_DAYMARKER;
|
||||||
use deltachat::contact::{may_be_valid_addr, Contact, ContactId, Origin};
|
use deltachat::contact::{Contact, ContactId, Origin, may_be_valid_addr};
|
||||||
use deltachat::context::get_info;
|
use deltachat::context::get_info;
|
||||||
use deltachat::ephemeral::Timer;
|
use deltachat::ephemeral::Timer;
|
||||||
use deltachat::imex;
|
use deltachat::imex;
|
||||||
use deltachat::location;
|
use deltachat::location;
|
||||||
use deltachat::message::{
|
use deltachat::message::{
|
||||||
self, delete_msgs_ex, get_existing_msg_ids, get_msg_read_receipt_count, get_msg_read_receipts,
|
self, Message, MessageState, MsgId, Viewtype, delete_msgs_ex, get_existing_msg_ids,
|
||||||
markseen_msgs, Message, MessageState, MsgId, Viewtype,
|
get_msg_read_receipt_count, get_msg_read_receipts, markseen_msgs,
|
||||||
};
|
};
|
||||||
use deltachat::peer_channels::{
|
use deltachat::peer_channels::{
|
||||||
leave_webxdc_realtime, send_webxdc_realtime_advertisement, send_webxdc_realtime_data,
|
leave_webxdc_realtime, send_webxdc_realtime_advertisement, send_webxdc_realtime_data,
|
||||||
@@ -36,10 +37,9 @@ use deltachat::securejoin;
|
|||||||
use deltachat::stock_str::StockMessage;
|
use deltachat::stock_str::StockMessage;
|
||||||
use deltachat::storage_usage::{get_blobdir_storage_usage, get_storage_usage};
|
use deltachat::storage_usage::{get_blobdir_storage_usage, get_storage_usage};
|
||||||
use deltachat::webxdc::StatusUpdateSerial;
|
use deltachat::webxdc::StatusUpdateSerial;
|
||||||
use deltachat::EventEmitter;
|
|
||||||
use sanitize_filename::is_sanitized;
|
use sanitize_filename::is_sanitized;
|
||||||
use tokio::fs;
|
use tokio::fs;
|
||||||
use tokio::sync::{watch, Mutex, RwLock};
|
use tokio::sync::{Mutex, RwLock, watch};
|
||||||
use types::login_param::EnteredLoginParam;
|
use types::login_param::EnteredLoginParam;
|
||||||
use yerpc::rpc;
|
use yerpc::rpc;
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ use self::types::{
|
|||||||
JsonrpcMessageListItem, MessageNotificationInfo, MessageSearchResult, MessageViewtype,
|
JsonrpcMessageListItem, MessageNotificationInfo, MessageSearchResult, MessageViewtype,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use crate::api::types::chat_list::{get_chat_list_item_by_id, ChatListItemFetchResult};
|
use crate::api::types::chat_list::{ChatListItemFetchResult, get_chat_list_item_by_id};
|
||||||
use crate::api::types::login_param::TransportListEntry;
|
use crate::api::types::login_param::TransportListEntry;
|
||||||
use crate::api::types::qr::{QrObject, SecurejoinSource, SecurejoinUiPath};
|
use crate::api::types::qr::{QrObject, SecurejoinSource, SecurejoinUiPath};
|
||||||
|
|
||||||
@@ -2278,7 +2278,7 @@ impl CommandApi {
|
|||||||
let message = Message::load_from_db(&ctx, MsgId::new(instance_msg_id)).await?;
|
let message = Message::load_from_db(&ctx, MsgId::new(instance_msg_id)).await?;
|
||||||
let blob = message.get_webxdc_blob(&ctx, &path).await?;
|
let blob = message.get_webxdc_blob(&ctx, &path).await?;
|
||||||
|
|
||||||
use base64::{engine::general_purpose, Engine as _};
|
use base64::{Engine as _, engine::general_purpose};
|
||||||
Ok(general_purpose::STANDARD_NO_PAD.encode(blob))
|
Ok(general_purpose::STANDARD_NO_PAD.encode(blob))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use anyhow::{Context as _, Result};
|
use anyhow::{Context as _, Result};
|
||||||
|
|
||||||
use deltachat::calls::{call_state, CallState};
|
use deltachat::calls::{CallState, call_state};
|
||||||
use deltachat::context::Context;
|
use deltachat::context::Context;
|
||||||
use deltachat::message::MsgId;
|
use deltachat::message::MsgId;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::time::{Duration, SystemTime};
|
use std::time::{Duration, SystemTime};
|
||||||
|
|
||||||
use anyhow::{bail, Context as _, Result};
|
use anyhow::{Context as _, Result, bail};
|
||||||
use deltachat::chat::{self, get_chat_contacts, get_past_chat_contacts, ChatVisibility};
|
use deltachat::chat::{self, ChatVisibility, get_chat_contacts, get_past_chat_contacts};
|
||||||
use deltachat::chat::{Chat, ChatId};
|
use deltachat::chat::{Chat, ChatId};
|
||||||
use deltachat::constants::Chattype;
|
use deltachat::constants::Chattype;
|
||||||
use deltachat::contact::{Contact, ContactId};
|
use deltachat::contact::{Contact, ContactId};
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use deltachat::chatlist::get_last_message_for_chat;
|
|||||||
use deltachat::constants::*;
|
use deltachat::constants::*;
|
||||||
use deltachat::contact::Contact;
|
use deltachat::contact::Contact;
|
||||||
use deltachat::{
|
use deltachat::{
|
||||||
chat::{get_chat_contacts, ChatVisibility},
|
chat::{ChatVisibility, get_chat_contacts},
|
||||||
chatlist::Chatlist,
|
chatlist::Chatlist,
|
||||||
};
|
};
|
||||||
use num_traits::cast::ToPrimitive;
|
use num_traits::cast::ToPrimitive;
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ pub struct HttpResponse {
|
|||||||
|
|
||||||
impl From<CoreHttpResponse> for HttpResponse {
|
impl From<CoreHttpResponse> for HttpResponse {
|
||||||
fn from(response: CoreHttpResponse) -> Self {
|
fn from(response: CoreHttpResponse) -> Self {
|
||||||
use base64::{engine::general_purpose, Engine as _};
|
use base64::{Engine as _, engine::general_purpose};
|
||||||
let blob = general_purpose::STANDARD_NO_PAD.encode(response.blob);
|
let blob = general_purpose::STANDARD_NO_PAD.encode(response.blob);
|
||||||
let mimetype = response.mimetype;
|
let mimetype = response.mimetype;
|
||||||
let encoding = response.encoding;
|
let encoding = response.encoding;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
name = "ratelimit"
|
name = "ratelimit"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
description = "Token bucket implementation"
|
description = "Token bucket implementation"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
license = "MPL-2.0"
|
license = "MPL-2.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
name = "deltachat-repl"
|
name = "deltachat-repl"
|
||||||
version = "2.58.0-dev"
|
version = "2.58.0-dev"
|
||||||
license = "MPL-2.0"
|
license = "MPL-2.0"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
repository = "https://github.com/chatmail/core"
|
repository = "https://github.com/chatmail/core"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use std::path::Path;
|
|||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use anyhow::{bail, ensure, Result};
|
use anyhow::{Result, bail, ensure};
|
||||||
use deltachat::chat::{self, Chat, ChatId, ChatItem, ChatVisibility, MuteDuration};
|
use deltachat::chat::{self, Chat, ChatId, ChatItem, ChatVisibility, MuteDuration};
|
||||||
use deltachat::chatlist::*;
|
use deltachat::chatlist::*;
|
||||||
use deltachat::config;
|
use deltachat::config;
|
||||||
@@ -1206,12 +1206,11 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu
|
|||||||
"fileinfo" => {
|
"fileinfo" => {
|
||||||
ensure!(!arg1.is_empty(), "Argument <file> missing.");
|
ensure!(!arg1.is_empty(), "Argument <file> missing.");
|
||||||
|
|
||||||
if let Ok(buf) = read_file(&context, Path::new(arg1)).await {
|
let Ok(buf) = read_file(&context, Path::new(arg1)).await else {
|
||||||
let (width, height) = get_filemeta(&buf)?;
|
|
||||||
println!("width={width}, height={height}");
|
|
||||||
} else {
|
|
||||||
bail!("Command failed.");
|
bail!("Command failed.");
|
||||||
}
|
};
|
||||||
|
let (width, height) = get_filemeta(&buf)?;
|
||||||
|
println!("width={width}, height={height}");
|
||||||
}
|
}
|
||||||
"estimatedeletion" => {
|
"estimatedeletion" => {
|
||||||
ensure!(!arg1.is_empty(), "Argument <seconds> missing");
|
ensure!(!arg1.is_empty(), "Argument <seconds> missing");
|
||||||
|
|||||||
@@ -9,12 +9,12 @@ extern crate deltachat;
|
|||||||
|
|
||||||
use std::borrow::Cow::{self, Borrowed, Owned};
|
use std::borrow::Cow::{self, Borrowed, Owned};
|
||||||
|
|
||||||
use anyhow::{bail, Error};
|
use anyhow::{Error, bail};
|
||||||
|
use deltachat::EventType;
|
||||||
use deltachat::chat::ChatId;
|
use deltachat::chat::ChatId;
|
||||||
use deltachat::context::*;
|
use deltachat::context::*;
|
||||||
use deltachat::qr_code_generator::get_securejoin_qr_svg;
|
use deltachat::qr_code_generator::get_securejoin_qr_svg;
|
||||||
use deltachat::securejoin::*;
|
use deltachat::securejoin::*;
|
||||||
use deltachat::EventType;
|
|
||||||
use log::{error, info, warn};
|
use log::{error, info, warn};
|
||||||
use nu_ansi_term::Color;
|
use nu_ansi_term::Color;
|
||||||
use rustyline::completion::{Completer, FilenameCompleter, Pair};
|
use rustyline::completion::{Completer, FilenameCompleter, Pair};
|
||||||
@@ -266,10 +266,11 @@ impl Hinter for DcHelper {
|
|||||||
&CONTACT_COMMANDS[..],
|
&CONTACT_COMMANDS[..],
|
||||||
&MISC_COMMANDS[..],
|
&MISC_COMMANDS[..],
|
||||||
] {
|
] {
|
||||||
if let Some(entry) = cmds.iter().find(|el| el.starts_with(&line[..pos])) {
|
if let Some(entry) = cmds.iter().find(|el| el.starts_with(&line[..pos]))
|
||||||
if *entry != line && *entry != &line[..pos] {
|
&& *entry != line
|
||||||
return Some(entry[pos..].to_owned());
|
&& *entry != &line[..pos]
|
||||||
}
|
{
|
||||||
|
return Some(entry[pos..].to_owned());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
name = "deltachat-rpc-server"
|
name = "deltachat-rpc-server"
|
||||||
version = "2.58.0-dev"
|
version = "2.58.0-dev"
|
||||||
description = "DeltaChat JSON-RPC server"
|
description = "DeltaChat JSON-RPC server"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
license = "MPL-2.0"
|
license = "MPL-2.0"
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use std::env;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use anyhow::{anyhow, Context as _, Result};
|
use anyhow::{Context as _, Result, anyhow};
|
||||||
use deltachat::constants::DC_VERSION_STR;
|
use deltachat::constants::DC_VERSION_STR;
|
||||||
use deltachat_jsonrpc::api::{Accounts, CommandApi};
|
use deltachat_jsonrpc::api::{Accounts, CommandApi};
|
||||||
use futures_lite::stream::StreamExt;
|
use futures_lite::stream::StreamExt;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
name = "deltachat-time"
|
name = "deltachat-time"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
description = "Time-related tools"
|
description = "Time-related tools"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
license = "MPL-2.0"
|
license = "MPL-2.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "deltachat_derive"
|
name = "deltachat_derive"
|
||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
edition = "2018"
|
edition = "2024"
|
||||||
license = "MPL-2.0"
|
license = "MPL-2.0"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ pub fn to_sql_derive(input: TokenStream) -> TokenStream {
|
|||||||
let ast: syn::DeriveInput = syn::parse(input).unwrap();
|
let ast: syn::DeriveInput = syn::parse(input).unwrap();
|
||||||
let name = &ast.ident;
|
let name = &ast.ident;
|
||||||
|
|
||||||
let gen = quote! {
|
let q = quote! {
|
||||||
impl rusqlite::types::ToSql for #name {
|
impl rusqlite::types::ToSql for #name {
|
||||||
fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput> {
|
fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput> {
|
||||||
let num = *self as i64;
|
let num = *self as i64;
|
||||||
@@ -24,7 +24,7 @@ pub fn to_sql_derive(input: TokenStream) -> TokenStream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
gen.into()
|
q.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro_derive(FromSql)]
|
#[proc_macro_derive(FromSql)]
|
||||||
@@ -32,7 +32,7 @@ pub fn from_sql_derive(input: TokenStream) -> TokenStream {
|
|||||||
let ast: syn::DeriveInput = syn::parse(input).unwrap();
|
let ast: syn::DeriveInput = syn::parse(input).unwrap();
|
||||||
let name = &ast.ident;
|
let name = &ast.ident;
|
||||||
|
|
||||||
let gen = quote! {
|
let q = quote! {
|
||||||
impl rusqlite::types::FromSql for #name {
|
impl rusqlite::types::FromSql for #name {
|
||||||
fn column_result(col: rusqlite::types::ValueRef) -> rusqlite::types::FromSqlResult<Self> {
|
fn column_result(col: rusqlite::types::ValueRef) -> rusqlite::types::FromSqlResult<Self> {
|
||||||
let inner = rusqlite::types::FromSql::column_result(col)?;
|
let inner = rusqlite::types::FromSql::column_result(col)?;
|
||||||
@@ -44,5 +44,5 @@ pub fn from_sql_derive(input: TokenStream) -> TokenStream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
gen.into()
|
q.into()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
name = "format-flowed"
|
name = "format-flowed"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
description = "format=flowed support"
|
description = "format=flowed support"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
license = "MPL-2.0"
|
license = "MPL-2.0"
|
||||||
|
|
||||||
keywords = ["email"]
|
keywords = ["email"]
|
||||||
|
|||||||
@@ -78,11 +78,11 @@ pub fn format_flowed(text: &str) -> String {
|
|||||||
|
|
||||||
let mut prefix = prefix.to_string();
|
let mut prefix = prefix.to_string();
|
||||||
|
|
||||||
if quote_depth > 0 {
|
if quote_depth > 0
|
||||||
if let Some(s) = line.strip_prefix(' ') {
|
&& let Some(s) = line.strip_prefix(' ')
|
||||||
line = s;
|
{
|
||||||
prefix += " ";
|
line = s;
|
||||||
}
|
prefix += " ";
|
||||||
}
|
}
|
||||||
|
|
||||||
result += &format_line_flowed(line, &prefix);
|
result += &format_line_flowed(line, &prefix);
|
||||||
@@ -224,8 +224,7 @@ mod tests {
|
|||||||
fn test_unformat_flowed() {
|
fn test_unformat_flowed() {
|
||||||
let text = "this is a very long message that should be wrapped using format=flowed and \n\
|
let text = "this is a very long message that should be wrapped using format=flowed and \n\
|
||||||
unwrapped on the receiver";
|
unwrapped on the receiver";
|
||||||
let expected =
|
let expected = "this is a very long message that should be wrapped using format=flowed and \
|
||||||
"this is a very long message that should be wrapped using format=flowed and \
|
|
||||||
unwrapped on the receiver";
|
unwrapped on the receiver";
|
||||||
assert_eq!(unformat_flowed(text, false), expected);
|
assert_eq!(unformat_flowed(text, false), expected);
|
||||||
|
|
||||||
@@ -255,8 +254,7 @@ mod tests {
|
|||||||
assert_eq!(format_flowed_quote(quote), expected);
|
assert_eq!(format_flowed_quote(quote), expected);
|
||||||
|
|
||||||
let quote = "this is a very long quote that should be wrapped using format=flowed and unwrapped on the receiver";
|
let quote = "this is a very long quote that should be wrapped using format=flowed and unwrapped on the receiver";
|
||||||
let expected =
|
let expected = "> this is a very long quote that should be wrapped using format=flowed and \r\n\
|
||||||
"> this is a very long quote that should be wrapped using format=flowed and \r\n\
|
|
||||||
> unwrapped on the receiver";
|
> unwrapped on the receiver";
|
||||||
assert_eq!(format_flowed_quote(quote), expected);
|
assert_eq!(format_flowed_quote(quote), expected);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
name = "deltachat-fuzz"
|
name = "deltachat-fuzz"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
publish = false
|
publish = false
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
license = "MPL-2.0"
|
license = "MPL-2.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|||||||
Reference in New Issue
Block a user