mirror of
https://github.com/chatmail/core.git
synced 2026-04-17 13:36:30 +03:00
Merge pull request #1207 from deltachat/provider-db
streamline provider-db
This commit is contained in:
28
Cargo.lock
generated
28
Cargo.lock
generated
@@ -685,17 +685,6 @@ dependencies = [
|
||||
"thread-local-object 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deltachat-provider-database"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deltachat_derive"
|
||||
version = "2.0.0"
|
||||
@@ -709,7 +698,6 @@ name = "deltachat_ffi"
|
||||
version = "1.0.0-beta.24"
|
||||
dependencies = [
|
||||
"deltachat 1.0.0-beta.24",
|
||||
"deltachat-provider-database 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"human-panic 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1167,11 +1155,6 @@ name = "glob"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.2.1"
|
||||
@@ -3258,14 +3241,6 @@ dependencies = [
|
||||
"zeroize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yaml-rust"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.1.0"
|
||||
@@ -3359,7 +3334,6 @@ dependencies = [
|
||||
"checksum darling_macro 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72"
|
||||
"checksum debug_stub_derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "496b7f8a2f853313c3ca370641d7ff3e42c32974fdccda8f0684599ed0a3ff6b"
|
||||
"checksum deflate 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)" = "707b6a7b384888a70c8d2e8650b3e60170dfc6a67bb4aa67b6dfca57af4bedb4"
|
||||
"checksum deltachat-provider-database 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "814dba060d9fdc7a989fccdc4810ada9d1c7a1f09131c78e42412bc6c634b93b"
|
||||
"checksum derive_builder 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a2658621297f2cf68762a6f7dc0bb7e1ff2cfd6583daef8ee0fed6f7ec468ec0"
|
||||
"checksum derive_builder_core 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2791ea3e372c8495c0bc2033991d76b512cd799d07491fbd6890124db9458bef"
|
||||
"checksum des 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "74ba5f1b5aee9772379c2670ba81306e65a93c0ee3caade7a1d22b188d88a3af"
|
||||
@@ -3415,7 +3389,6 @@ dependencies = [
|
||||
"checksum getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e7db7ca94ed4cd01190ceee0d8a8052f08a247aa1b469a7f68c6a3b71afcf407"
|
||||
"checksum gif 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)" = "471d90201b3b223f3451cd4ad53e34295f16a1df17b1edf3736d47761c3981af"
|
||||
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
|
||||
"checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||
"checksum h2 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b9433d71e471c1736fd5a61b671fc0b148d7a2992f666c958d03cd8feb3b88d1"
|
||||
"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
|
||||
"checksum hermit-abi 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f629dc602392d3ec14bfc8a09b5e644d7ffd725102b48b81e59f90f2633621d7"
|
||||
@@ -3648,6 +3621,5 @@ dependencies = [
|
||||
"checksum winutil 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7daf138b6b14196e3830a588acf1e86966c694d3e8fb026fb105b8b5dca07e6e"
|
||||
"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
|
||||
"checksum x25519-dalek 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "637ff90c9540fa3073bb577e65033069e4bae7c79d49d74aa3ffdf5342a53217"
|
||||
"checksum yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "65923dd1784f44da1d2c3dbbc5e822045628c590ba72123e1c73d3c230c4434d"
|
||||
"checksum zeroize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3cbac2ed2ba24cc90f5e06485ac8c7c1e5449fe8911aef4d8877218af021a5b8"
|
||||
"checksum zeroize_derive 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de251eec69fc7c1bc3923403d18ececb929380e016afe103da75f396704f8ca2"
|
||||
|
||||
@@ -16,7 +16,6 @@ crate-type = ["cdylib", "staticlib"]
|
||||
|
||||
[dependencies]
|
||||
deltachat = { path = "../", default-features = false }
|
||||
deltachat-provider-database = "0.2.1"
|
||||
libc = "0.2"
|
||||
human-panic = "1.0.1"
|
||||
num-traits = "0.2.6"
|
||||
|
||||
@@ -3686,30 +3686,19 @@ int dc_contact_is_verified (dc_contact_t* contact);
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Create a provider struct for the given domain.
|
||||
*
|
||||
* @memberof dc_provider_t
|
||||
* @param domain The domain to get provider info for.
|
||||
* @return a dc_provider_t struct which can be used with the dc_provider_get_*
|
||||
* accessor functions. If no provider info is found, NULL will be
|
||||
* returned.
|
||||
*/
|
||||
dc_provider_t* dc_provider_new_from_domain (const char* domain);
|
||||
|
||||
|
||||
/**
|
||||
* Create a provider struct for the given email address.
|
||||
*
|
||||
* The provider is extracted from the email address and it's information is returned.
|
||||
*
|
||||
* @memberof dc_provider_t
|
||||
* @param context The context object as created by dc_context_new().
|
||||
* @param email The user's email address to extract the provider info form.
|
||||
* @return a dc_provider_t struct which can be used with the dc_provider_get_*
|
||||
* accessor functions. If no provider info is found, NULL will be
|
||||
* returned.
|
||||
*/
|
||||
dc_provider_t* dc_provider_new_from_email (const char* email);
|
||||
dc_provider_t* dc_provider_new_from_email (const dc_context_t*, const char* email);
|
||||
|
||||
|
||||
/**
|
||||
@@ -3719,53 +3708,35 @@ dc_provider_t* dc_provider_new_from_email (const char* email);
|
||||
*
|
||||
* @memberof dc_provider_t
|
||||
* @param provider The dc_provider_t struct.
|
||||
* @return A string which must be released using dc_str_unref().
|
||||
* @return String with a fully-qualified URL,
|
||||
* if there is no such URL, an empty string is returned, NULL is never returned.
|
||||
* The returned value must be released using dc_str_unref().
|
||||
*/
|
||||
char* dc_provider_get_overview_page (const dc_provider_t* provider);
|
||||
|
||||
|
||||
/**
|
||||
* The provider's name.
|
||||
* Get hints to be shown to the user on the login screen.
|
||||
* Depending on the @ref DC_PROVIDER_STATUS returned by dc_provider_get_status(),
|
||||
* the ui may want to highlight the hint.
|
||||
*
|
||||
* The name of the provider, e.g. "POSTEO".
|
||||
* Moreover, the ui should display a "More information" link
|
||||
* that forwards to the url returned by dc_provider_get_overview_page().
|
||||
*
|
||||
* @memberof dc_provider_t
|
||||
* @param provider The dc_provider_t struct.
|
||||
* @return A string which must be released using dc_str_unref().
|
||||
* @return A string with the hint to show to the user, may contain multiple lines,
|
||||
* if there is no such hint, an empty string is returned, NULL is never returned.
|
||||
* The returned value must be released using dc_str_unref().
|
||||
*/
|
||||
char* dc_provider_get_name (const dc_provider_t* provider);
|
||||
|
||||
|
||||
/**
|
||||
* The markdown content of the providers page.
|
||||
*
|
||||
* This contains the preparation steps or additional information if the status
|
||||
* is @ref DC_PROVIDER_STATUS_BROKEN.
|
||||
*
|
||||
* @memberof dc_provider_t
|
||||
* @param provider The dc_provider_t struct.
|
||||
* @return A string which must be released using dc_str_unref().
|
||||
*/
|
||||
char* dc_provider_get_markdown (const dc_provider_t* provider);
|
||||
|
||||
|
||||
/**
|
||||
* Date of when the state was last checked/updated.
|
||||
*
|
||||
* This is returned as a string.
|
||||
*
|
||||
* @memberof dc_provider_t
|
||||
* @param provider The dc_provider_t struct.
|
||||
* @return A string which must be released using dc_str_unref().
|
||||
*/
|
||||
char* dc_provider_get_status_date (const dc_provider_t* provider);
|
||||
char* dc_provider_get_before_login_hint (const dc_provider_t* provider);
|
||||
|
||||
|
||||
/**
|
||||
* Whether DC works with this provider.
|
||||
*
|
||||
* Can be one of @ref DC_PROVIDER_STATUS_OK, @ref
|
||||
* DC_PROVIDER_STATUS_PREPARATION and @ref DC_PROVIDER_STATUS_BROKEN.
|
||||
* Can be one of #DC_PROVIDER_STATUS_OK,
|
||||
* #DC_PROVIDER_STATUS_PREPARATION or #DC_PROVIDER_STATUS_BROKEN.
|
||||
*
|
||||
* @memberof dc_provider_t
|
||||
* @param provider The dc_provider_t struct.
|
||||
@@ -3780,7 +3751,7 @@ int dc_provider_get_status (const dc_provider_t* prov
|
||||
* @memberof dc_provider_t
|
||||
* @param provider The dc_provider_t struct.
|
||||
*/
|
||||
void dc_provider_unref (const dc_provider_t* provider);
|
||||
void dc_provider_unref (dc_provider_t* provider);
|
||||
|
||||
|
||||
/**
|
||||
@@ -4506,23 +4477,43 @@ void dc_array_add_id (dc_array_t*, uint32_t); // depreca
|
||||
*/
|
||||
|
||||
/**
|
||||
* Provider status returned by dc_provider_get_status().
|
||||
* Prover works out-of-the-box.
|
||||
* This provider status is returned for provider where the login
|
||||
* works by just entering the name or the email-address.
|
||||
*
|
||||
* Works right out of the box without any preperation steps needed
|
||||
* - There is no need for the user to do any special things
|
||||
* (enable IMAP or so) in the provider's webinterface or at other places.
|
||||
* - There is no need for the user to enter advanced settings;
|
||||
* server, port etc. are known by the core.
|
||||
*
|
||||
* The status is returned by dc_provider_get_status().
|
||||
*/
|
||||
#define DC_PROVIDER_STATUS_OK 1
|
||||
|
||||
/**
|
||||
* Provider status returned by dc_provider_get_status().
|
||||
* Provider works, but there are preparations needed.
|
||||
*
|
||||
* Works, but preparation steps are needed
|
||||
* - The user has to do some special things as "Enable IMAP in the Webinterface",
|
||||
* what exactly, is described in the string returnd by dc_provider_get_before_login_hints()
|
||||
* and, typically more detailed, in the page linked by dc_provider_get_overview_page().
|
||||
* - There is no need for the user to enter advanced settings;
|
||||
* server, port etc. should be known by the core.
|
||||
*
|
||||
* The status is returned by dc_provider_get_status().
|
||||
*/
|
||||
#define DC_PROVIDER_STATUS_PREPARATION 2
|
||||
|
||||
/**
|
||||
* Provider status returned by dc_provider_get_status().
|
||||
* Provider is not working.
|
||||
* This provider status is returned for providers
|
||||
* that are known to not work with Delta Chat.
|
||||
* The ui should block logging in with this provider.
|
||||
*
|
||||
* Doesn't work (too unstable to use falls also in this category)
|
||||
* More information about that is typically provided
|
||||
* in the string returned by dc_provider_get_before_login_hints()
|
||||
* and in the page linked by dc_provider_get_overview_page().
|
||||
*
|
||||
* The status is returned by dc_provider_get_status().
|
||||
*/
|
||||
#define DC_PROVIDER_STATUS_BROKEN 3
|
||||
|
||||
|
||||
@@ -3156,8 +3156,6 @@ pub unsafe extern "C" fn dc_str_unref(s: *mut libc::c_char) {
|
||||
libc::free(s as *mut _)
|
||||
}
|
||||
|
||||
pub mod providers;
|
||||
|
||||
pub trait ResultExt<T, E> {
|
||||
fn unwrap_or_log_default(self, context: &context::Context, message: &str) -> T;
|
||||
fn log_err(self, context: &context::Context, message: &str) -> Result<T, E>;
|
||||
@@ -3212,3 +3210,68 @@ fn convert_and_prune_message_ids(msg_ids: *const u32, msg_cnt: libc::c_int) -> V
|
||||
|
||||
msg_ids
|
||||
}
|
||||
|
||||
// dc_provider_t
|
||||
|
||||
#[no_mangle]
|
||||
pub type dc_provider_t = provider::Provider;
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_provider_new_from_email(
|
||||
context: *const dc_context_t,
|
||||
addr: *const libc::c_char,
|
||||
) -> *const dc_provider_t {
|
||||
if context.is_null() || addr.is_null() {
|
||||
eprintln!("ignoring careless call to dc_provider_new_from_email()");
|
||||
return ptr::null();
|
||||
}
|
||||
let addr = to_string_lossy(addr);
|
||||
match provider::get_provider_info(addr.as_str()) {
|
||||
Some(provider) => provider,
|
||||
None => ptr::null_mut(),
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_provider_get_overview_page(
|
||||
provider: *const dc_provider_t,
|
||||
) -> *mut libc::c_char {
|
||||
if provider.is_null() {
|
||||
eprintln!("ignoring careless call to dc_provider_get_overview_page()");
|
||||
return "".strdup();
|
||||
}
|
||||
let provider = &*provider;
|
||||
provider.overview_page.strdup()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_provider_get_before_login_hint(
|
||||
provider: *const dc_provider_t,
|
||||
) -> *mut libc::c_char {
|
||||
if provider.is_null() {
|
||||
eprintln!("ignoring careless call to dc_provider_get_before_login_hint()");
|
||||
return "".strdup();
|
||||
}
|
||||
let provider = &*provider;
|
||||
provider.before_login_hint.strdup()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_provider_get_status(provider: *const dc_provider_t) -> libc::c_int {
|
||||
if provider.is_null() {
|
||||
eprintln!("ignoring careless call to dc_provider_get_status()");
|
||||
return 0;
|
||||
}
|
||||
let provider = &*provider;
|
||||
provider.status as libc::c_int
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_provider_unref(provider: *mut dc_provider_t) {
|
||||
if provider.is_null() {
|
||||
eprintln!("ignoring careless call to dc_provider_unref()");
|
||||
return;
|
||||
}
|
||||
// currently, there is nothing to free, the provider info is a static object.
|
||||
// this may change once we start localizing string.
|
||||
}
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
extern crate deltachat_provider_database;
|
||||
|
||||
use std::ptr;
|
||||
|
||||
use crate::string::{to_string_lossy, StrExt};
|
||||
use deltachat_provider_database::StatusState;
|
||||
|
||||
#[no_mangle]
|
||||
pub type dc_provider_t = deltachat_provider_database::Provider;
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_provider_new_from_domain(
|
||||
domain: *const libc::c_char,
|
||||
) -> *const dc_provider_t {
|
||||
match deltachat_provider_database::get_provider_info(&to_string_lossy(domain)) {
|
||||
Some(provider) => provider,
|
||||
None => ptr::null(),
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_provider_new_from_email(
|
||||
email: *const libc::c_char,
|
||||
) -> *const dc_provider_t {
|
||||
let email = to_string_lossy(email);
|
||||
let domain = deltachat_provider_database::get_domain_from_email(&email);
|
||||
match deltachat_provider_database::get_provider_info(domain) {
|
||||
Some(provider) => provider,
|
||||
None => ptr::null(),
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! null_guard {
|
||||
($context:tt) => {
|
||||
if $context.is_null() {
|
||||
return ptr::null_mut() as *mut libc::c_char;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_provider_get_overview_page(
|
||||
provider: *const dc_provider_t,
|
||||
) -> *mut libc::c_char {
|
||||
null_guard!(provider);
|
||||
format!(
|
||||
"{}/{}",
|
||||
deltachat_provider_database::PROVIDER_OVERVIEW_URL,
|
||||
(*provider).overview_page
|
||||
)
|
||||
.strdup()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_provider_get_name(provider: *const dc_provider_t) -> *mut libc::c_char {
|
||||
null_guard!(provider);
|
||||
(*provider).name.strdup()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_provider_get_markdown(
|
||||
provider: *const dc_provider_t,
|
||||
) -> *mut libc::c_char {
|
||||
null_guard!(provider);
|
||||
(*provider).markdown.strdup()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_provider_get_status_date(
|
||||
provider: *const dc_provider_t,
|
||||
) -> *mut libc::c_char {
|
||||
null_guard!(provider);
|
||||
(*provider).status.date.strdup()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_provider_get_status(provider: *const dc_provider_t) -> u32 {
|
||||
if provider.is_null() {
|
||||
return 0;
|
||||
}
|
||||
match (*provider).status.state {
|
||||
StatusState::OK => 1,
|
||||
StatusState::PREPARATION => 2,
|
||||
StatusState::BROKEN => 3,
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_provider_unref(_provider: *const dc_provider_t) {}
|
||||
|
||||
// TODO expose general provider overview url?
|
||||
@@ -3,7 +3,6 @@ use std::str::FromStr;
|
||||
|
||||
use deltachat::chat::{self, Chat, ChatId};
|
||||
use deltachat::chatlist::*;
|
||||
use deltachat::config;
|
||||
use deltachat::constants::*;
|
||||
use deltachat::contact::*;
|
||||
use deltachat::context::*;
|
||||
@@ -19,6 +18,7 @@ use deltachat::peerstate::*;
|
||||
use deltachat::qr::*;
|
||||
use deltachat::sql;
|
||||
use deltachat::Event;
|
||||
use deltachat::{config, provider};
|
||||
|
||||
/// Reset database tables.
|
||||
/// Argument is a bitmask, executing single or multiple actions in one call.
|
||||
@@ -392,6 +392,7 @@ pub fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::Error> {
|
||||
getqr [<chat-id>]\n\
|
||||
getbadqr\n\
|
||||
checkqr <qr-content>\n\
|
||||
providerinfo <addr>\n\
|
||||
event <event-id to test>\n\
|
||||
fileinfo <file>\n\
|
||||
emptyserver <flags> (1=MVBOX 2=INBOX)\n\
|
||||
@@ -966,6 +967,24 @@ pub fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::Error> {
|
||||
res.get_text2()
|
||||
);
|
||||
}
|
||||
"providerinfo" => {
|
||||
ensure!(!arg1.is_empty(), "Argument <addr> missing.");
|
||||
match provider::get_provider_info(arg1) {
|
||||
Some(info) => {
|
||||
println!("Information for provider belonging to {}:", arg1);
|
||||
println!("status: {}", info.status as u32);
|
||||
println!("before_login_hint: {}", info.before_login_hint);
|
||||
println!("after_login_hint: {}", info.after_login_hint);
|
||||
println!("overview_page: {}", info.overview_page);
|
||||
for server in info.server.iter() {
|
||||
println!("server: {}:{}", server.hostname, server.port,);
|
||||
}
|
||||
}
|
||||
None => {
|
||||
println!("No information for provider belonging to {} found.", arg1);
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: implement this again, unclear how to match this through though, without writing a parser.
|
||||
// "event" => {
|
||||
// ensure!(!arg1.is_empty(), "Argument <id> missing.");
|
||||
|
||||
@@ -11,27 +11,18 @@ class ProviderNotFoundError(Exception):
|
||||
class Provider(object):
|
||||
"""Provider information.
|
||||
|
||||
:param domain: The domain to get the provider info for, this is
|
||||
normally the part following the `@` of the domain.
|
||||
:param domain: The email to get the provider info for.
|
||||
"""
|
||||
|
||||
def __init__(self, domain):
|
||||
def __init__(self, account, addr):
|
||||
provider = ffi.gc(
|
||||
lib.dc_provider_new_from_domain(as_dc_charpointer(domain)),
|
||||
lib.dc_provider_new_from_email(account._dc_context, as_dc_charpointer(addr)),
|
||||
lib.dc_provider_unref,
|
||||
)
|
||||
if provider == ffi.NULL:
|
||||
raise ProviderNotFoundError("Provider not found")
|
||||
self._provider = provider
|
||||
|
||||
@classmethod
|
||||
def from_email(cls, email):
|
||||
"""Create provider info from an email address.
|
||||
|
||||
:param email: Email address to get provider info for.
|
||||
"""
|
||||
return cls(email.split('@')[-1])
|
||||
|
||||
@property
|
||||
def overview_page(self):
|
||||
"""URL to the overview page of the provider on providers.delta.chat."""
|
||||
@@ -39,21 +30,10 @@ class Provider(object):
|
||||
lib.dc_provider_get_overview_page(self._provider))
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""The name of the provider."""
|
||||
return from_dc_charpointer(lib.dc_provider_get_name(self._provider))
|
||||
|
||||
@property
|
||||
def markdown(self):
|
||||
"""Content of the information page, formatted as markdown."""
|
||||
def get_before_login_hints(self):
|
||||
"""Should be shown to the user on login."""
|
||||
return from_dc_charpointer(
|
||||
lib.dc_provider_get_markdown(self._provider))
|
||||
|
||||
@property
|
||||
def status_date(self):
|
||||
"""The date the provider info was last updated, as a string."""
|
||||
return from_dc_charpointer(
|
||||
lib.dc_provider_get_status_date(self._provider))
|
||||
lib.dc_provider_get_before_login_hints(self._provider))
|
||||
|
||||
@property
|
||||
def status(self):
|
||||
|
||||
@@ -102,19 +102,12 @@ def test_get_special_message_id_returns_empty_message(acfactory):
|
||||
assert msg.id == 0
|
||||
|
||||
|
||||
def test_provider_info():
|
||||
provider = lib.dc_provider_new_from_email(cutil.as_dc_charpointer("ex@example.com"))
|
||||
assert cutil.from_dc_charpointer(
|
||||
lib.dc_provider_get_overview_page(provider)
|
||||
) == "https://providers.delta.chat/example.com"
|
||||
assert cutil.from_dc_charpointer(lib.dc_provider_get_name(provider)) == "Example"
|
||||
assert cutil.from_dc_charpointer(lib.dc_provider_get_markdown(provider)) == "\n..."
|
||||
assert cutil.from_dc_charpointer(lib.dc_provider_get_status_date(provider)) == "2018-09"
|
||||
assert lib.dc_provider_get_status(provider) == const.DC_PROVIDER_STATUS_PREPARATION
|
||||
|
||||
|
||||
def test_provider_info_none():
|
||||
assert lib.dc_provider_new_from_email(cutil.as_dc_charpointer("email@unexistent.no")) == ffi.NULL
|
||||
ctx = ffi.gc(
|
||||
lib.dc_context_new(lib.py_dc_callback, ffi.NULL, ffi.NULL),
|
||||
lib.dc_context_unref,
|
||||
)
|
||||
assert lib.dc_provider_new_from_email(ctx, cutil.as_dc_charpointer("email@unexistent.no")) == ffi.NULL
|
||||
|
||||
|
||||
def test_get_info_closed():
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
import pytest
|
||||
|
||||
from deltachat import const
|
||||
from deltachat import provider
|
||||
|
||||
|
||||
def test_provider_info_from_email():
|
||||
example = provider.Provider.from_email("email@example.com")
|
||||
assert example.overview_page == "https://providers.delta.chat/example.com"
|
||||
assert example.name == "Example"
|
||||
assert example.markdown == "\n..."
|
||||
assert example.status_date == "2018-09"
|
||||
assert example.status == const.DC_PROVIDER_STATUS_PREPARATION
|
||||
|
||||
|
||||
def test_provider_info_from_domain():
|
||||
example = provider.Provider("example.com")
|
||||
assert example.overview_page == "https://providers.delta.chat/example.com"
|
||||
assert example.name == "Example"
|
||||
assert example.markdown == "\n..."
|
||||
assert example.status_date == "2018-09"
|
||||
assert example.status == const.DC_PROVIDER_STATUS_PREPARATION
|
||||
|
||||
|
||||
def test_provider_info_none():
|
||||
with pytest.raises(provider.ProviderNotFoundError):
|
||||
provider.Provider.from_email("email@unexistent.no")
|
||||
@@ -12,12 +12,13 @@ use crate::config::Config;
|
||||
use crate::constants::*;
|
||||
use crate::context::Context;
|
||||
use crate::dc_tools::*;
|
||||
use crate::e2ee;
|
||||
use crate::job::{self, job_add, job_kill_action};
|
||||
use crate::login_param::{CertificateChecks, LoginParam};
|
||||
use crate::oauth2::*;
|
||||
use crate::param::Params;
|
||||
use crate::{chat, e2ee, provider};
|
||||
|
||||
use crate::message::Message;
|
||||
use auto_mozilla::moz_autoconfigure;
|
||||
use auto_outlook::outlk_autodiscover;
|
||||
|
||||
@@ -436,45 +437,77 @@ pub fn JobConfigureImap(context: &Context) -> job::Status {
|
||||
LoginParam::from_database(context, "configured_raw_").save_to_database(context, "");
|
||||
}
|
||||
|
||||
if let Some(provider) = provider::get_provider_info(¶m.addr) {
|
||||
if !provider.after_login_hint.is_empty() {
|
||||
let mut msg = Message::new(Viewtype::Text);
|
||||
msg.text = Some(provider.after_login_hint.to_string());
|
||||
if chat::add_device_msg(context, Some("core-provider-info"), Some(&mut msg)).is_err() {
|
||||
warn!(context, "cannot add after_login_hint as core-provider-info");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
context.free_ongoing();
|
||||
progress!(context, if success { 1000 } else { 0 });
|
||||
job::Status::Finished(Ok(()))
|
||||
}
|
||||
|
||||
#[allow(clippy::unnecessary_unwrap)]
|
||||
fn get_offline_autoconfig(context: &Context, param: &LoginParam) -> Option<LoginParam> {
|
||||
// XXX we don't have https://github.com/deltachat/provider-db APIs
|
||||
// integrated yet but we'll already add nauta as a first use case, also
|
||||
// showing what we need from provider-db in the future.
|
||||
info!(
|
||||
context,
|
||||
"checking internal provider-info for offline autoconfig"
|
||||
);
|
||||
|
||||
if param.addr.ends_with("@nauta.cu") {
|
||||
let mut p = LoginParam::new();
|
||||
if let Some(provider) = provider::get_provider_info(¶m.addr) {
|
||||
match provider.status {
|
||||
provider::Status::OK | provider::Status::PREPARATION => {
|
||||
let imap = provider.get_imap_server();
|
||||
let smtp = provider.get_smtp_server();
|
||||
// clippy complains about these is_some()/unwrap() settings,
|
||||
// however, rewriting the code to "if let" would make things less obvious,
|
||||
// esp. if we allow more combinations of servers (pop, jmap).
|
||||
// therefore, #[allow(clippy::unnecessary_unwrap)] is added above.
|
||||
if imap.is_some() && smtp.is_some() {
|
||||
let imap = imap.unwrap();
|
||||
let smtp = smtp.unwrap();
|
||||
|
||||
p.addr = param.addr.clone();
|
||||
p.mail_server = "imap.nauta.cu".to_string();
|
||||
p.mail_user = param.addr.clone();
|
||||
p.mail_pw = param.mail_pw.clone();
|
||||
p.mail_port = 143;
|
||||
p.imap_certificate_checks = CertificateChecks::AcceptInvalidCertificates;
|
||||
let mut p = LoginParam::new();
|
||||
p.addr = param.addr.clone();
|
||||
|
||||
p.send_server = "smtp.nauta.cu".to_string();
|
||||
p.send_user = param.addr.clone();
|
||||
p.send_pw = param.mail_pw.clone();
|
||||
p.send_port = 25;
|
||||
p.smtp_certificate_checks = CertificateChecks::AcceptInvalidCertificates;
|
||||
p.server_flags = DC_LP_AUTH_NORMAL as i32
|
||||
| DC_LP_IMAP_SOCKET_STARTTLS as i32
|
||||
| DC_LP_SMTP_SOCKET_STARTTLS as i32;
|
||||
p.mail_server = imap.hostname.to_string();
|
||||
p.mail_user = imap.apply_username_pattern(param.addr.clone());
|
||||
p.mail_port = imap.port as i32;
|
||||
p.imap_certificate_checks = CertificateChecks::AcceptInvalidCertificates;
|
||||
p.server_flags |= match imap.socket {
|
||||
provider::Socket::STARTTLS => DC_LP_IMAP_SOCKET_STARTTLS,
|
||||
provider::Socket::SSL => DC_LP_IMAP_SOCKET_SSL,
|
||||
};
|
||||
|
||||
info!(context, "found offline autoconfig: {}", p);
|
||||
Some(p)
|
||||
} else {
|
||||
info!(context, "no offline autoconfig found");
|
||||
None
|
||||
p.send_server = smtp.hostname.to_string();
|
||||
p.send_user = smtp.apply_username_pattern(param.addr.clone());
|
||||
p.send_port = smtp.port as i32;
|
||||
p.smtp_certificate_checks = CertificateChecks::AcceptInvalidCertificates;
|
||||
p.server_flags |= match smtp.socket {
|
||||
provider::Socket::STARTTLS => DC_LP_SMTP_SOCKET_STARTTLS as i32,
|
||||
provider::Socket::SSL => DC_LP_SMTP_SOCKET_SSL as i32,
|
||||
};
|
||||
|
||||
info!(context, "offline autoconfig found: {}", p);
|
||||
return Some(p);
|
||||
} else {
|
||||
info!(context, "offline autoconfig found, but no servers defined");
|
||||
return None;
|
||||
}
|
||||
}
|
||||
provider::Status::BROKEN => {
|
||||
info!(context, "offline autoconfig found, provider is broken");
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
info!(context, "no offline autoconfig found");
|
||||
None
|
||||
}
|
||||
|
||||
fn try_imap_connections(
|
||||
|
||||
@@ -54,6 +54,7 @@ pub mod oauth2;
|
||||
mod param;
|
||||
pub mod peerstate;
|
||||
pub mod pgp;
|
||||
pub mod provider;
|
||||
pub mod qr;
|
||||
pub mod securejoin;
|
||||
mod simplify;
|
||||
|
||||
308
src/provider/data.rs
Normal file
308
src/provider/data.rs
Normal file
@@ -0,0 +1,308 @@
|
||||
// file generated by src/provider/update.py
|
||||
|
||||
use crate::provider::Protocol::*;
|
||||
use crate::provider::Socket::*;
|
||||
use crate::provider::UsernamePattern::*;
|
||||
use crate::provider::*;
|
||||
use std::collections::HashMap;
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
|
||||
// aktivix.org.md: aktivix.org
|
||||
static ref P_AKTIVIX_ORG: Provider = Provider {
|
||||
status: Status::OK,
|
||||
before_login_hint: "",
|
||||
after_login_hint: "",
|
||||
overview_page: "https://providers.delta.chat/aktivix-org",
|
||||
server: vec![
|
||||
Server { protocol: IMAP, socket: STARTTLS, hostname: "newyear.aktivix.org", port: 143, username_pattern: EMAIL },
|
||||
Server { protocol: SMTP, socket: STARTTLS, hostname: "newyear.aktivix.org", port: 25, username_pattern: EMAIL },
|
||||
],
|
||||
};
|
||||
|
||||
// autistici.org.md: autistici.org
|
||||
static ref P_AUTISTICI_ORG: Provider = Provider {
|
||||
status: Status::OK,
|
||||
before_login_hint: "",
|
||||
after_login_hint: "",
|
||||
overview_page: "https://providers.delta.chat/autistici-org",
|
||||
server: vec![
|
||||
Server { protocol: IMAP, socket: SSL, hostname: "mail.autistici.org", port: 993, username_pattern: EMAIL },
|
||||
Server { protocol: SMTP, socket: SSL, hostname: "smtp.autistici.org", port: 465, username_pattern: EMAIL },
|
||||
],
|
||||
};
|
||||
|
||||
// bluewin.ch.md: bluewin.ch
|
||||
static ref P_BLUEWIN_CH: Provider = Provider {
|
||||
status: Status::OK,
|
||||
before_login_hint: "",
|
||||
after_login_hint: "",
|
||||
overview_page: "https://providers.delta.chat/bluewin-ch",
|
||||
server: vec![
|
||||
Server { protocol: IMAP, socket: SSL, hostname: "imaps.bluewin.ch", port: 993, username_pattern: EMAIL },
|
||||
Server { protocol: SMTP, socket: SSL, hostname: "smtpauths.bluewin.ch", port: 465, username_pattern: EMAIL },
|
||||
],
|
||||
};
|
||||
|
||||
// comcast.md: xfinity.com, comcast.net
|
||||
// - skipping provider with status OK and no special things to do
|
||||
|
||||
// dismail.de.md: dismail.de
|
||||
// - skipping provider with status OK and no special things to do
|
||||
|
||||
// disroot.md: disroot.org
|
||||
// - skipping provider with status OK and no special things to do
|
||||
|
||||
// example.com.md: example.com, example.org
|
||||
static ref P_EXAMPLE_COM: Provider = Provider {
|
||||
status: Status::BROKEN,
|
||||
before_login_hint: "Hush this provider doesn't exist!",
|
||||
after_login_hint: "This provider doesn't really exist, so you can't use it :/ If you need an email provider for Delta Chat, take a look at providers.delta.chat!",
|
||||
overview_page: "https://providers.delta.chat/example-com",
|
||||
server: vec![
|
||||
Server { protocol: IMAP, socket: SSL, hostname: "imap.example.com", port: 1337, username_pattern: EMAIL },
|
||||
Server { protocol: SMTP, socket: STARTTLS, hostname: "smtp.example.com", port: 1337, username_pattern: EMAIL },
|
||||
],
|
||||
};
|
||||
|
||||
// freenet.de.md: freenet.de
|
||||
static ref P_FREENET_DE: Provider = Provider {
|
||||
status: Status::OK,
|
||||
before_login_hint: "",
|
||||
after_login_hint: "",
|
||||
overview_page: "https://providers.delta.chat/freenet-de",
|
||||
server: vec![
|
||||
Server { protocol: IMAP, socket: SSL, hostname: "mx.freenet.de", port: 993, username_pattern: EMAIL },
|
||||
Server { protocol: SMTP, socket: STARTTLS, hostname: "mx.freenet.de", port: 587, username_pattern: EMAIL },
|
||||
],
|
||||
};
|
||||
|
||||
// gmail.md: gmail.com, googlemail.com
|
||||
static ref P_GMAIL: Provider = Provider {
|
||||
status: Status::PREPARATION,
|
||||
before_login_hint: "For Gmail accounts, you need to create an app-password if you have \"2-Step Verification\" enabled. If this setting is not available, you need to enable \"less secure apps\".",
|
||||
after_login_hint: "",
|
||||
overview_page: "https://providers.delta.chat/gmail",
|
||||
server: vec![
|
||||
Server { protocol: IMAP, socket: SSL, hostname: "imap.gmail.com", port: 993, username_pattern: EMAIL },
|
||||
Server { protocol: SMTP, socket: SSL, hostname: "smtp.gmail.com", port: 465, username_pattern: EMAIL },
|
||||
],
|
||||
};
|
||||
|
||||
// gmx.net.md: gmx.net, gmx.de, gmx.at, gmx.ch, gmx.org, gmx.eu, gmx.info, gmx.biz, gmx.com
|
||||
static ref P_GMX_NET: Provider = Provider {
|
||||
status: Status::PREPARATION,
|
||||
before_login_hint: "You must allow IMAP access to your account before you can login.",
|
||||
after_login_hint: "",
|
||||
overview_page: "https://providers.delta.chat/gmx-net",
|
||||
server: vec![
|
||||
Server { protocol: IMAP, socket: SSL, hostname: "imap.gmx.net", port: 993, username_pattern: EMAIL },
|
||||
Server { protocol: SMTP, socket: SSL, hostname: "mail.gmx.net", port: 465, username_pattern: EMAIL },
|
||||
Server { protocol: SMTP, socket: STARTTLS, hostname: "mail.gmx.net", port: 587, username_pattern: EMAIL },
|
||||
],
|
||||
};
|
||||
|
||||
// i.ua.md: i.ua
|
||||
// - skipping provider with status OK and no special things to do
|
||||
|
||||
// icloud.md: icloud.com, me.com, mac.com
|
||||
static ref P_ICLOUD: Provider = Provider {
|
||||
status: Status::PREPARATION,
|
||||
before_login_hint: "You must create an app-specific password for Delta Chat before you can login.",
|
||||
after_login_hint: "",
|
||||
overview_page: "https://providers.delta.chat/icloud",
|
||||
server: vec![
|
||||
Server { protocol: IMAP, socket: SSL, hostname: "imap.mail.me.com", port: 993, username_pattern: EMAILLOCALPART },
|
||||
Server { protocol: SMTP, socket: STARTTLS, hostname: "smtp.mail.me.com", port: 587, username_pattern: EMAIL },
|
||||
],
|
||||
};
|
||||
|
||||
// kolst.com.md: kolst.com
|
||||
// - skipping provider with status OK and no special things to do
|
||||
|
||||
// kontent.com.md: kontent.com
|
||||
// - skipping provider with status OK and no special things to do
|
||||
|
||||
// mail.ru.md: mail.ru, inbox.ru, bk.ru, list.ru
|
||||
// - skipping provider with status OK and no special things to do
|
||||
|
||||
// mailbox.org.md: mailbox.org, secure.mailbox.org
|
||||
// - skipping provider with status OK and no special things to do
|
||||
|
||||
// nauta.cu.md: nauta.cu
|
||||
static ref P_NAUTA_CU: Provider = Provider {
|
||||
status: Status::OK,
|
||||
before_login_hint: "",
|
||||
after_login_hint: "Atención - con nauta.cu, puede enviar mensajes sólo a un máximo de 20 personas a la vez. En grupos más grandes, no puede enviar mensajes o abandonar el grupo.",
|
||||
overview_page: "https://providers.delta.chat/nauta-cu",
|
||||
server: vec![
|
||||
Server { protocol: IMAP, socket: STARTTLS, hostname: "imap.nauta.cu", port: 143, username_pattern: EMAIL },
|
||||
Server { protocol: SMTP, socket: STARTTLS, hostname: "smtp.nauta.cu", port: 25, username_pattern: EMAIL },
|
||||
],
|
||||
};
|
||||
|
||||
// outlook.com.md: hotmail.com, outlook.com, office365.com, outlook.com.tr, live.com
|
||||
static ref P_OUTLOOK_COM: Provider = Provider {
|
||||
status: Status::BROKEN,
|
||||
before_login_hint: "Outlook.com email addresses will not work as expected as these servers remove some important transport information. Hopefully sooner or later there will be a fix, for now we suggest to use another email address.",
|
||||
after_login_hint: "Outlook.com email addresses will not work as expected as these servers remove some important transport information. Unencrypted 1-on-1 chats kind of work, but groups and encryption don't. Hopefully sooner or later there will be a fix, for now we suggest to use another email address.",
|
||||
overview_page: "https://providers.delta.chat/outlook-com",
|
||||
server: vec![
|
||||
Server { protocol: IMAP, socket: SSL, hostname: "imap-mail.outlook.com", port: 993, username_pattern: EMAIL },
|
||||
Server { protocol: SMTP, socket: STARTTLS, hostname: "smtp-mail.outlook.com", port: 587, username_pattern: EMAIL },
|
||||
],
|
||||
};
|
||||
|
||||
// posteo.md: posteo.de
|
||||
static ref P_POSTEO: Provider = Provider {
|
||||
status: Status::OK,
|
||||
before_login_hint: "",
|
||||
after_login_hint: "",
|
||||
overview_page: "https://providers.delta.chat/posteo",
|
||||
server: vec![
|
||||
Server { protocol: IMAP, socket: STARTTLS, hostname: "posteo.de", port: 143, username_pattern: EMAIL },
|
||||
Server { protocol: SMTP, socket: STARTTLS, hostname: "posteo.de", port: 587, username_pattern: EMAIL },
|
||||
],
|
||||
};
|
||||
|
||||
// riseup.net.md: riseup.net
|
||||
// - skipping provider with status OK and no special things to do
|
||||
|
||||
// rogers.com.md: rogers.com
|
||||
// - skipping provider with status OK and no special things to do
|
||||
|
||||
// tiscali.it.md: tiscali.it
|
||||
static ref P_TISCALI_IT: Provider = Provider {
|
||||
status: Status::OK,
|
||||
before_login_hint: "",
|
||||
after_login_hint: "",
|
||||
overview_page: "https://providers.delta.chat/tiscali-it",
|
||||
server: vec![
|
||||
Server { protocol: IMAP, socket: SSL, hostname: "imap.tiscali.it", port: 993, username_pattern: EMAIL },
|
||||
Server { protocol: SMTP, socket: SSL, hostname: "smtp.tiscali.it", port: 465, username_pattern: EMAIL },
|
||||
],
|
||||
};
|
||||
|
||||
// ukr.net.md: ukr.net
|
||||
// - skipping provider with status OK and no special things to do
|
||||
|
||||
// vfemail.md: vfemail.net
|
||||
// - skipping provider with status OK and no special things to do
|
||||
|
||||
// web.de.md: web.de, email.de, flirt.ms, hallo.ms, kuss.ms, love.ms, magic.ms, singles.ms, cool.ms, kanzler.ms, okay.ms, party.ms, pop.ms, stars.ms, techno.ms, clever.ms, deutschland.ms, genial.ms, ich.ms, online.ms, smart.ms, wichtig.ms, action.ms, fussball.ms, joker.ms, planet.ms, power.ms
|
||||
static ref P_WEB_DE: Provider = Provider {
|
||||
status: Status::PREPARATION,
|
||||
before_login_hint: "You must allow IMAP access to your account before you can login.",
|
||||
after_login_hint: "Note: if you have your web.de spam settings too strict, you won't receive contact requests from new people. If you want to receive contact requests, you should disable the \"3-Wege-Spamschutz\" in the web.de settings. Read how: https://hilfe.web.de/email/spam-und-viren/spamschutz-einstellungen.html",
|
||||
overview_page: "https://providers.delta.chat/web-de",
|
||||
server: vec![
|
||||
Server { protocol: IMAP, socket: SSL, hostname: "imap.web.de", port: 993, username_pattern: EMAILLOCALPART },
|
||||
Server { protocol: IMAP, socket: STARTTLS, hostname: "imap.web.de", port: 143, username_pattern: EMAILLOCALPART },
|
||||
Server { protocol: SMTP, socket: STARTTLS, hostname: "smtp.web.de", port: 587, username_pattern: EMAILLOCALPART },
|
||||
],
|
||||
};
|
||||
|
||||
// yahoo.md: yahoo.com, yahoo.de, yahoo.it, yahoo.fr, yahoo.es, yahoo.se, yahoo.co.uk, yahoo.co.nz, yahoo.com.au, yahoo.com.ar, yahoo.com.br, yahoo.com.mx, ymail.com, rocketmail.com, yahoodns.net
|
||||
static ref P_YAHOO: Provider = Provider {
|
||||
status: Status::PREPARATION,
|
||||
before_login_hint: "To use Delta Chat with your Yahoo email address you have to allow \"less secure apps\" in the Yahoo webinterface.",
|
||||
after_login_hint: "",
|
||||
overview_page: "https://providers.delta.chat/yahoo",
|
||||
server: vec![
|
||||
Server { protocol: IMAP, socket: SSL, hostname: "imap.mail.yahoo.com", port: 993, username_pattern: EMAIL },
|
||||
Server { protocol: SMTP, socket: SSL, hostname: "smtp.mail.yahoo.com", port: 465, username_pattern: EMAIL },
|
||||
],
|
||||
};
|
||||
|
||||
// yandex.ru.md: yandex.ru, yandex.com
|
||||
// - skipping provider with status OK and no special things to do
|
||||
|
||||
// ziggo.nl.md: ziggo.nl
|
||||
static ref P_ZIGGO_NL: Provider = Provider {
|
||||
status: Status::OK,
|
||||
before_login_hint: "",
|
||||
after_login_hint: "",
|
||||
overview_page: "https://providers.delta.chat/ziggo-nl",
|
||||
server: vec![
|
||||
Server { protocol: IMAP, socket: SSL, hostname: "imap.ziggo.nl", port: 993, username_pattern: EMAIL },
|
||||
Server { protocol: SMTP, socket: STARTTLS, hostname: "smtp.ziggo.nl", port: 587, username_pattern: EMAIL },
|
||||
],
|
||||
};
|
||||
|
||||
// zoho.com.md: zoho.com
|
||||
// - skipping provider with status OK and no special things to do
|
||||
|
||||
pub static ref PROVIDER_DATA: HashMap<&'static str, &'static Provider> = [
|
||||
("aktivix.org", &*P_AKTIVIX_ORG),
|
||||
("autistici.org", &*P_AUTISTICI_ORG),
|
||||
("bluewin.ch", &*P_BLUEWIN_CH),
|
||||
("example.com", &*P_EXAMPLE_COM),
|
||||
("example.org", &*P_EXAMPLE_COM),
|
||||
("freenet.de", &*P_FREENET_DE),
|
||||
("gmail.com", &*P_GMAIL),
|
||||
("googlemail.com", &*P_GMAIL),
|
||||
("gmx.net", &*P_GMX_NET),
|
||||
("gmx.de", &*P_GMX_NET),
|
||||
("gmx.at", &*P_GMX_NET),
|
||||
("gmx.ch", &*P_GMX_NET),
|
||||
("gmx.org", &*P_GMX_NET),
|
||||
("gmx.eu", &*P_GMX_NET),
|
||||
("gmx.info", &*P_GMX_NET),
|
||||
("gmx.biz", &*P_GMX_NET),
|
||||
("gmx.com", &*P_GMX_NET),
|
||||
("icloud.com", &*P_ICLOUD),
|
||||
("me.com", &*P_ICLOUD),
|
||||
("mac.com", &*P_ICLOUD),
|
||||
("nauta.cu", &*P_NAUTA_CU),
|
||||
("hotmail.com", &*P_OUTLOOK_COM),
|
||||
("outlook.com", &*P_OUTLOOK_COM),
|
||||
("office365.com", &*P_OUTLOOK_COM),
|
||||
("outlook.com.tr", &*P_OUTLOOK_COM),
|
||||
("live.com", &*P_OUTLOOK_COM),
|
||||
("posteo.de", &*P_POSTEO),
|
||||
("tiscali.it", &*P_TISCALI_IT),
|
||||
("web.de", &*P_WEB_DE),
|
||||
("email.de", &*P_WEB_DE),
|
||||
("flirt.ms", &*P_WEB_DE),
|
||||
("hallo.ms", &*P_WEB_DE),
|
||||
("kuss.ms", &*P_WEB_DE),
|
||||
("love.ms", &*P_WEB_DE),
|
||||
("magic.ms", &*P_WEB_DE),
|
||||
("singles.ms", &*P_WEB_DE),
|
||||
("cool.ms", &*P_WEB_DE),
|
||||
("kanzler.ms", &*P_WEB_DE),
|
||||
("okay.ms", &*P_WEB_DE),
|
||||
("party.ms", &*P_WEB_DE),
|
||||
("pop.ms", &*P_WEB_DE),
|
||||
("stars.ms", &*P_WEB_DE),
|
||||
("techno.ms", &*P_WEB_DE),
|
||||
("clever.ms", &*P_WEB_DE),
|
||||
("deutschland.ms", &*P_WEB_DE),
|
||||
("genial.ms", &*P_WEB_DE),
|
||||
("ich.ms", &*P_WEB_DE),
|
||||
("online.ms", &*P_WEB_DE),
|
||||
("smart.ms", &*P_WEB_DE),
|
||||
("wichtig.ms", &*P_WEB_DE),
|
||||
("action.ms", &*P_WEB_DE),
|
||||
("fussball.ms", &*P_WEB_DE),
|
||||
("joker.ms", &*P_WEB_DE),
|
||||
("planet.ms", &*P_WEB_DE),
|
||||
("power.ms", &*P_WEB_DE),
|
||||
("yahoo.com", &*P_YAHOO),
|
||||
("yahoo.de", &*P_YAHOO),
|
||||
("yahoo.it", &*P_YAHOO),
|
||||
("yahoo.fr", &*P_YAHOO),
|
||||
("yahoo.es", &*P_YAHOO),
|
||||
("yahoo.se", &*P_YAHOO),
|
||||
("yahoo.co.uk", &*P_YAHOO),
|
||||
("yahoo.co.nz", &*P_YAHOO),
|
||||
("yahoo.com.au", &*P_YAHOO),
|
||||
("yahoo.com.ar", &*P_YAHOO),
|
||||
("yahoo.com.br", &*P_YAHOO),
|
||||
("yahoo.com.mx", &*P_YAHOO),
|
||||
("ymail.com", &*P_YAHOO),
|
||||
("rocketmail.com", &*P_YAHOO),
|
||||
("yahoodns.net", &*P_YAHOO),
|
||||
("ziggo.nl", &*P_ZIGGO_NL),
|
||||
].iter().copied().collect();
|
||||
}
|
||||
144
src/provider/mod.rs
Normal file
144
src/provider/mod.rs
Normal file
@@ -0,0 +1,144 @@
|
||||
mod data;
|
||||
|
||||
use crate::dc_tools::EmailAddress;
|
||||
use crate::provider::data::PROVIDER_DATA;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, ToPrimitive)]
|
||||
#[repr(u8)]
|
||||
pub enum Status {
|
||||
OK = 1,
|
||||
PREPARATION = 2,
|
||||
BROKEN = 3,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[repr(u8)]
|
||||
pub enum Protocol {
|
||||
SMTP = 1,
|
||||
IMAP = 2,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[repr(u8)]
|
||||
pub enum Socket {
|
||||
STARTTLS = 1,
|
||||
SSL = 2,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[repr(u8)]
|
||||
pub enum UsernamePattern {
|
||||
EMAIL = 1,
|
||||
EMAILLOCALPART = 2,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Server {
|
||||
pub protocol: Protocol,
|
||||
pub socket: Socket,
|
||||
pub hostname: &'static str,
|
||||
pub port: u16,
|
||||
pub username_pattern: UsernamePattern,
|
||||
}
|
||||
|
||||
impl Server {
|
||||
pub fn apply_username_pattern(&self, addr: String) -> String {
|
||||
match self.username_pattern {
|
||||
UsernamePattern::EMAIL => addr,
|
||||
UsernamePattern::EMAILLOCALPART => {
|
||||
if let Some(at) = addr.find('@') {
|
||||
return addr.split_at(at).0.to_string();
|
||||
}
|
||||
addr
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Provider {
|
||||
pub status: Status,
|
||||
pub before_login_hint: &'static str,
|
||||
pub after_login_hint: &'static str,
|
||||
pub overview_page: &'static str,
|
||||
pub server: Vec<Server>,
|
||||
}
|
||||
|
||||
impl Provider {
|
||||
pub fn get_server(&self, protocol: Protocol) -> Option<&Server> {
|
||||
for record in self.server.iter() {
|
||||
if record.protocol == protocol {
|
||||
return Some(record);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn get_imap_server(&self) -> Option<&Server> {
|
||||
self.get_server(Protocol::IMAP)
|
||||
}
|
||||
|
||||
pub fn get_smtp_server(&self) -> Option<&Server> {
|
||||
self.get_server(Protocol::SMTP)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_provider_info(addr: &str) -> Option<&Provider> {
|
||||
let domain = match addr.parse::<EmailAddress>() {
|
||||
Ok(addr) => addr.domain,
|
||||
Err(_err) => return None,
|
||||
}
|
||||
.to_lowercase();
|
||||
|
||||
if let Some(provider) = PROVIDER_DATA.get(domain.as_str()) {
|
||||
return Some(*provider);
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_get_provider_info_unexistant() {
|
||||
let provider = get_provider_info("user@unexistant.org");
|
||||
assert!(provider.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_provider_info_mixed_case() {
|
||||
let provider = get_provider_info("uSer@nAUta.Cu").unwrap();
|
||||
assert!(provider.status == Status::OK);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_provider_info() {
|
||||
let provider = get_provider_info("nauta.cu"); // this is no email address
|
||||
assert!(provider.is_none());
|
||||
|
||||
let provider = get_provider_info("user@nauta.cu").unwrap();
|
||||
assert!(provider.status == Status::OK);
|
||||
let server = provider.get_imap_server().unwrap();
|
||||
assert_eq!(server.protocol, Protocol::IMAP);
|
||||
assert_eq!(server.socket, Socket::STARTTLS);
|
||||
assert_eq!(server.hostname, "imap.nauta.cu");
|
||||
assert_eq!(server.port, 143);
|
||||
assert_eq!(server.username_pattern, UsernamePattern::EMAIL);
|
||||
let server = provider.get_smtp_server().unwrap();
|
||||
assert_eq!(server.protocol, Protocol::SMTP);
|
||||
assert_eq!(server.socket, Socket::STARTTLS);
|
||||
assert_eq!(server.hostname, "smtp.nauta.cu");
|
||||
assert_eq!(server.port, 25);
|
||||
assert_eq!(server.username_pattern, UsernamePattern::EMAIL);
|
||||
|
||||
let provider = get_provider_info("user@gmail.com").unwrap();
|
||||
assert!(provider.status == Status::PREPARATION);
|
||||
assert!(!provider.before_login_hint.is_empty());
|
||||
assert!(!provider.overview_page.is_empty());
|
||||
|
||||
let provider = get_provider_info("user@googlemail.com").unwrap();
|
||||
assert!(provider.status == Status::PREPARATION);
|
||||
}
|
||||
}
|
||||
148
src/provider/update.py
Executable file
148
src/provider/update.py
Executable file
@@ -0,0 +1,148 @@
|
||||
#!/usr/bin/env python3
|
||||
# if the yaml import fails, run "pip install pyyaml"
|
||||
|
||||
import sys
|
||||
import os
|
||||
import yaml
|
||||
|
||||
out_all = ""
|
||||
out_domains = ""
|
||||
domains_dict = {}
|
||||
|
||||
|
||||
def cleanstr(s):
|
||||
s = s.strip()
|
||||
s = s.replace("\n", " ")
|
||||
s = s.replace("\\", "\\\\")
|
||||
s = s.replace("\"", "\\\"")
|
||||
return s
|
||||
|
||||
|
||||
def file2varname(f):
|
||||
f = f[f.rindex("/")+1:].replace(".md", "")
|
||||
f = f.replace(".", "_")
|
||||
f = f.replace("-", "_")
|
||||
return "P_" + f.upper()
|
||||
|
||||
|
||||
def file2url(f):
|
||||
f = f[f.rindex("/")+1:].replace(".md", "")
|
||||
f = f.replace(".", "-")
|
||||
return "https://providers.delta.chat/" + f
|
||||
|
||||
|
||||
def process_data(data, file):
|
||||
status = data.get("status", "")
|
||||
if status != "OK" and status != "PREPARATION" and status != "BROKEN":
|
||||
raise TypeError("bad status")
|
||||
|
||||
comment = ""
|
||||
domains = ""
|
||||
if not "domains" in data:
|
||||
raise TypeError("no domains found")
|
||||
for domain in data["domains"]:
|
||||
domain = cleanstr(domain)
|
||||
if domain == "" or domain.count(".") < 1 or domain.lower() != domain:
|
||||
raise TypeError("bad domain: " + domain)
|
||||
|
||||
global domains_dict
|
||||
if domains_dict.get(domain, False):
|
||||
raise TypeError("domain used twice: " + domain)
|
||||
domains_dict[domain] = True
|
||||
|
||||
domains += " (\"" + domain + "\", &*" + file2varname(file) + "),\n"
|
||||
comment += domain + ", "
|
||||
|
||||
|
||||
server = ""
|
||||
has_imap = False
|
||||
has_smtp = False
|
||||
if "server" in data:
|
||||
for s in data["server"]:
|
||||
hostname = cleanstr(s.get("hostname", ""))
|
||||
port = int(s.get("port", ""))
|
||||
if hostname == "" or hostname.count(".") < 1 or port <= 0:
|
||||
raise TypeError("bad hostname or port")
|
||||
|
||||
protocol = s.get("type", "").upper()
|
||||
if protocol == "IMAP":
|
||||
has_imap = True
|
||||
elif protocol == "SMTP":
|
||||
has_smtp = True
|
||||
else:
|
||||
raise TypeError("bad protocol")
|
||||
|
||||
socket = s.get("socket", "").upper()
|
||||
if socket != "STARTTLS" and socket != "SSL":
|
||||
raise TypeError("bad socket")
|
||||
|
||||
username_pattern = s.get("username_pattern", "EMAIL").upper()
|
||||
if username_pattern != "EMAIL" and username_pattern != "EMAILLOCALPART":
|
||||
raise TypeError("bad username pattern")
|
||||
|
||||
server += (" Server { protocol: " + protocol + ", socket: " + socket + ", hostname: \""
|
||||
+ hostname + "\", port: " + str(port) + ", username_pattern: " + username_pattern + " },\n")
|
||||
|
||||
provider = ""
|
||||
before_login_hint = cleanstr(data.get("before_login_hint", ""))
|
||||
after_login_hint = cleanstr(data.get("after_login_hint", ""))
|
||||
if (not has_imap and not has_smtp) or (has_imap and has_smtp):
|
||||
provider += " static ref " + file2varname(file) + ": Provider = Provider {\n"
|
||||
provider += " status: Status::" + status + ",\n"
|
||||
provider += " before_login_hint: \"" + before_login_hint + "\",\n"
|
||||
provider += " after_login_hint: \"" + after_login_hint + "\",\n"
|
||||
provider += " overview_page: \"" + file2url(file) + "\",\n"
|
||||
provider += " server: vec![\n" + server + " ],\n"
|
||||
provider += " };\n\n"
|
||||
else:
|
||||
raise TypeError("SMTP and IMAP must be specified together or left out both")
|
||||
|
||||
if status != "OK" and before_login_hint == "":
|
||||
raise TypeError("status PREPARATION or BROKEN requires before_login_hint: " + file)
|
||||
|
||||
# finally, add the provider
|
||||
global out_all, out_domains
|
||||
out_all += " // " + file[file.rindex("/")+1:] + ": " + comment.strip(", ") + "\n"
|
||||
if status == "OK" and before_login_hint == "" and after_login_hint == "" and server == "":
|
||||
out_all += " // - skipping provider with status OK and no special things to do\n\n"
|
||||
else:
|
||||
out_all += provider
|
||||
out_domains += domains
|
||||
|
||||
|
||||
def process_file(file):
|
||||
print("processing file: " + file, file=sys.stderr)
|
||||
with open(file) as f:
|
||||
# load_all() loads "---"-separated yamls -
|
||||
# by coincidence, this is also the frontmatter separator :)
|
||||
data = next(yaml.load_all(f, Loader=yaml.SafeLoader))
|
||||
process_data(data, file)
|
||||
|
||||
|
||||
def process_dir(dir):
|
||||
print("processing directory: " + dir, file=sys.stderr)
|
||||
files = [f for f in os.listdir(dir) if f.endswith(".md")]
|
||||
files.sort()
|
||||
for f in files:
|
||||
process_file(os.path.join(dir, f))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
raise SystemExit("usage: update.py DIR_WITH_MD_FILES > data.rs")
|
||||
|
||||
out_all = ("// file generated by src/provider/update.py\n\n"
|
||||
"use crate::provider::Protocol::*;\n"
|
||||
"use crate::provider::Socket::*;\n"
|
||||
"use crate::provider::UsernamePattern::*;\n"
|
||||
"use crate::provider::*;\n"
|
||||
"use std::collections::HashMap;\n\n"
|
||||
"lazy_static::lazy_static! {\n\n")
|
||||
|
||||
process_dir(sys.argv[1])
|
||||
|
||||
out_all += " pub static ref PROVIDER_DATA: HashMap<&'static str, &'static Provider> = [\n"
|
||||
out_all += out_domains;
|
||||
out_all += " ].iter().copied().collect();\n}"
|
||||
|
||||
print(out_all)
|
||||
Reference in New Issue
Block a user