use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC}; use quick_xml; use quick_xml::events::{BytesEnd, BytesStart, BytesText}; use crate::constants::Event; use crate::context::Context; use crate::dc_e2ee::*; use crate::dc_loginparam::*; use crate::dc_tools::*; use crate::imap::*; use crate::job::*; use crate::oauth2::*; use crate::param::Params; use crate::types::*; use crate::x::*; use std::ptr; macro_rules! progress { ($context:tt, $progress:expr) => { assert!( $progress >= 0 && $progress <= 1000, "value in range 0..1000 expected with: 0=error, 1..999=progress, 1000=success" ); $context.call_cb( Event::CONFIGURE_PROGRESS, $progress as uintptr_t, 0 as uintptr_t, ); }; } /* ****************************************************************************** * Configure folders ******************************************************************************/ #[derive(Copy, Clone)] #[repr(C)] struct dc_imapfolder_t { pub name_to_select: *mut libc::c_char, pub name_utf8: *mut libc::c_char, pub meaning: libc::c_int, } /* ****************************************************************************** * Thunderbird's Autoconfigure ******************************************************************************/ /* documentation: https://developer.mozilla.org/en-US/docs/Mozilla/Thunderbird/Autoconfiguration */ #[repr(C)] struct moz_autoconfigure_t<'a> { pub in_0: &'a dc_loginparam_t, pub in_emaildomain: *mut libc::c_char, pub in_emaillocalpart: *mut libc::c_char, pub out: dc_loginparam_t, pub out_imap_set: libc::c_int, pub out_smtp_set: libc::c_int, pub tag_server: libc::c_int, pub tag_config: libc::c_int, } /* ****************************************************************************** * Outlook's Autodiscover ******************************************************************************/ #[repr(C)] struct outlk_autodiscover_t<'a> { pub in_0: &'a dc_loginparam_t, pub out: dc_loginparam_t, pub out_imap_set: libc::c_int, pub out_smtp_set: libc::c_int, pub tag_config: libc::c_int, pub config: [*mut libc::c_char; 6], pub redirect: *mut libc::c_char, } // connect pub unsafe fn dc_configure(context: &Context) { if 0 != dc_has_ongoing(context) { warn!( context, 0, "There is already another ongoing process running.", ); return; } job_kill_action(context, Action::ConfigureImap); job_add(context, Action::ConfigureImap, 0, Params::new(), 0); } unsafe fn dc_has_ongoing(context: &Context) -> libc::c_int { let s_a = context.running_state.clone(); let s = s_a.read().unwrap(); if s.ongoing_running || !s.shall_stop_ongoing { 1 } else { 0 } } pub fn dc_is_configured(context: &Context) -> libc::c_int { if context .sql .get_config_int(context, "configured") .unwrap_or_default() > 0 { 1 } else { 0 } } pub fn dc_stop_ongoing_process(context: &Context) { let s_a = context.running_state.clone(); let mut s = s_a.write().unwrap(); if s.ongoing_running && !s.shall_stop_ongoing { info!(context, 0, "Signaling the ongoing process to stop ASAP.",); s.shall_stop_ongoing = true; } else { info!(context, 0, "No ongoing process to stop.",); }; } // the other dc_job_do_DC_JOB_*() functions are declared static in the c-file #[allow(non_snake_case, unused_must_use)] pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: &Job) { let flags: libc::c_int; let mut success = false; let mut imap_connected_here = false; let mut smtp_connected_here = false; let mut ongoing_allocated_here = false; let mut param_autoconfig = None; if !(0 == dc_alloc_ongoing(context)) { ongoing_allocated_here = true; if !context.sql.is_open() { error!(context, 0, "Cannot configure, database not opened.",); } else { context.inbox.read().unwrap().disconnect(context); context .sentbox_thread .read() .unwrap() .imap .disconnect(context); context .mvbox_thread .read() .unwrap() .imap .disconnect(context); context.smtp.clone().lock().unwrap().disconnect(); info!(context, 0, "Configure ...",); let s_a = context.running_state.clone(); let s = s_a.read().unwrap(); if !s.shall_stop_ongoing { progress!(context, 1); let mut param = dc_loginparam_read(context, &context.sql, ""); if param.addr.is_empty() { error!(context, 0, "Please enter an email address.",); } else { let ok_to_continue0; if 0 != param.server_flags & 0x2 { // the used oauth2 addr may differ, check this. // if dc_get_oauth2_addr() is not available in the oauth2 implementation, // just use the given one. if s.shall_stop_ongoing { ok_to_continue0 = false; } else { progress!(context, 10); if let Some(oauth2_addr) = dc_get_oauth2_addr(context, ¶m.addr, ¶m.mail_pw) .and_then(|e| e.parse().ok()) { param.addr = oauth2_addr; context .sql .set_config(context, "addr", Some(param.addr.as_str())) .ok(); } if s.shall_stop_ongoing { ok_to_continue0 = false; } else { progress!(context, 20); ok_to_continue0 = true; } } } else { ok_to_continue0 = true; } if ok_to_continue0 { let parsed: Result = param.addr.parse(); let mut ok_to_continue7 = false; if parsed.is_err() { error!(context, 0, "Bad email-address."); } else { let parsed = parsed.unwrap(); let param_domain = parsed.domain; let param_addr_urlencoded = utf8_percent_encode(¶m.addr, NON_ALPHANUMERIC).to_string(); if !s.shall_stop_ongoing { progress!(context, 200); /* 2. Autoconfig **************************************************************************/ if param.mail_server.is_empty() && param.mail_port == 0 && param.send_server.is_empty() && param.send_port == 0 && param.send_user.is_empty() && param.server_flags & !0x2 == 0 { let ok_to_continue1; /*&¶m->mail_user ==NULL -- the user can enter a loginname which is used by autoconfig then */ /*&¶m->send_pw ==NULL -- the password cannot be auto-configured and is no criterion for autoconfig or not */ /* flags but OAuth2 avoid autoconfig */ let keep_flags = param.server_flags & 0x2; /* A. Search configurations from the domain used in the email-address, prefer encrypted */ if param_autoconfig.is_none() { let url = format!( "https://autoconfig.{}/mail/config-v1.1.xml?emailaddress={}", param_domain, param_addr_urlencoded ); param_autoconfig = moz_autoconfigure(context, &url, ¶m); if s.shall_stop_ongoing { ok_to_continue1 = false; } else { progress!(context, 300); ok_to_continue1 = true; } } else { ok_to_continue1 = true; } if ok_to_continue1 { let ok_to_continue2; if param_autoconfig.is_none() { // the doc does not mention `emailaddress=`, however, Thunderbird adds it, see https://releases.mozilla.org/pub/thunderbird/ , which makes some sense let url = format!( "https://{}/.well-known/autoconfig/mail/config-v1.1.xml?emailaddress={}", param_domain, param_addr_urlencoded ); param_autoconfig = moz_autoconfigure(context, &url, ¶m); if s.shall_stop_ongoing { ok_to_continue2 = false; } else { progress!(context, 310); ok_to_continue2 = true; } } else { ok_to_continue2 = true; } if ok_to_continue2 { let mut i: libc::c_int = 0; let ok_to_continue3; loop { if !(i <= 1) { ok_to_continue3 = true; break; } if param_autoconfig.is_none() { /* Outlook uses always SSL but different domains */ let url = format!( "https://{}{}/autodiscover/autodiscover.xml", if i == 0 { "" } else { "autodiscover." }, param_domain ); param_autoconfig = outlk_autodiscover(context, &url, ¶m); if s.shall_stop_ongoing { ok_to_continue3 = false; break; } progress!(context, 320 + i * 10); } i += 1 } if ok_to_continue3 { let ok_to_continue4; if param_autoconfig.is_none() { let url = format!( "http://autoconfig.{}/mail/config-v1.1.xml?emailaddress={}", param_domain, param_addr_urlencoded ); param_autoconfig = moz_autoconfigure(context, &url, ¶m); if s.shall_stop_ongoing { ok_to_continue4 = false; } else { progress!(context, 340); ok_to_continue4 = true; } } else { ok_to_continue4 = true; } if ok_to_continue4 { let ok_to_continue5; if param_autoconfig.is_none() { // do not transfer the email-address unencrypted let url = format!( "http://{}/.well-known/autoconfig/mail/config-v1.1.xml", param_domain ); param_autoconfig = moz_autoconfigure( context, &url, ¶m, ); if s.shall_stop_ongoing { ok_to_continue5 = false; } else { progress!(context, 350); ok_to_continue5 = true; } } else { ok_to_continue5 = true; } if ok_to_continue5 { let ok_to_continue6; /* B. If we have no configuration yet, search configuration in Thunderbird's centeral database */ if param_autoconfig.is_none() { /* always SSL for Thunderbird's database */ let url = format!("https://autoconfig.thunderbird.net/v1.1/{}", param_domain ); param_autoconfig = moz_autoconfigure( context, &url, ¶m, ); if s.shall_stop_ongoing { ok_to_continue6 = false; } else { progress!(context, 500); ok_to_continue6 = true; } } else { ok_to_continue6 = true; } if ok_to_continue6 { if let Some(ref cfg) = param_autoconfig { let r = dc_loginparam_get_readable(cfg); info!( context, 0, "Got autoconfig: {}", r ); if !cfg.mail_user.is_empty() { param.mail_user = cfg.mail_user.clone(); } param.mail_server = cfg.mail_server.clone(); param.mail_port = cfg.mail_port; param.send_server = cfg.send_server.clone(); param.send_port = cfg.send_port; param.send_user = cfg.send_user.clone(); param.server_flags = cfg.server_flags; } param.server_flags |= keep_flags; ok_to_continue7 = true; } } } } } } } } else { ok_to_continue7 = true; } if ok_to_continue7 { if param.mail_server.is_empty() { param.mail_server = format!("imap.{}", param_domain,) } if param.mail_port == 0 { param.mail_port = if 0 != param.server_flags & (0x100 | 0x400) { 143 } else { 993 } } if param.mail_user.is_empty() { param.mail_user = param.addr.clone(); } if param.send_server.is_empty() && !param.mail_server.is_empty() { param.send_server = param.mail_server.clone(); if param.send_server.starts_with("imap.") { param.send_server = param.send_server.replacen("imap", "smtp", 1); } } if param.send_port == 0 { param.send_port = if 0 != param.server_flags & 0x10000 { 587 } else if 0 != param.server_flags & 0x40000 { 25 } else { 465 } } if param.send_user.is_empty() && !param.mail_user.is_empty() { param.send_user = param.mail_user.clone(); } if param.send_pw.is_empty() && !param.mail_pw.is_empty() { param.send_pw = param.mail_pw.clone() } if !dc_exactly_one_bit_set(param.server_flags & (0x2 | 0x4)) { param.server_flags &= !(0x2 | 0x4); param.server_flags |= 0x4 } if !dc_exactly_one_bit_set( param.server_flags & (0x100 | 0x200 | 0x400), ) { param.server_flags &= !(0x100 | 0x200 | 0x400); param.server_flags |= if param.send_port == 143 { 0x100 } else { 0x200 } } if !dc_exactly_one_bit_set( param.server_flags & (0x10000 | 0x20000 | 0x40000), ) { param.server_flags &= !(0x10000 | 0x20000 | 0x40000); param.server_flags |= if param.send_port == 587 { 0x10000 } else if param.send_port == 25 { 0x40000 } else { 0x20000 } } /* do we have a complete configuration? */ if param.mail_server.is_empty() || param.mail_port == 0 || param.mail_user.is_empty() || param.mail_pw.is_empty() || param.send_server.is_empty() || param.send_port == 0 || param.send_user.is_empty() || param.send_pw.is_empty() || param.server_flags == 0 { error!(context, 0, "Account settings incomplete.",); } else if !s.shall_stop_ongoing { progress!(context, 600); /* try to connect to IMAP - if we did not got an autoconfig, do some further tries with different settings and username variations */ let ok_to_continue8; let mut username_variation = 0; loop { if !(username_variation <= 1) { ok_to_continue8 = true; break; } let r_0 = dc_loginparam_get_readable(¶m); info!(context, 0, "Trying: {}", r_0,); if context.inbox.read().unwrap().connect(context, ¶m) { ok_to_continue8 = true; break; } if !param_autoconfig.is_none() { ok_to_continue8 = false; break; } // probe STARTTLS/993 if s.shall_stop_ongoing { ok_to_continue8 = false; break; } progress!(context, 650 + username_variation * 30); param.server_flags &= !(0x100 | 0x200 | 0x400); param.server_flags |= 0x100; let r_1 = dc_loginparam_get_readable(¶m); info!(context, 0, "Trying: {}", r_1,); if context.inbox.read().unwrap().connect(context, ¶m) { ok_to_continue8 = true; break; } // probe STARTTLS/143 if s.shall_stop_ongoing { ok_to_continue8 = false; break; } progress!(context, 660 + username_variation * 30); param.mail_port = 143; let r_2 = dc_loginparam_get_readable(¶m); info!(context, 0, "Trying: {}", r_2,); if context.inbox.read().unwrap().connect(context, ¶m) { ok_to_continue8 = true; break; } if 0 != username_variation { ok_to_continue8 = false; break; } // next probe round with only the localpart of the email-address as the loginname if s.shall_stop_ongoing { ok_to_continue8 = false; break; } progress!(context, 670 + username_variation * 30); param.server_flags &= !(0x100 | 0x200 | 0x400); param.server_flags |= 0x200; param.mail_port = 993; if let Some(at) = param.mail_user.find('@') { param.mail_user = param.mail_user.split_at(at).0.to_string(); } if let Some(at) = param.send_user.find('@') { param.send_user = param.send_user.split_at(at).0.to_string(); } username_variation += 1 } if ok_to_continue8 { imap_connected_here = true; if !s.shall_stop_ongoing { progress!(context, 800); let ok_to_continue9; /* try to connect to SMTP - if we did not got an autoconfig, the first try was SSL-465 and we do a second try with STARTTLS-587 */ if !context .smtp .clone() .lock() .unwrap() .connect(context, ¶m) { if !param_autoconfig.is_none() { ok_to_continue9 = false; } else if s.shall_stop_ongoing { ok_to_continue9 = false; } else { progress!(context, 850); param.server_flags &= !(0x10000 | 0x20000 | 0x40000); param.server_flags |= 0x10000; param.send_port = 587; let r_3 = dc_loginparam_get_readable(¶m); info!(context, 0, "Trying: {}", r_3,); if !context .smtp .clone() .lock() .unwrap() .connect(context, ¶m) { if s.shall_stop_ongoing { ok_to_continue9 = false; } else { progress!(context, 860); param.server_flags &= !(0x10000 | 0x20000 | 0x40000); param.server_flags |= 0x10000; param.send_port = 25; let r_4 = dc_loginparam_get_readable(¶m); info!(context, 0, "Trying: {}", r_4); if !context .smtp .clone() .lock() .unwrap() .connect(context, ¶m) { ok_to_continue9 = false; } else { ok_to_continue9 = true; } } } else { ok_to_continue9 = true; } } } else { ok_to_continue9 = true; } if ok_to_continue9 { smtp_connected_here = true; if !s.shall_stop_ongoing { progress!(context, 900); flags = if 0 != context .sql .get_config_int(context, "mvbox_watch") .unwrap_or_else(|| 1) || 0 != context .sql .get_config_int(context, "mvbox_move") .unwrap_or_else(|| 1) { 0x1 } else { 0 }; context .inbox .read() .unwrap() .configure_folders(context, flags); if !s.shall_stop_ongoing { progress!(context, 910); dc_loginparam_write( context, ¶m, &context.sql, "configured_", ); context .sql .set_config_int( context, "configured", 1, ) .ok(); if !s.shall_stop_ongoing { progress!(context, 920); dc_ensure_secret_key_exists(context); success = true; info!( context, 0, "Configure completed." ); if !s.shall_stop_ongoing { progress!(context, 940); } } } } } } } } } } } } } } } if imap_connected_here { context.inbox.read().unwrap().disconnect(context); } if smtp_connected_here { context.smtp.clone().lock().unwrap().disconnect(); } /* if !success { // disconnect if configure did not succeed if imap_connected_here { // context.inbox.read().unwrap().disconnect(context); } if smtp_connected_here { // context.smtp.clone().lock().unwrap().disconnect(); } } else { assert!(imap_connected_here && smtp_connected_here); info!( context, 0, "Keeping IMAP/SMTP connections open after successful configuration" ); } */ if ongoing_allocated_here { dc_free_ongoing(context); } progress!(context, (if success { 1000 } else { 0 })); } pub unsafe fn dc_free_ongoing(context: &Context) { let s_a = context.running_state.clone(); let mut s = s_a.write().unwrap(); s.ongoing_running = false; s.shall_stop_ongoing = true; } unsafe fn moz_autoconfigure( context: &Context, url: &str, param_in: &dc_loginparam_t, ) -> Option { let mut moz_ac = moz_autoconfigure_t { in_0: param_in, in_emaildomain: std::ptr::null_mut(), in_emaillocalpart: std::ptr::null_mut(), out: dc_loginparam_new(), out_imap_set: 0, out_smtp_set: 0, tag_server: 0, tag_config: 0, }; let url_c = url.strdup(); let xml_raw = read_autoconf_file(context, url_c); free(url_c as *mut libc::c_void); if xml_raw.is_null() { return None; } moz_ac.in_emaillocalpart = param_in.addr.strdup(); let p = strchr(moz_ac.in_emaillocalpart, '@' as i32); if p.is_null() { free(xml_raw as *mut libc::c_void); free(moz_ac.in_emaildomain as *mut libc::c_void); free(moz_ac.in_emaillocalpart as *mut libc::c_void); return None; } *p = 0 as libc::c_char; moz_ac.in_emaildomain = dc_strdup(p.offset(1isize)); let mut reader = quick_xml::Reader::from_str(as_str(xml_raw)); reader.trim_text(true); let mut buf = Vec::new(); loop { match reader.read_event(&mut buf) { Ok(quick_xml::events::Event::Start(ref e)) => { moz_autoconfigure_starttag_cb(e, &mut moz_ac, &reader) } Ok(quick_xml::events::Event::End(ref e)) => moz_autoconfigure_endtag_cb(e, &mut moz_ac), Ok(quick_xml::events::Event::Text(ref e)) => { moz_autoconfigure_text_cb(e, &mut moz_ac, &reader) } Err(e) => { error!( context, 0, "Configure xml: Error at position {}: {:?}", reader.buffer_position(), e ); } Ok(quick_xml::events::Event::Eof) => break, _ => (), } buf.clear(); } if moz_ac.out.mail_server.is_empty() || moz_ac.out.mail_port == 0 || moz_ac.out.send_server.is_empty() || moz_ac.out.send_port == 0 { let r = dc_loginparam_get_readable(&moz_ac.out); warn!(context, 0, "Bad or incomplete autoconfig: {}", r,); free(xml_raw as *mut libc::c_void); free(moz_ac.in_emaildomain as *mut libc::c_void); free(moz_ac.in_emaillocalpart as *mut libc::c_void); return None; } free(xml_raw as *mut libc::c_void); free(moz_ac.in_emaildomain as *mut libc::c_void); free(moz_ac.in_emaillocalpart as *mut libc::c_void); Some(moz_ac.out) } fn moz_autoconfigure_text_cb( event: &BytesText, moz_ac: &mut moz_autoconfigure_t, reader: &quick_xml::Reader, ) { let val = event.unescape_and_decode(reader).unwrap_or_default(); let addr = &moz_ac.in_0.addr; let email_local = as_str(moz_ac.in_emaillocalpart); let email_domain = as_str(moz_ac.in_emaildomain); let val = val .trim() .replace("%EMAILADDRESS%", addr) .replace("%EMAILLOCALPART%", email_local) .replace("%EMAILDOMAIN%", email_domain); if moz_ac.tag_server == 1 { match moz_ac.tag_config { 10 => moz_ac.out.mail_server = val, 11 => moz_ac.out.mail_port = val.parse().unwrap_or_default(), 12 => moz_ac.out.mail_user = val, 13 => { let val_lower = val.to_lowercase(); if val_lower == "ssl" { moz_ac.out.server_flags |= 0x200 } if val_lower == "starttls" { moz_ac.out.server_flags |= 0x100 } if val_lower == "plain" { moz_ac.out.server_flags |= 0x400 } } _ => {} } } else if moz_ac.tag_server == 2 { match moz_ac.tag_config { 10 => moz_ac.out.send_server = val, 11 => moz_ac.out.send_port = val.parse().unwrap_or_default(), 12 => moz_ac.out.send_user = val, 13 => { let val_lower = val.to_lowercase(); if val_lower == "ssl" { moz_ac.out.server_flags |= 0x20000 } if val_lower == "starttls" { moz_ac.out.server_flags |= 0x10000 } if val_lower == "plain" { moz_ac.out.server_flags |= 0x40000 } } _ => {} } } } fn moz_autoconfigure_endtag_cb(event: &BytesEnd, moz_ac: &mut moz_autoconfigure_t) { let tag = String::from_utf8_lossy(event.name()).trim().to_lowercase(); if tag == "incomingserver" { moz_ac.tag_server = 0; moz_ac.tag_config = 0; moz_ac.out_imap_set = 1; } else if tag == "outgoingserver" { moz_ac.tag_server = 0; moz_ac.tag_config = 0; moz_ac.out_smtp_set = 1; } else { moz_ac.tag_config = 0; } } fn moz_autoconfigure_starttag_cb( event: &BytesStart, moz_ac: &mut moz_autoconfigure_t, reader: &quick_xml::Reader, ) { let tag = String::from_utf8_lossy(event.name()).trim().to_lowercase(); if tag == "incomingserver" { moz_ac.tag_server = if let Some(typ) = event.attributes().find(|attr| { attr.as_ref() .map(|a| String::from_utf8_lossy(a.key).trim().to_lowercase() == "type") .unwrap_or_default() }) { let typ = typ .unwrap() .unescape_and_decode_value(reader) .unwrap_or_default() .to_lowercase(); if typ == "imap" && moz_ac.out_imap_set == 0 { 1 } else { 0 } } else { 0 }; moz_ac.tag_config = 0; } else if tag == "outgoingserver" { moz_ac.tag_server = if moz_ac.out_smtp_set == 0 { 2 } else { 0 }; moz_ac.tag_config = 0; } else if tag == "hostname" { moz_ac.tag_config = 10; } else if tag == "port" { moz_ac.tag_config = 11; } else if tag == "sockettype" { moz_ac.tag_config = 13; } else if tag == "username" { moz_ac.tag_config = 12; } } fn read_autoconf_file(context: &Context, url: *const libc::c_char) -> *mut libc::c_char { info!(context, 0, "Testing {} ...", to_string(url)); match reqwest::Client::new() .get(as_str(url)) .send() .and_then(|mut res| res.text()) { Ok(res) => unsafe { res.strdup() }, Err(_err) => { info!(context, 0, "Can\'t read file.",); std::ptr::null_mut() } } } unsafe fn outlk_autodiscover( context: &Context, url__: &str, param_in: &dc_loginparam_t, ) -> Option { let mut xml_raw: *mut libc::c_char = ptr::null_mut(); let mut url = url__.strdup(); let mut outlk_ad = outlk_autodiscover_t { in_0: param_in, out: dc_loginparam_new(), out_imap_set: 0, out_smtp_set: 0, tag_config: 0, config: [ptr::null_mut(); 6], redirect: ptr::null_mut(), }; let ok_to_continue; let mut i = 0; loop { if !(i < 10) { ok_to_continue = true; break; } memset( &mut outlk_ad as *mut outlk_autodiscover_t as *mut libc::c_void, 0, ::std::mem::size_of::(), ); xml_raw = read_autoconf_file(context, url); if xml_raw.is_null() { ok_to_continue = false; break; } let mut reader = quick_xml::Reader::from_str(as_str(xml_raw)); reader.trim_text(true); let mut buf = Vec::new(); loop { match reader.read_event(&mut buf) { Ok(quick_xml::events::Event::Start(ref e)) => { outlk_autodiscover_starttag_cb(e, &mut outlk_ad) } Ok(quick_xml::events::Event::End(ref e)) => { outlk_autodiscover_endtag_cb(e, &mut outlk_ad) } Ok(quick_xml::events::Event::Text(ref e)) => { outlk_autodiscover_text_cb(e, &mut outlk_ad, &reader) } Err(e) => { error!( context, 0, "Configure xml: Error at position {}: {:?}", reader.buffer_position(), e ); } Ok(quick_xml::events::Event::Eof) => break, _ => (), } buf.clear(); } if !(!outlk_ad.config[5].is_null() && 0 != *outlk_ad.config[5usize].offset(0isize) as libc::c_int) { ok_to_continue = true; break; } free(url as *mut libc::c_void); url = dc_strdup(outlk_ad.config[5usize]); outlk_clean_config(&mut outlk_ad); free(xml_raw as *mut libc::c_void); xml_raw = ptr::null_mut(); i += 1; } if ok_to_continue { if outlk_ad.out.mail_server.is_empty() || outlk_ad.out.mail_port == 0 || outlk_ad.out.send_server.is_empty() || outlk_ad.out.send_port == 0 { let r = dc_loginparam_get_readable(&outlk_ad.out); warn!(context, 0, "Bad or incomplete autoconfig: {}", r,); free(url as *mut libc::c_void); free(xml_raw as *mut libc::c_void); outlk_clean_config(&mut outlk_ad); return None; } } free(url as *mut libc::c_void); free(xml_raw as *mut libc::c_void); outlk_clean_config(&mut outlk_ad); Some(outlk_ad.out) } unsafe fn outlk_clean_config(mut outlk_ad: *mut outlk_autodiscover_t) { for i in 0..6 { free((*outlk_ad).config[i] as *mut libc::c_void); (*outlk_ad).config[i] = 0 as *mut libc::c_char; } } fn outlk_autodiscover_text_cb( event: &BytesText, outlk_ad: &mut outlk_autodiscover_t, reader: &quick_xml::Reader, ) { let val = event.unescape_and_decode(reader).unwrap_or_default(); unsafe { free(outlk_ad.config[outlk_ad.tag_config as usize].cast()); outlk_ad.config[outlk_ad.tag_config as usize] = val.trim().strdup(); } } unsafe fn outlk_autodiscover_endtag_cb(event: &BytesEnd, outlk_ad: &mut outlk_autodiscover_t) { let tag = String::from_utf8_lossy(event.name()).trim().to_lowercase(); if tag == "protocol" { if !outlk_ad.config[1].is_null() { let port = dc_atoi_null_is_0(outlk_ad.config[3]); let ssl_on = (!outlk_ad.config[4].is_null() && strcasecmp( outlk_ad.config[4], b"on\x00" as *const u8 as *const libc::c_char, ) == 0) as libc::c_int; let ssl_off = (!outlk_ad.config[4].is_null() && strcasecmp( outlk_ad.config[4], b"off\x00" as *const u8 as *const libc::c_char, ) == 0) as libc::c_int; if strcasecmp( outlk_ad.config[1], b"imap\x00" as *const u8 as *const libc::c_char, ) == 0 && outlk_ad.out_imap_set == 0 { outlk_ad.out.mail_server = to_string(outlk_ad.config[2]); outlk_ad.out.mail_port = port; if 0 != ssl_on { outlk_ad.out.server_flags |= 0x200 } else if 0 != ssl_off { outlk_ad.out.server_flags |= 0x400 } outlk_ad.out_imap_set = 1 } else if strcasecmp( outlk_ad.config[1usize], b"smtp\x00" as *const u8 as *const libc::c_char, ) == 0 && outlk_ad.out_smtp_set == 0 { outlk_ad.out.send_server = to_string(outlk_ad.config[2]); outlk_ad.out.send_port = port; if 0 != ssl_on { outlk_ad.out.server_flags |= 0x20000 } else if 0 != ssl_off { outlk_ad.out.server_flags |= 0x40000 } outlk_ad.out_smtp_set = 1 } } outlk_clean_config(outlk_ad); } outlk_ad.tag_config = 0; } fn outlk_autodiscover_starttag_cb(event: &BytesStart, outlk_ad: &mut outlk_autodiscover_t) { let tag = String::from_utf8_lossy(event.name()).trim().to_lowercase(); if tag == "protocol" { unsafe { outlk_clean_config(outlk_ad) }; } else if tag == "type" { outlk_ad.tag_config = 1 } else if tag == "server" { outlk_ad.tag_config = 2 } else if tag == "port" { outlk_ad.tag_config = 3 } else if tag == "ssl" { outlk_ad.tag_config = 4 } else if tag == "redirecturl" { outlk_ad.tag_config = 5 }; } pub unsafe fn dc_alloc_ongoing(context: &Context) -> libc::c_int { if 0 != dc_has_ongoing(context) { warn!( context, 0, "There is already another ongoing process running.", ); return 0; } let s_a = context.running_state.clone(); let mut s = s_a.write().unwrap(); s.ongoing_running = true; s.shall_stop_ongoing = false; 1 } pub fn dc_connect_to_configured_imap(context: &Context, imap: &Imap) -> libc::c_int { let mut ret_connected = 0; if imap.is_connected() { ret_connected = 1 } else if context .sql .get_config_int(context, "configured") .unwrap_or_default() == 0 { warn!(context, 0, "Not configured, cannot connect.",); } else { let param = dc_loginparam_read(context, &context.sql, "configured_"); // the trailing underscore is correct if imap.connect(context, ¶m) { ret_connected = 2; } } ret_connected }