Compare commits

...

13 Commits

Author SHA1 Message Date
link2xt
80f59b3ff0 WIP attempt to parse List-Id header 2023-05-16 15:33:02 +00:00
link2xt
5bdc3cefb7 fix: handle quote marks in the List-Id when setting chat name 2023-05-16 15:32:43 +00:00
link2xt
2e6f98f4e4 api: add dc_jsonrpc_blocking_call() 2023-05-15 19:55:13 +00:00
link2xt
50431d8cfe build(git-cliff): add "Documentation" section 2023-05-15 15:34:16 +00:00
link2xt
55fcd589db build(git-cliff): put "ci" commits into "CI" section of changelog 2023-05-15 15:34:16 +00:00
link2xt
081178d623 ci(mergeable): allow PR titles to start with "ci" and "build" 2023-05-15 15:34:16 +00:00
link2xt
92d5857150 build(git-cliff): update the link to configuration documentation 2023-05-15 15:34:16 +00:00
link2xt
bb45c249a3 build(git-cliff): add unconventional commits to "Other" section 2023-05-15 15:34:16 +00:00
link2xt
8796e0472a build(git-cliff): add scope to changelog entries 2023-05-15 15:34:16 +00:00
link2xt
3bd16ba045 build(git-cliff): add "Build system" section 2023-05-15 15:34:16 +00:00
link2xt
4b7ff6f003 build(git-cliff): add period at the end of changelog entry titles
Make it consistent with the rest of the changelog.
2023-05-15 15:34:16 +00:00
link2xt
53449ea5b3 build(git-cliff): remove git-cliff footer 2023-05-15 15:34:16 +00:00
link2xt
3b381c4862 docs: update instructions for python devenv 2023-05-15 15:33:26 +00:00
12 changed files with 129 additions and 19 deletions

View File

@@ -5,7 +5,7 @@ mergeable:
validate:
- do: title
begins_with:
match: ['feat', 'fix', 'api', 'refactor', 'perf', 'test', 'style', 'chore', 'cargo']
match: ['feat', 'fix', 'api', 'refactor', 'perf', 'test', 'style', 'chore', 'cargo', 'build', 'ci']
fail:
- do: checks

5
Cargo.lock generated
View File

@@ -1295,6 +1295,7 @@ dependencies = [
"serde_json",
"thiserror",
"tokio",
"yerpc",
]
[[package]]
@@ -5754,9 +5755,9 @@ dependencies = [
[[package]]
name = "yerpc"
version = "0.4.3"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6a0257f42e6bdc187f37074723b6094da3502cee21ae517b3c54d2c37d506e7"
checksum = "b2c26a804eaa30c1ff1a296dc6dd1a7d7c622750dafcd0d6b2ed5e3c5c3beb22"
dependencies = [
"anyhow",
"async-channel",

View File

@@ -1,12 +1,12 @@
# configuration file for git-cliff
# see https://github.com/orhun/git-cliff#configuration-file
# see https://git-cliff.org/docs/configuration/
[git]
# parse the commits based on https://www.conventionalcommits.org
conventional_commits = true
# filter out the commits that are not conventional
filter_unconventional = true
filter_unconventional = false
# process each line of a commit as an individual commit
split_commits = false
# regex for preprocessing the commit messages
@@ -24,6 +24,10 @@ commit_parsers = [
{ message = "^style", group = "Styling"},
{ message = "^chore\\(release\\): prepare for", skip = true},
{ message = "^chore", group = "Miscellaneous Tasks"},
{ message = "^build", group = "Build system"},
{ message = "^docs", group = "Documentation"},
{ message = "^ci", group = "CI"},
{ message = ".*", group = "Other"},
# { body = ".*security", group = "Security"},
]
# protect breaking changes from being skipped due to matching a skipping commit_parser
@@ -60,7 +64,9 @@ body = """
{% for group, commits in commits | group_by(attribute="group") %}
### {{ group | upper_first }}
{% for commit in commits %}
- {% if commit.breaking %}[**breaking**] {% endif %}{{ commit.message | upper_first }}\
- {% if commit.breaking %}[**breaking**] {% endif %}\
{% if commit.scope %}{{ commit.scope }}: {% endif %}\
{{ commit.message | upper_first }}.\
{% for footer in commit.footers %}{% if 'BREAKING CHANGE' in footer.token %}
{% raw %} {% endraw %}- {{ footer.value }}\
{% endif %}{% endfor %}\
@@ -69,7 +75,3 @@ body = """
"""
# remove the leading and trailing whitespace from the template
trim = true
# changelog footer
footer = """
<!-- generated by git-cliff -->
"""

View File

@@ -25,6 +25,7 @@ anyhow = "1"
thiserror = "1"
rand = "0.8"
once_cell = "1.17.0"
yerpc = { version = "0.4.4", features = ["anyhow_expose"] }
[features]
default = ["vendored"]

View File

@@ -5720,6 +5720,18 @@ void dc_jsonrpc_request(dc_jsonrpc_instance_t* jsonrpc_instance, const char* req
*/
char* dc_jsonrpc_next_response(dc_jsonrpc_instance_t* jsonrpc_instance);
/**
* Make a JSON-RPC call and return a response.
*
* @memberof dc_jsonrpc_instance_t
* @param jsonrpc_instance jsonrpc instance as returned from dc_jsonrpc_init().
* @param method JSON-RPC method name, e.g. `check_email_validity`.
* @param params JSON-RPC method parameters, e.g. `["alice@example.org"]`.
* @return JSON-RPC response as string, must be freed using dc_str_unref() after usage.
* On error, NULL is returned.
*/
char* dc_jsonrpc_blocking_call(dc_jsonrpc_instance_t* jsonrpc_instance, const char *method, const char *params);
/**
* @class dc_event_emitter_t
*

View File

@@ -4967,7 +4967,7 @@ pub unsafe extern "C" fn dc_accounts_get_event_emitter(
#[cfg(feature = "jsonrpc")]
mod jsonrpc {
use deltachat_jsonrpc::api::CommandApi;
use deltachat_jsonrpc::yerpc::{OutReceiver, RpcClient, RpcSession};
use deltachat_jsonrpc::yerpc::{OutReceiver, RpcClient, RpcServer, RpcSession};
use super::*;
@@ -5039,4 +5039,29 @@ mod jsonrpc {
.map(|result| serde_json::to_string(&result).unwrap_or_default().strdup())
.unwrap_or(ptr::null_mut())
}
#[no_mangle]
pub unsafe extern "C" fn dc_jsonrpc_blocking_call(
jsonrpc_instance: *mut dc_jsonrpc_instance_t,
method: *const libc::c_char,
params: *const libc::c_char,
) -> *mut libc::c_char {
if jsonrpc_instance.is_null() {
eprintln!("ignoring careless call to dc_jsonrpc_blocking_call()");
return ptr::null_mut();
}
let api = &*jsonrpc_instance;
let method = to_string_lossy(method);
let params = to_string_lossy(params);
let params: Option<yerpc::Params> = match serde_json::from_str(&params) {
Ok(params) => Some(params),
Err(_) => None,
};
let params = params.map(yerpc::Params::into_value).unwrap_or_default();
let res = block_on(api.handle.server().handle_request(method, params));
match res {
Ok(res) => res.to_string().strdup(),
Err(_) => ptr::null_mut(),
}
}
}

View File

@@ -21,7 +21,7 @@ log = "0.4"
async-channel = { version = "1.8.0" }
futures = { version = "0.3.28" }
serde_json = "1.0.96"
yerpc = { version = "0.4.3", features = ["anyhow_expose"] }
yerpc = { version = "0.4.4", features = ["anyhow_expose"] }
typescript-type-def = { version = "0.5.5", features = ["json_value"] }
tokio = { version = "1.28.0" }
sanitize-filename = "0.4"

View File

@@ -74,7 +74,9 @@ Developing the bindings
If you want to develop or debug the bindings,
you can create a testing development environment using `tox`::
tox -c python --devenv env
export DCC_RS_DEV="$PWD"
export DCC_RS_TARGET=debug
tox -c python --devenv env -e py
. env/bin/activate
Inside this environment the bindings are installed

View File

@@ -9,6 +9,7 @@ from deltachat.testplugin import (
create_dict_from_files_in_path,
write_dict_to_dir,
)
from deltachat.cutil import from_optional_dc_charpointer
# from deltachat.account import EventLogger
@@ -215,3 +216,19 @@ def test_logged_ac_process_ffi_failure(acfactory):
assert "ac_process_ffi_event" in res
assert "ZeroDivisionError" in res
assert "Traceback" in res
def test_jsonrpc_blocking_call(tmpdir):
accounts_fname = tmpdir.join("accounts")
accounts = ffi.gc(
lib.dc_accounts_new(ffi.NULL, accounts_fname.strpath.encode("ascii")),
lib.dc_accounts_unref,
)
jsonrpc = ffi.gc(lib.dc_jsonrpc_init(accounts), lib.dc_jsonrpc_unref)
res = from_optional_dc_charpointer(
lib.dc_jsonrpc_blocking_call(jsonrpc, b"check_email_validity", b'["alice@example.org"]'),
)
assert res == "true"
res = from_optional_dc_charpointer(lib.dc_jsonrpc_blocking_call(jsonrpc, b"check_email_validity", b'["alice"]'))
assert res == "false"

View File

@@ -63,6 +63,10 @@ pub(crate) struct MimeMessage {
/// Whether the From address was repeated in the signed part
/// (and we know that the signer intended to send from this address)
pub from_is_signed: bool,
/// List-Id header as defined in <https://datatracker.ietf.org/doc/html/rfc2919>.
pub list_id: Option<SingleInfo>,
pub list_post: Option<String>,
pub chat_disposition_notification_to: Option<SingleInfo>,
pub decryption_info: DecryptionInfo,
@@ -212,6 +216,7 @@ impl MimeMessage {
let mut headers = Default::default();
let mut recipients = Default::default();
let mut from = Default::default();
let mut list_id = Default::default();
let mut list_post = Default::default();
let mut chat_disposition_notification_to = None;
@@ -221,6 +226,7 @@ impl MimeMessage {
&mut headers,
&mut recipients,
&mut from,
&mut list_id,
&mut list_post,
&mut chat_disposition_notification_to,
&mail.headers,
@@ -239,6 +245,7 @@ impl MimeMessage {
&mut headers,
&mut recipients,
&mut from,
&mut list_id,
&mut list_post,
&mut chat_disposition_notification_to,
&part.headers,
@@ -344,6 +351,7 @@ impl MimeMessage {
&mut headers,
&mut recipients,
&mut signed_from,
&mut list_id,
&mut list_post,
&mut chat_disposition_notification_to,
&mail.headers,
@@ -386,6 +394,7 @@ impl MimeMessage {
parts: Vec::new(),
header: headers,
recipients,
list_id,
list_post,
from,
from_is_signed,
@@ -1375,6 +1384,7 @@ impl MimeMessage {
headers: &mut HashMap<String, String>,
recipients: &mut Vec<SingleInfo>,
from: &mut Option<SingleInfo>,
list_id: &mut Option<SingleInfo>,
list_post: &mut Option<String>,
chat_disposition_notification_to: &mut Option<SingleInfo>,
fields: &[mailparse::MailHeader<'_>],
@@ -1392,6 +1402,14 @@ impl MimeMessage {
}
Err(e) => warn!(context, "Could not read {} address: {}", key, e),
}
} else if key == HeaderDef::ListId.get_headername() {
match addrparse_header(field) {
Ok(addrlist) => {
*list_id = addrlist.extract_single_info();
}
Err(e) => warn!(context, "Could not read {} address: {}", key, e),
}
eprintln!("LIST ID parsed as {:?}", *list_id);
} else {
let value = field.get_value();
headers.insert(key.to_string(), value);

View File

@@ -5,7 +5,7 @@ use std::collections::HashSet;
use std::convert::TryFrom;
use anyhow::{bail, ensure, Context as _, Result};
use mailparse::{parse_mail, SingleInfo};
use mailparse::{addrparse, parse_mail, SingleInfo};
use num_traits::FromPrimitive;
use once_cell::sync::Lazy;
use regex::Regex;
@@ -1835,15 +1835,23 @@ async fn create_or_lookup_mailinglist(
mime_parser: &MimeMessage,
) -> Result<Option<(ChatId, Blocked)>> {
static LIST_ID: Lazy<Regex> = Lazy::new(|| Regex::new(r"^(.+)<(.+)>$").unwrap());
eprintln!("List ID is {list_id_header:?}");
let (mut name, listid) = match LIST_ID.captures(list_id_header) {
Some(cap) => (cap[1].trim().to_string(), cap[2].trim().to_string()),
None => (
"".to_string(),
list_id_header
.trim()
.trim_start_matches('<')
.trim_end_matches('>')
.to_string(),
match addrparse(list_id_header)
.ok()
.and_then(|addrlist| addrlist.extract_single_info())
.and_then(|info| info.display_name)
{
Some(name) => name.clone(),
None => list_id_header
.trim()
.trim_start_matches('<')
.trim_end_matches('>')
.to_string(),
},
),
};

View File

@@ -1058,6 +1058,30 @@ async fn test_mailing_list_multiple_names_in_subject() -> Result<()> {
Ok(())
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_mailing_list_with_quotes() -> Result<()> {
let t = TestContext::new_alice().await;
receive_imf(
&t,
b"From: Foo Bar <foobar@lists.example.net>\n\
To: Alice <alice@example.org>\n\
Subject: confirm xxyyzz\n\
Message-ID: <3333@example.org>\n\
List-Id: \"Mailing list for \\\"Foo Bar\\\"\"\n\
\t<foo-bar.lists.example.net>\n\
Date: Sun, 22 Mar 2020 22:37:57 +0000\n\
\n\
hello\n",
false,
)
.await?;
let msg = t.get_last_msg().await;
let chat_id = msg.get_chat_id();
let chat = Chat::load_from_db(&t, chat_id).await?;
assert_eq!(chat.name, "Mailing list for \"Foo Bar\"");
Ok(())
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_majordomo_mailing_list() -> Result<()> {
let t = TestContext::new_alice().await;