mirror of
https://github.com/chatmail/core.git
synced 2026-04-02 05:22:14 +03:00
Compare commits
19 Commits
1.78.0
...
fix_few_ma
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a208c4f6b | ||
|
|
25ab59eb93 | ||
|
|
e6f737be9d | ||
|
|
e94a896478 | ||
|
|
a7a0277330 | ||
|
|
62a2f70fab | ||
|
|
04ec7f86ef | ||
|
|
f9e27934f5 | ||
|
|
f1b978c9c7 | ||
|
|
4eea6b297a | ||
|
|
0c77cadf19 | ||
|
|
b616830aea | ||
|
|
4bc637d6d8 | ||
|
|
bb605e28aa | ||
|
|
deddb8fde4 | ||
|
|
a59f0bd885 | ||
|
|
881e15d218 | ||
|
|
7bf825a253 | ||
|
|
fe7d99ae11 |
520
Cargo.lock
generated
520
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,6 @@ license = "MPL"
|
||||
|
||||
[dependencies]
|
||||
deltachat_derive = { path = "./deltachat_derive" }
|
||||
mmime = { version = "0.1.2", path = "./mmime" }
|
||||
|
||||
libc = "0.2.51"
|
||||
pgp = { git = "https://github.com/rpgp/rpgp", branch = "master", default-features = false }
|
||||
@@ -18,11 +17,12 @@ smallvec = "0.6.9"
|
||||
reqwest = { version = "0.9.15", default-features = false, features = ["rustls-tls"] }
|
||||
num-derive = "0.2.5"
|
||||
num-traits = "0.2.6"
|
||||
lettre = { git = "https://github.com/deltachat/lettre", branch = "feat/rustls" }
|
||||
lettre = { git = "https://github.com/deltachat/lettre", branch = "feat/mail" }
|
||||
lettre_email = { git = "https://github.com/deltachat/lettre", branch = "feat/mail" }
|
||||
async-imap = { git = "https://github.com/async-email/async-imap", branch="master" }
|
||||
async-tls = "0.6"
|
||||
async-std = { version = "1.0", features = ["unstable"] }
|
||||
base64 = "0.10"
|
||||
base64 = "0.11"
|
||||
charset = "0.1"
|
||||
percent-encoding = "2.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
@@ -47,13 +47,13 @@ image-meta = "0.1.0"
|
||||
quick-xml = "0.15.0"
|
||||
escaper = "0.1.0"
|
||||
bitflags = "1.1.0"
|
||||
jetscii = "0.4.4"
|
||||
debug_stub_derive = "0.3.0"
|
||||
sanitize-filename = "0.2.1"
|
||||
stop-token = { version = "0.1.1", features = ["unstable"] }
|
||||
rustls = "0.16.0"
|
||||
webpki-roots = "0.18.0"
|
||||
webpki = "0.21.0"
|
||||
mailparse = "0.10.1"
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3.0"
|
||||
@@ -65,7 +65,6 @@ proptest = "0.9.4"
|
||||
members = [
|
||||
"deltachat-ffi",
|
||||
"deltachat_derive",
|
||||
"mmime",
|
||||
]
|
||||
|
||||
[[example]]
|
||||
|
||||
@@ -20,6 +20,7 @@ deltachat-provider-database = "0.2.1"
|
||||
libc = "0.2"
|
||||
human-panic = "1.0.1"
|
||||
num-traits = "0.2.6"
|
||||
failure = "0.1.6"
|
||||
|
||||
[features]
|
||||
default = ["vendored", "nightly", "ringbuf"]
|
||||
|
||||
@@ -25,13 +25,13 @@ use num_traits::{FromPrimitive, ToPrimitive};
|
||||
use deltachat::constants::DC_MSG_ID_LAST_SPECIAL;
|
||||
use deltachat::contact::Contact;
|
||||
use deltachat::context::Context;
|
||||
use deltachat::dc_tools::{
|
||||
as_path, dc_strdup, to_opt_string_lossy, to_string_lossy, OsStrExt, StrExt,
|
||||
};
|
||||
use deltachat::message::MsgId;
|
||||
use deltachat::stock::StockMessage;
|
||||
use deltachat::*;
|
||||
|
||||
mod string;
|
||||
use self::string::*;
|
||||
|
||||
// as C lacks a good and portable error handling,
|
||||
// in general, the C Interface is forgiving wrt to bad parameters.
|
||||
// - objects returned by some functions
|
||||
|
||||
@@ -2,7 +2,7 @@ extern crate deltachat_provider_database;
|
||||
|
||||
use std::ptr;
|
||||
|
||||
use deltachat::dc_tools::{to_string_lossy, StrExt};
|
||||
use crate::string::{to_string_lossy, StrExt};
|
||||
use deltachat_provider_database::StatusState;
|
||||
|
||||
#[no_mangle]
|
||||
|
||||
350
deltachat-ffi/src/string.rs
Normal file
350
deltachat-ffi/src/string.rs
Normal file
@@ -0,0 +1,350 @@
|
||||
use failure::Fail;
|
||||
use std::ffi::{CStr, CString};
|
||||
|
||||
/// Duplicates a string
|
||||
///
|
||||
/// returns an empty string if NULL is given, never returns NULL (exits on errors)
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust,norun
|
||||
/// use deltachat::dc_tools::{dc_strdup, to_string_lossy};
|
||||
/// unsafe {
|
||||
/// let str_a = b"foobar\x00" as *const u8 as *const libc::c_char;
|
||||
/// let str_a_copy = dc_strdup(str_a);
|
||||
/// assert_eq!(to_string_lossy(str_a_copy), "foobar");
|
||||
/// assert_ne!(str_a, str_a_copy);
|
||||
/// }
|
||||
/// ```
|
||||
pub unsafe fn dc_strdup(s: *const libc::c_char) -> *mut libc::c_char {
|
||||
let ret: *mut libc::c_char;
|
||||
if !s.is_null() {
|
||||
ret = libc::strdup(s);
|
||||
assert!(!ret.is_null());
|
||||
} else {
|
||||
ret = libc::calloc(1, 1) as *mut libc::c_char;
|
||||
assert!(!ret.is_null());
|
||||
}
|
||||
|
||||
ret
|
||||
}
|
||||
|
||||
/// Error type for the [OsStrExt] trait
|
||||
#[derive(Debug, Fail, PartialEq)]
|
||||
pub enum CStringError {
|
||||
/// The string contains an interior null byte
|
||||
#[fail(display = "String contains an interior null byte")]
|
||||
InteriorNullByte,
|
||||
/// The string is not valid Unicode
|
||||
#[fail(display = "String is not valid unicode")]
|
||||
NotUnicode,
|
||||
}
|
||||
|
||||
/// Extra convenience methods on [std::ffi::OsStr] to work with `*libc::c_char`.
|
||||
///
|
||||
/// The primary function of this trait is to more easily convert
|
||||
/// [OsStr], [OsString] or [Path] into pointers to C strings. This always
|
||||
/// allocates a new string since it is very common for the source
|
||||
/// string not to have the required terminal null byte.
|
||||
///
|
||||
/// It is implemented for `AsRef<std::ffi::OsStr>>` trait, which
|
||||
/// allows any type which implements this trait to transparently use
|
||||
/// this. This is how the conversion for [Path] works.
|
||||
///
|
||||
/// [OsStr]: std::ffi::OsStr
|
||||
/// [OsString]: std::ffi::OsString
|
||||
/// [Path]: std::path::Path
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use deltachat::dc_tools::{dc_strdup, OsStrExt};
|
||||
/// let path = std::path::Path::new("/some/path");
|
||||
/// let path_c = path.to_c_string().unwrap();
|
||||
/// unsafe {
|
||||
/// let mut c_ptr: *mut libc::c_char = dc_strdup(path_c.as_ptr());
|
||||
/// }
|
||||
/// ```
|
||||
pub trait OsStrExt {
|
||||
/// Convert a [std::ffi::OsStr] to an [std::ffi::CString]
|
||||
///
|
||||
/// This is useful to convert e.g. a [std::path::Path] to
|
||||
/// [*libc::c_char] by using
|
||||
/// [Path::as_os_str()](std::path::Path::as_os_str) and
|
||||
/// [CStr::as_ptr()](std::ffi::CStr::as_ptr).
|
||||
///
|
||||
/// This returns [CString] and not [&CStr] because not all [OsStr]
|
||||
/// slices end with a null byte, particularly those coming from
|
||||
/// [Path] do not have a null byte and having to handle this as
|
||||
/// the caller would defeat the point of this function.
|
||||
///
|
||||
/// On Windows this requires that the [OsStr] contains valid
|
||||
/// unicode, which should normally be the case for a [Path].
|
||||
///
|
||||
/// [CString]: std::ffi::CString
|
||||
/// [CStr]: std::ffi::CStr
|
||||
/// [OsStr]: std::ffi::OsStr
|
||||
/// [Path]: std::path::Path
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Since a C `*char` is terminated by a NULL byte this conversion
|
||||
/// will fail, when the [OsStr] has an interior null byte. The
|
||||
/// function will return
|
||||
/// `[Err]([CStringError::InteriorNullByte])`. When converting
|
||||
/// from a [Path] it should be safe to
|
||||
/// [`.unwrap()`](std::result::Result::unwrap) this anyway since a
|
||||
/// [Path] should not contain interior null bytes.
|
||||
///
|
||||
/// On windows when the string contains invalid Unicode
|
||||
/// `[Err]([CStringError::NotUnicode])` is returned.
|
||||
fn to_c_string(&self) -> Result<CString, CStringError>;
|
||||
}
|
||||
|
||||
impl<T: AsRef<std::ffi::OsStr>> OsStrExt for T {
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
fn to_c_string(&self) -> Result<CString, CStringError> {
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
CString::new(self.as_ref().as_bytes()).map_err(|err| match err {
|
||||
std::ffi::NulError { .. } => CStringError::InteriorNullByte,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn to_c_string(&self) -> Result<CString, CStringError> {
|
||||
os_str_to_c_string_unicode(&self)
|
||||
}
|
||||
}
|
||||
|
||||
// Implementation for os_str_to_c_string on windows.
|
||||
#[allow(dead_code)]
|
||||
fn os_str_to_c_string_unicode(
|
||||
os_str: &dyn AsRef<std::ffi::OsStr>,
|
||||
) -> Result<CString, CStringError> {
|
||||
match os_str.as_ref().to_str() {
|
||||
Some(val) => CString::new(val.as_bytes()).map_err(|err| match err {
|
||||
std::ffi::NulError { .. } => CStringError::InteriorNullByte,
|
||||
}),
|
||||
None => Err(CStringError::NotUnicode),
|
||||
}
|
||||
}
|
||||
|
||||
/// Convenience methods/associated functions for working with [CString]
|
||||
///
|
||||
/// This is helps transitioning from unsafe code.
|
||||
pub trait CStringExt {
|
||||
/// Create a new [CString], yolo style
|
||||
///
|
||||
/// This unwrap the result, panicking when there are embedded NULL
|
||||
/// bytes.
|
||||
fn yolo<T: Into<Vec<u8>>>(t: T) -> CString {
|
||||
CString::new(t).expect("String contains null byte, can not be CString")
|
||||
}
|
||||
}
|
||||
|
||||
impl CStringExt for CString {}
|
||||
|
||||
/// Convenience methods to make transitioning from raw C strings easier.
|
||||
///
|
||||
/// To interact with (legacy) C APIs we often need to convert from
|
||||
/// Rust strings to raw C strings. This can be clumsy to do correctly
|
||||
/// and the compiler sometimes allows it in an unsafe way. These
|
||||
/// methods make it more succinct and help you get it right.
|
||||
pub trait StrExt {
|
||||
/// Allocate a new raw C `*char` version of this string.
|
||||
///
|
||||
/// This allocates a new raw C string which must be freed using
|
||||
/// `free`. It takes care of some common pitfalls with using
|
||||
/// [CString.as_ptr].
|
||||
///
|
||||
/// [CString.as_ptr]: std::ffi::CString.as_ptr
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function will panic when the original string contains an
|
||||
/// interior null byte as this can not be represented in raw C
|
||||
/// strings.
|
||||
unsafe fn strdup(&self) -> *mut libc::c_char;
|
||||
}
|
||||
|
||||
impl<T: AsRef<str>> StrExt for T {
|
||||
unsafe fn strdup(&self) -> *mut libc::c_char {
|
||||
let tmp = CString::yolo(self.as_ref());
|
||||
dc_strdup(tmp.as_ptr())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_string_lossy(s: *const libc::c_char) -> String {
|
||||
if s.is_null() {
|
||||
return "".into();
|
||||
}
|
||||
|
||||
let cstr = unsafe { CStr::from_ptr(s) };
|
||||
|
||||
cstr.to_string_lossy().to_string()
|
||||
}
|
||||
|
||||
pub fn to_opt_string_lossy(s: *const libc::c_char) -> Option<String> {
|
||||
if s.is_null() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(to_string_lossy(s))
|
||||
}
|
||||
|
||||
/// Convert a C `*char` pointer to a [std::path::Path] slice.
|
||||
///
|
||||
/// This converts a `*libc::c_char` pointer to a [Path] slice. This
|
||||
/// essentially has to convert the pointer to [std::ffi::OsStr] to do
|
||||
/// so and thus is the inverse of [OsStrExt::to_c_string]. Just like
|
||||
/// [OsStrExt::to_c_string] requires valid Unicode on Windows, this
|
||||
/// requires that the pointer contains valid UTF-8 on Windows.
|
||||
///
|
||||
/// Because this returns a reference the [Path] silce can not outlive
|
||||
/// the original pointer.
|
||||
///
|
||||
/// [Path]: std::path::Path
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
pub fn as_path<'a>(s: *const libc::c_char) -> &'a std::path::Path {
|
||||
assert!(!s.is_null(), "cannot be used on null pointers");
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
unsafe {
|
||||
let c_str = std::ffi::CStr::from_ptr(s).to_bytes();
|
||||
let os_str = std::ffi::OsStr::from_bytes(c_str);
|
||||
std::path::Path::new(os_str)
|
||||
}
|
||||
}
|
||||
|
||||
// as_path() implementation for windows, documented above.
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn as_path<'a>(s: *const libc::c_char) -> &'a std::path::Path {
|
||||
as_path_unicode(s)
|
||||
}
|
||||
|
||||
// Implementation for as_path() on Windows.
|
||||
//
|
||||
// Having this as a separate function means it can be tested on unix
|
||||
// too.
|
||||
#[allow(dead_code)]
|
||||
fn as_path_unicode<'a>(s: *const libc::c_char) -> &'a std::path::Path {
|
||||
assert!(!s.is_null(), "cannot be used on null pointers");
|
||||
|
||||
let cstr = unsafe { CStr::from_ptr(s) };
|
||||
let str = cstr.to_str().unwrap_or_else(|err| panic!("{}", err));
|
||||
|
||||
std::path::Path::new(str)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use libc::{free, strcmp};
|
||||
|
||||
#[test]
|
||||
fn test_os_str_to_c_string_cwd() {
|
||||
let some_dir = std::env::current_dir().unwrap();
|
||||
some_dir.as_os_str().to_c_string().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_os_str_to_c_string_unicode() {
|
||||
let some_str = String::from("/some/valid/utf8");
|
||||
let some_dir = std::path::Path::new(&some_str);
|
||||
assert_eq!(
|
||||
some_dir.as_os_str().to_c_string().unwrap(),
|
||||
CString::new("/some/valid/utf8").unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_os_str_to_c_string_nul() {
|
||||
let some_str = std::ffi::OsString::from("foo\x00bar");
|
||||
assert_eq!(
|
||||
some_str.to_c_string().err().unwrap(),
|
||||
CStringError::InteriorNullByte
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_path_to_c_string_cwd() {
|
||||
let some_dir = std::env::current_dir().unwrap();
|
||||
some_dir.to_c_string().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_path_to_c_string_unicode() {
|
||||
let some_str = String::from("/some/valid/utf8");
|
||||
let some_dir = std::path::Path::new(&some_str);
|
||||
assert_eq!(
|
||||
some_dir.as_os_str().to_c_string().unwrap(),
|
||||
CString::new("/some/valid/utf8").unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_os_str_to_c_string_unicode_fn() {
|
||||
let some_str = std::ffi::OsString::from("foo");
|
||||
assert_eq!(
|
||||
os_str_to_c_string_unicode(&some_str).unwrap(),
|
||||
CString::new("foo").unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_path_to_c_string_unicode_fn() {
|
||||
let some_str = String::from("/some/path");
|
||||
let some_path = std::path::Path::new(&some_str);
|
||||
assert_eq!(
|
||||
os_str_to_c_string_unicode(&some_path).unwrap(),
|
||||
CString::new("/some/path").unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_os_str_to_c_string_unicode_fn_nul() {
|
||||
let some_str = std::ffi::OsString::from("fooz\x00bar");
|
||||
assert_eq!(
|
||||
os_str_to_c_string_unicode(&some_str).err().unwrap(),
|
||||
CStringError::InteriorNullByte
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_as_path() {
|
||||
let some_path = CString::new("/some/path").unwrap();
|
||||
let ptr = some_path.as_ptr();
|
||||
assert_eq!(as_path(ptr), std::ffi::OsString::from("/some/path"))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_as_path_unicode_fn() {
|
||||
let some_path = CString::new("/some/path").unwrap();
|
||||
let ptr = some_path.as_ptr();
|
||||
assert_eq!(as_path_unicode(ptr), std::ffi::OsString::from("/some/path"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cstring_yolo() {
|
||||
assert_eq!(CString::new("hello").unwrap(), CString::yolo("hello"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_strdup_str() {
|
||||
unsafe {
|
||||
let s = "hello".strdup();
|
||||
let cmp = strcmp(s, b"hello\x00" as *const u8 as *const libc::c_char);
|
||||
free(s as *mut libc::c_void);
|
||||
assert_eq!(cmp, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_strdup_string() {
|
||||
unsafe {
|
||||
let s = String::from("hello").strdup();
|
||||
let cmp = strcmp(s, b"hello\x00" as *const u8 as *const libc::c_char);
|
||||
free(s as *mut libc::c_void);
|
||||
assert_eq!(cmp, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,12 +19,11 @@ use deltachat::peerstate::*;
|
||||
use deltachat::qr::*;
|
||||
use deltachat::sql;
|
||||
use deltachat::Event;
|
||||
use libc::free;
|
||||
|
||||
/// Reset database tables. This function is called from Core cmdline.
|
||||
/// Argument is a bitmask, executing single or multiple actions in one call.
|
||||
/// e.g. bitmask 7 triggers actions definded with bits 1, 2 and 4.
|
||||
pub unsafe fn dc_reset_tables(context: &Context, bits: i32) -> i32 {
|
||||
pub fn dc_reset_tables(context: &Context, bits: i32) -> i32 {
|
||||
info!(context, "Resetting tables ({})...", bits);
|
||||
if 0 != bits & 1 {
|
||||
sql::execute(context, &context.sql, "DELETE FROM jobs;", params![]).unwrap();
|
||||
@@ -95,7 +94,7 @@ pub unsafe fn dc_reset_tables(context: &Context, bits: i32) -> i32 {
|
||||
fn dc_poke_eml_file(context: &Context, filename: impl AsRef<Path>) -> Result<(), Error> {
|
||||
let data = dc_read_file(context, filename)?;
|
||||
|
||||
unsafe { dc_receive_imf(context, &data, "import", 0, 0) };
|
||||
dc_receive_imf(context, &data, "import", 0, 0);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -107,18 +106,19 @@ fn dc_poke_eml_file(context: &Context, filename: impl AsRef<Path>) -> Result<(),
|
||||
/// @param context The context as created by dc_context_new().
|
||||
/// @param spec The file or directory to import. NULL for the last command.
|
||||
/// @return 1=success, 0=error.
|
||||
fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int {
|
||||
fn poke_spec(context: &Context, spec: Option<&str>) -> libc::c_int {
|
||||
if !context.sql.is_open() {
|
||||
error!(context, "Import: Database not opened.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
let real_spec: String;
|
||||
let mut read_cnt = 0;
|
||||
|
||||
let real_spec: String;
|
||||
|
||||
/* if `spec` is given, remember it for later usage; if it is not given, try to use the last one */
|
||||
if !spec.is_null() {
|
||||
real_spec = to_string_lossy(spec);
|
||||
if let Some(spec) = spec {
|
||||
real_spec = spec.to_string();
|
||||
context
|
||||
.sql
|
||||
.set_raw_config(context, "import_spec", Some(&real_spec))
|
||||
@@ -174,7 +174,7 @@ fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int {
|
||||
1
|
||||
}
|
||||
|
||||
unsafe fn log_msg(context: &Context, prefix: impl AsRef<str>, msg: &Message) {
|
||||
fn log_msg(context: &Context, prefix: impl AsRef<str>, msg: &Message) {
|
||||
let contact = Contact::get_by_id(context, msg.get_from_id()).expect("invalid contact");
|
||||
let contact_name = contact.get_name();
|
||||
let contact_id = contact.get_id();
|
||||
@@ -219,7 +219,7 @@ unsafe fn log_msg(context: &Context, prefix: impl AsRef<str>, msg: &Message) {
|
||||
);
|
||||
}
|
||||
|
||||
unsafe fn log_msglist(context: &Context, msglist: &Vec<MsgId>) -> Result<(), Error> {
|
||||
fn log_msglist(context: &Context, msglist: &Vec<MsgId>) -> Result<(), Error> {
|
||||
let mut lines_out = 0;
|
||||
for &msg_id in msglist {
|
||||
if msg_id.is_daymarker() {
|
||||
@@ -250,7 +250,7 @@ unsafe fn log_msglist(context: &Context, msglist: &Vec<MsgId>) -> Result<(), Err
|
||||
Ok(())
|
||||
}
|
||||
|
||||
unsafe fn log_contactlist(context: &Context, contacts: &Vec<u32>) {
|
||||
fn log_contactlist(context: &Context, contacts: &Vec<u32>) {
|
||||
let mut contacts = contacts.clone();
|
||||
if !contacts.contains(&1) {
|
||||
contacts.push(1);
|
||||
@@ -302,7 +302,7 @@ fn chat_prefix(chat: &Chat) -> &'static str {
|
||||
chat.typ.into()
|
||||
}
|
||||
|
||||
pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::Error> {
|
||||
pub fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::Error> {
|
||||
let chat_id = *context.cmdline_sel_chat_id.read().unwrap();
|
||||
let mut sel_chat = if chat_id > 0 {
|
||||
Chat::load_from_db(context, chat_id).ok()
|
||||
@@ -313,11 +313,6 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
let mut args = line.splitn(3, ' ');
|
||||
let arg0 = args.next().unwrap_or_default();
|
||||
let arg1 = args.next().unwrap_or_default();
|
||||
let arg1_c = if arg1.is_empty() {
|
||||
std::ptr::null()
|
||||
} else {
|
||||
arg1.strdup() as *const _
|
||||
};
|
||||
let arg2 = args.next().unwrap_or_default();
|
||||
|
||||
let blobdir = context.get_blobdir();
|
||||
@@ -467,7 +462,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
);
|
||||
}
|
||||
"poke" => {
|
||||
ensure!(0 != poke_spec(context, arg1_c), "Poke failed");
|
||||
ensure!(0 != poke_spec(context, Some(arg1)), "Poke failed");
|
||||
}
|
||||
"reset" => {
|
||||
ensure!(!arg1.is_empty(), "Argument <bits> missing: 1=jobs, 2=peerstates, 4=private keys, 8=rest but server config");
|
||||
@@ -1005,7 +1000,5 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
_ => bail!("Unknown command: \"{}\" type ? for help.", arg0),
|
||||
}
|
||||
|
||||
free(arg1_c as *mut _);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -403,7 +403,7 @@ fn main_0(args: Vec<String>) -> Result<(), failure::Error> {
|
||||
// TODO: ignore "set mail_pw"
|
||||
rl.add_history_entry(line.as_str());
|
||||
let ctx = ctx.clone();
|
||||
match unsafe { handle_cmd(line.trim(), ctx) } {
|
||||
match handle_cmd(line.trim(), ctx) {
|
||||
Ok(ExitResult::Continue) => {}
|
||||
Ok(ExitResult::Exit) => break,
|
||||
Err(err) => println!("Error: {}", err),
|
||||
@@ -434,7 +434,7 @@ enum ExitResult {
|
||||
Exit,
|
||||
}
|
||||
|
||||
unsafe fn handle_cmd(line: &str, ctx: Arc<RwLock<Context>>) -> Result<ExitResult, failure::Error> {
|
||||
fn handle_cmd(line: &str, ctx: Arc<RwLock<Context>>) -> Result<ExitResult, failure::Error> {
|
||||
let mut args = line.splitn(2, ' ');
|
||||
let arg0 = args.next().unwrap_or_default();
|
||||
let arg1 = args.next().unwrap_or_default();
|
||||
|
||||
@@ -101,16 +101,6 @@ fn main() {
|
||||
|
||||
thread::sleep(duration);
|
||||
|
||||
// let msglist = dc_get_chat_msgs(&ctx, chat_id, 0, 0);
|
||||
// for i in 0..dc_array_get_cnt(msglist) {
|
||||
// let msg_id = dc_array_get_id(msglist, i);
|
||||
// let msg = dc_get_msg(context, msg_id);
|
||||
// let text = CStr::from_ptr(dc_msg_get_text(msg)).unwrap();
|
||||
// println!("Message {}: {}\n", i + 1, text.to_str().unwrap());
|
||||
// dc_msg_unref(msg);
|
||||
// }
|
||||
// dc_array_unref(msglist);
|
||||
|
||||
println!("stopping threads");
|
||||
|
||||
*running.write().unwrap() = false;
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
# copied from http://koushiro.me/2019/04/30/Building-and-Testing-Rust-projects-on-CircleCI/
|
||||
|
||||
version: 2.1
|
||||
jobs:
|
||||
build:
|
||||
docker:
|
||||
- image: ubuntu:18.04
|
||||
|
||||
working_directory: ~/deltachat-core-rust
|
||||
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
- run:
|
||||
name: Setup build environment
|
||||
command: |
|
||||
apt update
|
||||
apt install -y curl build-essential autoconf libtool git python pkg-config
|
||||
# this will pick default toolchain from `rust-toolchain` file
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --no-modify-path --default-toolchain none -y;
|
||||
source $HOME/.cargo/env
|
||||
no_output_timeout: 1800s
|
||||
|
||||
- run:
|
||||
name: Format
|
||||
command: |
|
||||
export PATH=~/.cargo/bin:$PATH
|
||||
rustup component add rustfmt
|
||||
cargo fmt -- --check
|
||||
|
||||
- run:
|
||||
name: Test
|
||||
command: |
|
||||
export PATH=~/.cargo/bin:$PATH
|
||||
export RUST_BACKTRACE=1
|
||||
cargo test
|
||||
|
||||
workflows:
|
||||
version: 2.1
|
||||
build:
|
||||
jobs:
|
||||
- build
|
||||
@@ -1,23 +0,0 @@
|
||||
[package]
|
||||
name = "mmime"
|
||||
version = "0.1.2"
|
||||
authors = ["dignifiedquire <dignifiedquire@users.noreply.github.com>"]
|
||||
edition = "2018"
|
||||
license = "MIT OR Apache-2.0"
|
||||
homepage = "https://github.com/deltachat/deltachat-core-rust"
|
||||
repository = "https://github.com/deltachat/deltachat-core-rust"
|
||||
readme = "README.md"
|
||||
description = "Mime parsing for email"
|
||||
|
||||
|
||||
keywords = ["mail", "mim", "email", "imap", "smtp"]
|
||||
categories = ["std", "email"]
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2.54"
|
||||
charset = "0.1.2"
|
||||
memmap = "0.7.0"
|
||||
lazy_static = "1.3.0"
|
||||
rand = "0.6.5"
|
||||
chrono = "0.4.6"
|
||||
hex = "0.4.0"
|
||||
@@ -1,201 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -1,23 +0,0 @@
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
@@ -1,4 +0,0 @@
|
||||
This library is primarly distributed under the terms of both the MIT license and
|
||||
the Apache License (Version 2.0).
|
||||
|
||||
See LICENSE-MIT and LICENSE-APACHE for details.
|
||||
@@ -1,16 +0,0 @@
|
||||
# mmime
|
||||
|
||||
[![CircleCI build status][circle-shield]][circle] [![Appveyor build status][appveyor-shield]][appveyor] [![License][license-shield]][license]
|
||||
|
||||
> mmmmmmime parsing
|
||||
|
||||
Base code was compiled using c2rust from libetpan.
|
||||
|
||||
|
||||
|
||||
[circle-shield]: https://img.shields.io/circleci/project/github/dignifiedquire/mmime/master.svg?style=flat-square
|
||||
[circle]: https://circleci.com/gh/dignifiedquire/mmime/
|
||||
[appveyor-shield]: https://ci.appveyor.com/api/projects/status/l26co5rba32knrlu/branch/master?style=flat-square
|
||||
[appveyor]: https://ci.appveyor.com/project/dignifiedquire/mmime/branch/master
|
||||
[license-shield]: https://img.shields.io/badge/License-MIT%2FApache2.0-green.svg?style=flat-square
|
||||
[license]: https://github.com/rpgp/rpgp/blob/master/LICENSE.md
|
||||
@@ -1,32 +0,0 @@
|
||||
use crate::other::*;
|
||||
use libc;
|
||||
use std::ffi::{CStr, CString};
|
||||
|
||||
pub const MAIL_CHARCONV_ERROR_CONV: libc::c_uint = 3;
|
||||
pub const MAIL_CHARCONV_ERROR_MEMORY: libc::c_uint = 2;
|
||||
pub const MAIL_CHARCONV_ERROR_UNKNOWN_CHARSET: libc::c_uint = 1;
|
||||
pub const MAIL_CHARCONV_NO_ERROR: libc::c_uint = 0;
|
||||
|
||||
pub unsafe fn charconv(
|
||||
tocode: *const libc::c_char,
|
||||
fromcode: *const libc::c_char,
|
||||
s: *const libc::c_char,
|
||||
length: size_t,
|
||||
result: *mut *mut libc::c_char,
|
||||
) -> libc::c_int {
|
||||
assert!(!fromcode.is_null(), "invalid fromcode");
|
||||
assert!(!s.is_null(), "invalid input string");
|
||||
if let Some(encoding) =
|
||||
charset::Charset::for_label(CStr::from_ptr(fromcode).to_string_lossy().as_bytes())
|
||||
{
|
||||
let data = std::slice::from_raw_parts(s as *const u8, strlen(s));
|
||||
|
||||
let (res, _, _) = encoding.decode(data);
|
||||
let res_c = CString::new(res.as_bytes()).unwrap_or_default();
|
||||
*result = strdup(res_c.as_ptr()) as *mut _;
|
||||
|
||||
MAIL_CHARCONV_NO_ERROR as libc::c_int
|
||||
} else {
|
||||
MAIL_CHARCONV_ERROR_UNKNOWN_CHARSET as libc::c_int
|
||||
}
|
||||
}
|
||||
@@ -1,427 +0,0 @@
|
||||
use libc;
|
||||
|
||||
use crate::other::*;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct chashdatum {
|
||||
pub data: *mut libc::c_void,
|
||||
pub len: libc::c_uint,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct chash {
|
||||
pub size: libc::c_uint,
|
||||
pub count: libc::c_uint,
|
||||
pub copyvalue: libc::c_int,
|
||||
pub copykey: libc::c_int,
|
||||
pub cells: *mut *mut chashcell,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct chashcell {
|
||||
pub func: libc::c_uint,
|
||||
pub key: chashdatum,
|
||||
pub value: chashdatum,
|
||||
pub next: *mut chashcell,
|
||||
}
|
||||
|
||||
pub type chashiter = chashcell;
|
||||
/* Allocates a new (empty) hash using this initial size and the given flags,
|
||||
specifying which data should be copied in the hash.
|
||||
CHASH_COPYNONE : Keys/Values are not copied.
|
||||
CHASH_COPYKEY : Keys are dupped and freed as needed in the hash.
|
||||
CHASH_COPYVALUE : Values are dupped and freed as needed in the hash.
|
||||
CHASH_COPYALL : Both keys and values are dupped in the hash.
|
||||
*/
|
||||
pub unsafe fn chash_new(mut size: libc::c_uint, mut flags: libc::c_int) -> *mut chash {
|
||||
let mut h: *mut chash = 0 as *mut chash;
|
||||
h = malloc(::std::mem::size_of::<chash>() as libc::size_t) as *mut chash;
|
||||
if h.is_null() {
|
||||
return 0 as *mut chash;
|
||||
}
|
||||
if size < 13i32 as libc::c_uint {
|
||||
size = 13i32 as libc::c_uint
|
||||
}
|
||||
(*h).count = 0i32 as libc::c_uint;
|
||||
(*h).cells = calloc(
|
||||
size as libc::size_t,
|
||||
::std::mem::size_of::<*mut chashcell>() as libc::size_t,
|
||||
) as *mut *mut chashcell;
|
||||
if (*h).cells.is_null() {
|
||||
free(h as *mut libc::c_void);
|
||||
return 0 as *mut chash;
|
||||
}
|
||||
(*h).size = size;
|
||||
(*h).copykey = flags & 1i32;
|
||||
(*h).copyvalue = flags & 2i32;
|
||||
return h;
|
||||
}
|
||||
|
||||
/* Frees a hash */
|
||||
pub unsafe fn chash_free(mut hash: *mut chash) {
|
||||
let mut indx: libc::c_uint = 0;
|
||||
let mut iter: *mut chashiter = 0 as *mut chashiter;
|
||||
let mut next: *mut chashiter = 0 as *mut chashiter;
|
||||
indx = 0i32 as libc::c_uint;
|
||||
while indx < (*hash).size {
|
||||
iter = *(*hash).cells.offset(indx as isize);
|
||||
while !iter.is_null() {
|
||||
next = (*iter).next;
|
||||
if 0 != (*hash).copykey {
|
||||
free((*iter).key.data);
|
||||
}
|
||||
if 0 != (*hash).copyvalue {
|
||||
free((*iter).value.data);
|
||||
}
|
||||
free(iter as *mut libc::c_void);
|
||||
iter = next
|
||||
}
|
||||
indx = indx.wrapping_add(1)
|
||||
}
|
||||
free((*hash).cells as *mut libc::c_void);
|
||||
free(hash as *mut libc::c_void);
|
||||
}
|
||||
|
||||
/* Removes all elements from a hash */
|
||||
pub unsafe fn chash_clear(mut hash: *mut chash) {
|
||||
let mut indx: libc::c_uint = 0;
|
||||
let mut iter: *mut chashiter = 0 as *mut chashiter;
|
||||
let mut next: *mut chashiter = 0 as *mut chashiter;
|
||||
indx = 0i32 as libc::c_uint;
|
||||
while indx < (*hash).size {
|
||||
iter = *(*hash).cells.offset(indx as isize);
|
||||
while !iter.is_null() {
|
||||
next = (*iter).next;
|
||||
if 0 != (*hash).copykey {
|
||||
free((*iter).key.data);
|
||||
}
|
||||
if 0 != (*hash).copyvalue {
|
||||
free((*iter).value.data);
|
||||
}
|
||||
free(iter as *mut libc::c_void);
|
||||
iter = next
|
||||
}
|
||||
indx = indx.wrapping_add(1)
|
||||
}
|
||||
memset(
|
||||
(*hash).cells as *mut libc::c_void,
|
||||
0i32,
|
||||
((*hash).size as libc::size_t)
|
||||
.wrapping_mul(::std::mem::size_of::<*mut chashcell>() as libc::size_t),
|
||||
);
|
||||
(*hash).count = 0i32 as libc::c_uint;
|
||||
}
|
||||
/* Adds an entry in the hash table.
|
||||
Length can be 0 if key/value are strings.
|
||||
If an entry already exists for this key, it is replaced, and its value
|
||||
is returned. Otherwise, the data pointer will be NULL and the length
|
||||
field be set to TRUE or FALSe to indicate success or failure. */
|
||||
pub unsafe fn chash_set(
|
||||
mut hash: *mut chash,
|
||||
mut key: *mut chashdatum,
|
||||
mut value: *mut chashdatum,
|
||||
mut oldvalue: *mut chashdatum,
|
||||
) -> libc::c_int {
|
||||
let mut current_block: u64;
|
||||
let mut func: libc::c_uint = 0;
|
||||
let mut indx: libc::c_uint = 0;
|
||||
let mut iter: *mut chashiter = 0 as *mut chashiter;
|
||||
let mut cell: *mut chashiter = 0 as *mut chashiter;
|
||||
let mut r: libc::c_int = 0;
|
||||
if (*hash).count > (*hash).size.wrapping_mul(3i32 as libc::c_uint) {
|
||||
r = chash_resize(
|
||||
hash,
|
||||
(*hash)
|
||||
.count
|
||||
.wrapping_div(3i32 as libc::c_uint)
|
||||
.wrapping_mul(2i32 as libc::c_uint)
|
||||
.wrapping_add(1i32 as libc::c_uint),
|
||||
);
|
||||
if r < 0i32 {
|
||||
current_block = 17701753836843438419;
|
||||
} else {
|
||||
current_block = 7095457783677275021;
|
||||
}
|
||||
} else {
|
||||
current_block = 7095457783677275021;
|
||||
}
|
||||
match current_block {
|
||||
7095457783677275021 => {
|
||||
func = chash_func((*key).data as *const libc::c_char, (*key).len);
|
||||
indx = func.wrapping_rem((*hash).size);
|
||||
iter = *(*hash).cells.offset(indx as isize);
|
||||
loop {
|
||||
if iter.is_null() {
|
||||
current_block = 17788412896529399552;
|
||||
break;
|
||||
}
|
||||
if (*iter).key.len == (*key).len
|
||||
&& (*iter).func == func
|
||||
&& 0 == memcmp((*iter).key.data, (*key).data, (*key).len as libc::size_t)
|
||||
{
|
||||
/* found, replacing entry */
|
||||
if 0 != (*hash).copyvalue {
|
||||
let mut data: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
data = chash_dup((*value).data, (*value).len);
|
||||
if data.is_null() {
|
||||
current_block = 17701753836843438419;
|
||||
break;
|
||||
}
|
||||
free((*iter).value.data);
|
||||
(*iter).value.data = data as *mut libc::c_void;
|
||||
(*iter).value.len = (*value).len
|
||||
} else {
|
||||
if !oldvalue.is_null() {
|
||||
(*oldvalue).data = (*iter).value.data;
|
||||
(*oldvalue).len = (*iter).value.len
|
||||
}
|
||||
(*iter).value.data = (*value).data;
|
||||
(*iter).value.len = (*value).len
|
||||
}
|
||||
if 0 == (*hash).copykey {
|
||||
(*iter).key.data = (*key).data
|
||||
}
|
||||
if !oldvalue.is_null() {
|
||||
(*oldvalue).data = (*value).data;
|
||||
(*oldvalue).len = (*value).len
|
||||
}
|
||||
return 0i32;
|
||||
} else {
|
||||
iter = (*iter).next
|
||||
}
|
||||
}
|
||||
match current_block {
|
||||
17701753836843438419 => {}
|
||||
_ => {
|
||||
if !oldvalue.is_null() {
|
||||
(*oldvalue).data = 0 as *mut libc::c_void;
|
||||
(*oldvalue).len = 0i32 as libc::c_uint
|
||||
}
|
||||
cell = malloc(::std::mem::size_of::<chashcell>() as libc::size_t)
|
||||
as *mut chashcell;
|
||||
if !cell.is_null() {
|
||||
if 0 != (*hash).copykey {
|
||||
(*cell).key.data =
|
||||
chash_dup((*key).data, (*key).len) as *mut libc::c_void;
|
||||
if (*cell).key.data.is_null() {
|
||||
current_block = 4267898785354516004;
|
||||
} else {
|
||||
current_block = 7226443171521532240;
|
||||
}
|
||||
} else {
|
||||
(*cell).key.data = (*key).data;
|
||||
current_block = 7226443171521532240;
|
||||
}
|
||||
match current_block {
|
||||
7226443171521532240 => {
|
||||
(*cell).key.len = (*key).len;
|
||||
if 0 != (*hash).copyvalue {
|
||||
(*cell).value.data =
|
||||
chash_dup((*value).data, (*value).len) as *mut libc::c_void;
|
||||
if (*cell).value.data.is_null() {
|
||||
if 0 != (*hash).copykey {
|
||||
free((*cell).key.data);
|
||||
}
|
||||
current_block = 4267898785354516004;
|
||||
} else {
|
||||
current_block = 6717214610478484138;
|
||||
}
|
||||
} else {
|
||||
(*cell).value.data = (*value).data;
|
||||
current_block = 6717214610478484138;
|
||||
}
|
||||
match current_block {
|
||||
4267898785354516004 => {}
|
||||
_ => {
|
||||
(*cell).value.len = (*value).len;
|
||||
(*cell).func = func;
|
||||
(*cell).next = *(*hash).cells.offset(indx as isize);
|
||||
let ref mut fresh0 = *(*hash).cells.offset(indx as isize);
|
||||
*fresh0 = cell;
|
||||
(*hash).count = (*hash).count.wrapping_add(1);
|
||||
return 0i32;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
free(cell as *mut libc::c_void);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
return -1i32;
|
||||
}
|
||||
#[inline]
|
||||
unsafe fn chash_dup(mut data: *const libc::c_void, mut len: libc::c_uint) -> *mut libc::c_char {
|
||||
let mut r: *mut libc::c_void = 0 as *mut libc::c_void;
|
||||
r = malloc(len as libc::size_t) as *mut libc::c_char as *mut libc::c_void;
|
||||
if r.is_null() {
|
||||
return 0 as *mut libc::c_char;
|
||||
}
|
||||
memcpy(r, data, len as libc::size_t);
|
||||
return r as *mut libc::c_char;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn chash_func(mut key: *const libc::c_char, mut len: libc::c_uint) -> libc::c_uint {
|
||||
let mut c: libc::c_uint = 5381i32 as libc::c_uint;
|
||||
let mut k: *const libc::c_char = key;
|
||||
loop {
|
||||
let fresh1 = len;
|
||||
len = len.wrapping_sub(1);
|
||||
if !(0 != fresh1) {
|
||||
break;
|
||||
}
|
||||
let fresh2 = k;
|
||||
k = k.offset(1);
|
||||
c = (c << 5i32)
|
||||
.wrapping_add(c)
|
||||
.wrapping_add(*fresh2 as libc::c_uint)
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/* Resizes the hash table to the passed size. */
|
||||
pub unsafe fn chash_resize(mut hash: *mut chash, mut size: libc::c_uint) -> libc::c_int {
|
||||
let mut cells: *mut *mut chashcell = 0 as *mut *mut chashcell;
|
||||
let mut indx: libc::c_uint = 0;
|
||||
let mut nindx: libc::c_uint = 0;
|
||||
let mut iter: *mut chashiter = 0 as *mut chashiter;
|
||||
let mut next: *mut chashiter = 0 as *mut chashiter;
|
||||
if (*hash).size == size {
|
||||
return 0i32;
|
||||
}
|
||||
cells = calloc(
|
||||
size as libc::size_t,
|
||||
::std::mem::size_of::<*mut chashcell>() as libc::size_t,
|
||||
) as *mut *mut chashcell;
|
||||
if cells.is_null() {
|
||||
return -1i32;
|
||||
}
|
||||
indx = 0i32 as libc::c_uint;
|
||||
while indx < (*hash).size {
|
||||
iter = *(*hash).cells.offset(indx as isize);
|
||||
while !iter.is_null() {
|
||||
next = (*iter).next;
|
||||
nindx = (*iter).func.wrapping_rem(size);
|
||||
(*iter).next = *cells.offset(nindx as isize);
|
||||
let ref mut fresh3 = *cells.offset(nindx as isize);
|
||||
*fresh3 = iter;
|
||||
iter = next
|
||||
}
|
||||
indx = indx.wrapping_add(1)
|
||||
}
|
||||
free((*hash).cells as *mut libc::c_void);
|
||||
(*hash).size = size;
|
||||
(*hash).cells = cells;
|
||||
return 0i32;
|
||||
}
|
||||
|
||||
/* Retrieves the data associated to the key if it is found in the hash table.
|
||||
The data pointer and the length will be NULL if not found*/
|
||||
pub unsafe fn chash_get(
|
||||
mut hash: *mut chash,
|
||||
mut key: *mut chashdatum,
|
||||
mut result: *mut chashdatum,
|
||||
) -> libc::c_int {
|
||||
let mut func: libc::c_uint = 0;
|
||||
let mut iter: *mut chashiter = 0 as *mut chashiter;
|
||||
func = chash_func((*key).data as *const libc::c_char, (*key).len);
|
||||
iter = *(*hash)
|
||||
.cells
|
||||
.offset(func.wrapping_rem((*hash).size) as isize);
|
||||
while !iter.is_null() {
|
||||
if (*iter).key.len == (*key).len
|
||||
&& (*iter).func == func
|
||||
&& 0 == memcmp((*iter).key.data, (*key).data, (*key).len as libc::size_t)
|
||||
{
|
||||
*result = (*iter).value;
|
||||
return 0i32;
|
||||
}
|
||||
iter = (*iter).next
|
||||
}
|
||||
return -1i32;
|
||||
}
|
||||
/* Removes the entry associated to this key if it is found in the hash table,
|
||||
and returns its contents if not dupped (otherwise, pointer will be NULL
|
||||
and len TRUE). If entry is not found both pointer and len will be NULL. */
|
||||
pub unsafe fn chash_delete(
|
||||
mut hash: *mut chash,
|
||||
mut key: *mut chashdatum,
|
||||
mut oldvalue: *mut chashdatum,
|
||||
) -> libc::c_int {
|
||||
/* chashdatum result = { NULL, TRUE }; */
|
||||
let mut func: libc::c_uint = 0;
|
||||
let mut indx: libc::c_uint = 0;
|
||||
let mut iter: *mut chashiter = 0 as *mut chashiter;
|
||||
let mut old: *mut chashiter = 0 as *mut chashiter;
|
||||
func = chash_func((*key).data as *const libc::c_char, (*key).len);
|
||||
indx = func.wrapping_rem((*hash).size);
|
||||
old = 0 as *mut chashiter;
|
||||
iter = *(*hash).cells.offset(indx as isize);
|
||||
while !iter.is_null() {
|
||||
if (*iter).key.len == (*key).len
|
||||
&& (*iter).func == func
|
||||
&& 0 == memcmp((*iter).key.data, (*key).data, (*key).len as libc::size_t)
|
||||
{
|
||||
if !old.is_null() {
|
||||
(*old).next = (*iter).next
|
||||
} else {
|
||||
let ref mut fresh4 = *(*hash).cells.offset(indx as isize);
|
||||
*fresh4 = (*iter).next
|
||||
}
|
||||
if 0 != (*hash).copykey {
|
||||
free((*iter).key.data);
|
||||
}
|
||||
if 0 != (*hash).copyvalue {
|
||||
free((*iter).value.data);
|
||||
} else if !oldvalue.is_null() {
|
||||
(*oldvalue).data = (*iter).value.data;
|
||||
(*oldvalue).len = (*iter).value.len
|
||||
}
|
||||
free(iter as *mut libc::c_void);
|
||||
(*hash).count = (*hash).count.wrapping_sub(1);
|
||||
return 0i32;
|
||||
}
|
||||
old = iter;
|
||||
iter = (*iter).next
|
||||
}
|
||||
return -1i32;
|
||||
}
|
||||
/* Returns an iterator to the first non-empty entry of the hash table */
|
||||
pub unsafe fn chash_begin(mut hash: *mut chash) -> *mut chashiter {
|
||||
let mut iter: *mut chashiter = 0 as *mut chashiter;
|
||||
let mut indx: libc::c_uint = 0i32 as libc::c_uint;
|
||||
iter = *(*hash).cells.offset(0isize);
|
||||
while iter.is_null() {
|
||||
indx = indx.wrapping_add(1);
|
||||
if indx >= (*hash).size {
|
||||
return 0 as *mut chashiter;
|
||||
}
|
||||
iter = *(*hash).cells.offset(indx as isize)
|
||||
}
|
||||
return iter;
|
||||
}
|
||||
/* Returns the next non-empty entry of the hash table */
|
||||
pub unsafe fn chash_next(mut hash: *mut chash, mut iter: *mut chashiter) -> *mut chashiter {
|
||||
let mut indx: libc::c_uint = 0;
|
||||
if iter.is_null() {
|
||||
return 0 as *mut chashiter;
|
||||
}
|
||||
indx = (*iter).func.wrapping_rem((*hash).size);
|
||||
iter = (*iter).next;
|
||||
while iter.is_null() {
|
||||
indx = indx.wrapping_add(1);
|
||||
if indx >= (*hash).size {
|
||||
return 0 as *mut chashiter;
|
||||
}
|
||||
iter = *(*hash).cells.offset(indx as isize)
|
||||
}
|
||||
return iter;
|
||||
}
|
||||
@@ -1,202 +0,0 @@
|
||||
use libc;
|
||||
|
||||
use crate::other::*;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct clistcell {
|
||||
pub data: *mut libc::c_void,
|
||||
pub previous: *mut clistcell,
|
||||
pub next: *mut clistcell,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[repr(C)]
|
||||
pub struct clist {
|
||||
pub first: *mut clistcell,
|
||||
pub last: *mut clistcell,
|
||||
pub count: libc::c_int,
|
||||
}
|
||||
|
||||
impl Default for clist {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
first: std::ptr::null_mut(),
|
||||
last: std::ptr::null_mut(),
|
||||
count: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for clist {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let mut l1 = self.first;
|
||||
while !l1.is_null() {
|
||||
let l2 = (*l1).next;
|
||||
free(l1 as *mut libc::c_void);
|
||||
l1 = l2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type clistiter = clistcell;
|
||||
pub struct CListIterator {
|
||||
cur: *mut clistiter,
|
||||
}
|
||||
impl Iterator for CListIterator {
|
||||
type Item = *mut libc::c_void;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
unsafe {
|
||||
if self.cur.is_null() {
|
||||
None
|
||||
} else {
|
||||
let data = (*self.cur).data;
|
||||
self.cur = (*self.cur).next;
|
||||
Some(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for &clist {
|
||||
type Item = *mut libc::c_void;
|
||||
type IntoIter = CListIterator;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
return CListIterator { cur: self.first };
|
||||
}
|
||||
}
|
||||
|
||||
pub type clist_func =
|
||||
Option<unsafe extern "C" fn(_: *mut libc::c_void, _: *mut libc::c_void) -> ()>;
|
||||
|
||||
/* Allocate a new pointer list */
|
||||
pub fn clist_new() -> *mut clist {
|
||||
Box::into_raw(Box::new(Default::default()))
|
||||
}
|
||||
/* Destroys a list. Data pointed by data pointers is NOT freed. */
|
||||
pub unsafe fn clist_free(mut lst: *mut clist) {
|
||||
Box::from_raw(lst);
|
||||
}
|
||||
/* Inserts this data pointer after the element pointed by the iterator */
|
||||
pub unsafe fn clist_insert_after(
|
||||
mut lst: *mut clist,
|
||||
mut iter: *mut clistiter,
|
||||
mut data: *mut libc::c_void,
|
||||
) -> libc::c_int {
|
||||
let mut c: *mut clistcell = 0 as *mut clistcell;
|
||||
c = malloc(::std::mem::size_of::<clistcell>() as libc::size_t) as *mut clistcell;
|
||||
if c.is_null() {
|
||||
return -1i32;
|
||||
}
|
||||
(*c).data = data;
|
||||
(*lst).count += 1;
|
||||
if (*lst).first == (*lst).last && (*lst).last.is_null() {
|
||||
(*c).next = 0 as *mut clistcell;
|
||||
(*c).previous = (*c).next;
|
||||
(*lst).last = c;
|
||||
(*lst).first = (*lst).last;
|
||||
return 0i32;
|
||||
}
|
||||
if iter.is_null() {
|
||||
(*c).previous = (*lst).last;
|
||||
(*(*c).previous).next = c;
|
||||
(*c).next = 0 as *mut clistcell;
|
||||
(*lst).last = c;
|
||||
return 0i32;
|
||||
}
|
||||
(*c).previous = iter;
|
||||
(*c).next = (*iter).next;
|
||||
if !(*c).next.is_null() {
|
||||
(*(*c).next).previous = c
|
||||
} else {
|
||||
(*lst).last = c
|
||||
}
|
||||
(*(*c).previous).next = c;
|
||||
return 0i32;
|
||||
}
|
||||
/* Deletes the element pointed by the iterator.
|
||||
Returns an iterator to the next element. */
|
||||
pub unsafe fn clist_delete(mut lst: *mut clist, mut iter: *mut clistiter) -> *mut clistiter {
|
||||
let mut ret: *mut clistiter = 0 as *mut clistiter;
|
||||
if iter.is_null() {
|
||||
return 0 as *mut clistiter;
|
||||
}
|
||||
if !(*iter).previous.is_null() {
|
||||
(*(*iter).previous).next = (*iter).next
|
||||
} else {
|
||||
(*lst).first = (*iter).next
|
||||
}
|
||||
if !(*iter).next.is_null() {
|
||||
(*(*iter).next).previous = (*iter).previous;
|
||||
ret = (*iter).next
|
||||
} else {
|
||||
(*lst).last = (*iter).previous;
|
||||
ret = 0 as *mut clistiter
|
||||
}
|
||||
free(iter as *mut libc::c_void);
|
||||
(*lst).count -= 1;
|
||||
return ret;
|
||||
}
|
||||
pub unsafe fn clist_foreach(
|
||||
mut lst: *mut clist,
|
||||
mut func: clist_func,
|
||||
mut data: *mut libc::c_void,
|
||||
) {
|
||||
let mut cur: *mut clistiter = 0 as *mut clistiter;
|
||||
cur = (*lst).first;
|
||||
while !cur.is_null() {
|
||||
func.expect("non-null function pointer")((*cur).data, data);
|
||||
cur = (*cur).next
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn clist_nth_data(mut lst: *mut clist, mut indx: libc::c_int) -> *mut libc::c_void {
|
||||
let mut cur: *mut clistiter = 0 as *mut clistiter;
|
||||
cur = internal_clist_nth(lst, indx);
|
||||
if cur.is_null() {
|
||||
return 0 as *mut libc::c_void;
|
||||
}
|
||||
return (*cur).data;
|
||||
}
|
||||
#[inline]
|
||||
unsafe fn internal_clist_nth(mut lst: *mut clist, mut indx: libc::c_int) -> *mut clistiter {
|
||||
let mut cur: *mut clistiter = 0 as *mut clistiter;
|
||||
cur = (*lst).first;
|
||||
while indx > 0i32 && !cur.is_null() {
|
||||
cur = (*cur).next;
|
||||
indx -= 1
|
||||
}
|
||||
if cur.is_null() {
|
||||
return 0 as *mut clistiter;
|
||||
}
|
||||
return cur;
|
||||
}
|
||||
|
||||
pub unsafe fn clist_nth(mut lst: *mut clist, mut indx: libc::c_int) -> *mut clistiter {
|
||||
return internal_clist_nth(lst, indx);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::ptr;
|
||||
#[test]
|
||||
fn test_clist_iterator() {
|
||||
unsafe {
|
||||
let mut c = clist_new();
|
||||
assert!(!c.is_null());
|
||||
clist_insert_after(c, ptr::null_mut(), clist_nth as _);
|
||||
assert_eq!((*c).count, 1);
|
||||
|
||||
/* Only one iteration */
|
||||
for data in &*c {
|
||||
assert_eq!(data, clist_nth as _);
|
||||
}
|
||||
assert_eq!((*c).count, 1);
|
||||
|
||||
clist_free(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
pub const MAIL_ERROR_SSL: libc::c_uint = 58;
|
||||
pub const MAIL_ERROR_FOLDER: libc::c_uint = 57;
|
||||
pub const MAIL_ERROR_UNABLE: libc::c_uint = 56;
|
||||
pub const MAIL_ERROR_SYSTEM: libc::c_uint = 55;
|
||||
pub const MAIL_ERROR_COMMAND: libc::c_uint = 54;
|
||||
pub const MAIL_ERROR_SEND: libc::c_uint = 53;
|
||||
pub const MAIL_ERROR_CHAR_ENCODING_FAILED: libc::c_uint = 52;
|
||||
pub const MAIL_ERROR_SUBJECT_NOT_FOUND: libc::c_uint = 51;
|
||||
/* 50 */
|
||||
pub const MAIL_ERROR_PROGRAM_ERROR: libc::c_uint = 50;
|
||||
pub const MAIL_ERROR_NO_PERMISSION: libc::c_uint = 49;
|
||||
pub const MAIL_ERROR_COMMAND_NOT_SUPPORTED: libc::c_uint = 48;
|
||||
pub const MAIL_ERROR_NO_APOP: libc::c_uint = 47;
|
||||
pub const MAIL_ERROR_READONLY: libc::c_uint = 46;
|
||||
pub const MAIL_ERROR_FATAL: libc::c_uint = 45;
|
||||
pub const MAIL_ERROR_CLOSE: libc::c_uint = 44;
|
||||
pub const MAIL_ERROR_CAPABILITY: libc::c_uint = 43;
|
||||
pub const MAIL_ERROR_PROTOCOL: libc::c_uint = 42;
|
||||
/* misc errors */
|
||||
pub const MAIL_ERROR_MISC: libc::c_uint = 41;
|
||||
/* 40 */
|
||||
pub const MAIL_ERROR_EXPUNGE: libc::c_uint = 40;
|
||||
pub const MAIL_ERROR_NO_TLS: libc::c_uint = 39;
|
||||
pub const MAIL_ERROR_CACHE_MISS: libc::c_uint = 38;
|
||||
pub const MAIL_ERROR_STARTTLS: libc::c_uint = 37;
|
||||
pub const MAIL_ERROR_MOVE: libc::c_uint = 36;
|
||||
pub const MAIL_ERROR_FOLDER_NOT_FOUND: libc::c_uint = 35;
|
||||
pub const MAIL_ERROR_REMOVE: libc::c_uint = 34;
|
||||
pub const MAIL_ERROR_PART_NOT_FOUND: libc::c_uint = 33;
|
||||
pub const MAIL_ERROR_INVAL: libc::c_uint = 32;
|
||||
pub const MAIL_ERROR_PARSE: libc::c_uint = 31;
|
||||
/* 30 */
|
||||
pub const MAIL_ERROR_MSG_NOT_FOUND: libc::c_uint = 30;
|
||||
pub const MAIL_ERROR_DISKSPACE: libc::c_uint = 29;
|
||||
pub const MAIL_ERROR_SEARCH: libc::c_uint = 28;
|
||||
pub const MAIL_ERROR_STORE: libc::c_uint = 27;
|
||||
pub const MAIL_ERROR_FETCH: libc::c_uint = 26;
|
||||
pub const MAIL_ERROR_COPY: libc::c_uint = 25;
|
||||
pub const MAIL_ERROR_APPEND: libc::c_uint = 24;
|
||||
pub const MAIL_ERROR_LSUB: libc::c_uint = 23;
|
||||
pub const MAIL_ERROR_LIST: libc::c_uint = 22;
|
||||
pub const MAIL_ERROR_UNSUBSCRIBE: libc::c_uint = 21;
|
||||
/* 20 */
|
||||
pub const MAIL_ERROR_SUBSCRIBE: libc::c_uint = 20;
|
||||
pub const MAIL_ERROR_STATUS: libc::c_uint = 19;
|
||||
pub const MAIL_ERROR_MEMORY: libc::c_uint = 18;
|
||||
pub const MAIL_ERROR_SELECT: libc::c_uint = 17;
|
||||
pub const MAIL_ERROR_EXAMINE: libc::c_uint = 16;
|
||||
pub const MAIL_ERROR_CHECK: libc::c_uint = 15;
|
||||
pub const MAIL_ERROR_RENAME: libc::c_uint = 14;
|
||||
pub const MAIL_ERROR_NOOP: libc::c_uint = 13;
|
||||
pub const MAIL_ERROR_LOGOUT: libc::c_uint = 12;
|
||||
pub const MAIL_ERROR_DELETE: libc::c_uint = 11;
|
||||
/* 10 */
|
||||
pub const MAIL_ERROR_CREATE: libc::c_uint = 10;
|
||||
pub const MAIL_ERROR_LOGIN: libc::c_uint = 9;
|
||||
pub const MAIL_ERROR_STREAM: libc::c_uint = 8;
|
||||
pub const MAIL_ERROR_FILE: libc::c_uint = 7;
|
||||
pub const MAIL_ERROR_BAD_STATE: libc::c_uint = 6;
|
||||
pub const MAIL_ERROR_CONNECT: libc::c_uint = 5;
|
||||
pub const MAIL_ERROR_UNKNOWN: libc::c_uint = 4;
|
||||
pub const MAIL_ERROR_NOT_IMPLEMENTED: libc::c_uint = 3;
|
||||
pub const MAIL_NO_ERROR_NON_AUTHENTICATED: libc::c_uint = 2;
|
||||
pub const MAIL_NO_ERROR_AUTHENTICATED: libc::c_uint = 1;
|
||||
pub const MAIL_NO_ERROR: libc::c_uint = 0;
|
||||
|
||||
pub const MAILIMF_ERROR_FILE: libc::c_uint = 4;
|
||||
pub const MAILIMF_ERROR_INVAL: libc::c_uint = 3;
|
||||
pub const MAILIMF_ERROR_MEMORY: libc::c_uint = 2;
|
||||
pub const MAILIMF_ERROR_PARSE: libc::c_uint = 1;
|
||||
pub const MAILIMF_NO_ERROR: libc::c_uint = 0;
|
||||
@@ -1,386 +0,0 @@
|
||||
use crate::clist::*;
|
||||
|
||||
use crate::mailimf::types::*;
|
||||
use crate::mailmime::types::*;
|
||||
|
||||
use std::ffi::CStr;
|
||||
|
||||
pub unsafe fn display_mime(mut mime: *mut Mailmime) {
|
||||
let mut cur: *mut clistiter = 0 as *mut clistiter;
|
||||
println!("{}", (*mime).mm_type);
|
||||
|
||||
match (*mime).mm_type as u32 {
|
||||
MAILMIME_SINGLE => {
|
||||
println!("single part");
|
||||
}
|
||||
MAILMIME_MULTIPLE => {
|
||||
println!("multipart");
|
||||
}
|
||||
MAILMIME_MESSAGE => println!("message"),
|
||||
_ => {}
|
||||
}
|
||||
if !(*mime).mm_mime_fields.is_null() {
|
||||
if !(*(*(*mime).mm_mime_fields).fld_list).first.is_null() {
|
||||
print!("MIME headers begin");
|
||||
display_mime_fields((*mime).mm_mime_fields);
|
||||
println!("MIME headers end");
|
||||
}
|
||||
}
|
||||
display_mime_content((*mime).mm_content_type);
|
||||
match (*mime).mm_type as u32 {
|
||||
MAILMIME_SINGLE => {
|
||||
display_mime_data((*mime).mm_data.mm_single);
|
||||
}
|
||||
MAILMIME_MULTIPLE => {
|
||||
cur = (*(*mime).mm_data.mm_multipart.mm_mp_list).first;
|
||||
while !cur.is_null() {
|
||||
display_mime(
|
||||
(if !cur.is_null() {
|
||||
(*cur).data
|
||||
} else {
|
||||
0 as *mut libc::c_void
|
||||
}) as *mut Mailmime,
|
||||
);
|
||||
cur = if !cur.is_null() {
|
||||
(*cur).next
|
||||
} else {
|
||||
0 as *mut clistcell
|
||||
}
|
||||
}
|
||||
}
|
||||
MAILMIME_MESSAGE => {
|
||||
if !(*mime).mm_data.mm_message.mm_fields.is_null() {
|
||||
if !(*(*(*mime).mm_data.mm_message.mm_fields).fld_list)
|
||||
.first
|
||||
.is_null()
|
||||
{
|
||||
println!("headers begin");
|
||||
display_fields((*mime).mm_data.mm_message.mm_fields);
|
||||
println!("headers end");
|
||||
}
|
||||
if !(*mime).mm_data.mm_message.mm_msg_mime.is_null() {
|
||||
display_mime((*mime).mm_data.mm_message.mm_msg_mime);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
|
||||
unsafe fn display_mime_content(mut content_type: *mut mailmime_content) {
|
||||
print!("type: ");
|
||||
display_mime_type((*content_type).ct_type);
|
||||
println!(
|
||||
"/{}",
|
||||
CStr::from_ptr((*content_type).ct_subtype).to_str().unwrap()
|
||||
);
|
||||
}
|
||||
unsafe fn display_mime_type(mut type_0: *mut mailmime_type) {
|
||||
match (*type_0).tp_type {
|
||||
1 => {
|
||||
display_mime_discrete_type((*type_0).tp_data.tp_discrete_type);
|
||||
}
|
||||
2 => {
|
||||
display_mime_composite_type((*type_0).tp_data.tp_composite_type);
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
unsafe fn display_mime_composite_type(mut ct: *mut mailmime_composite_type) {
|
||||
match (*ct).ct_type {
|
||||
1 => {
|
||||
print!("message");
|
||||
}
|
||||
2 => {
|
||||
print!("multipart");
|
||||
}
|
||||
3 => {
|
||||
print!("{}", CStr::from_ptr((*ct).ct_token).to_str().unwrap());
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
unsafe fn display_mime_discrete_type(mut discrete_type: *mut mailmime_discrete_type) {
|
||||
match (*discrete_type).dt_type {
|
||||
1 => {
|
||||
print!("text");
|
||||
}
|
||||
2 => {
|
||||
print!("image");
|
||||
}
|
||||
3 => {
|
||||
print!("audio");
|
||||
}
|
||||
4 => {
|
||||
print!("video");
|
||||
}
|
||||
5 => {
|
||||
print!("application");
|
||||
}
|
||||
6 => {
|
||||
print!("{}", (*discrete_type).dt_extension as u8 as char);
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
pub unsafe fn display_mime_data(mut data: *mut mailmime_data) {
|
||||
match (*data).dt_type {
|
||||
0 => {
|
||||
println!(
|
||||
"data : {} bytes",
|
||||
(*data).dt_data.dt_text.dt_length as libc::c_uint,
|
||||
);
|
||||
}
|
||||
1 => {
|
||||
println!(
|
||||
"data (file) : {}",
|
||||
CStr::from_ptr((*data).dt_data.dt_filename)
|
||||
.to_str()
|
||||
.unwrap()
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
unsafe fn display_mime_dsp_parm(mut param: *mut mailmime_disposition_parm) {
|
||||
match (*param).pa_type {
|
||||
0 => {
|
||||
println!(
|
||||
"filename: {}",
|
||||
CStr::from_ptr((*param).pa_data.pa_filename)
|
||||
.to_str()
|
||||
.unwrap()
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
unsafe fn display_mime_disposition(mut disposition: *mut mailmime_disposition) {
|
||||
let mut cur: *mut clistiter = 0 as *mut clistiter;
|
||||
cur = (*(*disposition).dsp_parms).first;
|
||||
while !cur.is_null() {
|
||||
let mut param: *mut mailmime_disposition_parm = 0 as *mut mailmime_disposition_parm;
|
||||
param = (if !cur.is_null() {
|
||||
(*cur).data
|
||||
} else {
|
||||
0 as *mut libc::c_void
|
||||
}) as *mut mailmime_disposition_parm;
|
||||
display_mime_dsp_parm(param);
|
||||
cur = if !cur.is_null() {
|
||||
(*cur).next
|
||||
} else {
|
||||
0 as *mut clistcell
|
||||
}
|
||||
}
|
||||
}
|
||||
unsafe fn display_mime_field(mut field: *mut mailmime_field) {
|
||||
match (*field).fld_type {
|
||||
1 => {
|
||||
print!("content-type: ");
|
||||
display_mime_content((*field).fld_data.fld_content);
|
||||
println!("");
|
||||
}
|
||||
6 => {
|
||||
display_mime_disposition((*field).fld_data.fld_disposition);
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
unsafe fn display_mime_fields(mut fields: *mut mailmime_fields) {
|
||||
let mut cur: *mut clistiter = 0 as *mut clistiter;
|
||||
cur = (*(*fields).fld_list).first;
|
||||
while !cur.is_null() {
|
||||
let mut field: *mut mailmime_field = 0 as *mut mailmime_field;
|
||||
field = (if !cur.is_null() {
|
||||
(*cur).data
|
||||
} else {
|
||||
0 as *mut libc::c_void
|
||||
}) as *mut mailmime_field;
|
||||
display_mime_field(field);
|
||||
cur = if !cur.is_null() {
|
||||
(*cur).next
|
||||
} else {
|
||||
0 as *mut clistcell
|
||||
}
|
||||
}
|
||||
}
|
||||
unsafe fn display_date_time(mut d: *mut mailimf_date_time) {
|
||||
print!(
|
||||
"{:02}/{:02}/{:02} {:02}:{:02}:{:02} +{:04}",
|
||||
(*d).dt_day,
|
||||
(*d).dt_month,
|
||||
(*d).dt_year,
|
||||
(*d).dt_hour,
|
||||
(*d).dt_min,
|
||||
(*d).dt_sec,
|
||||
(*d).dt_zone,
|
||||
);
|
||||
}
|
||||
unsafe fn display_orig_date(mut orig_date: *mut mailimf_orig_date) {
|
||||
display_date_time((*orig_date).dt_date_time);
|
||||
}
|
||||
unsafe fn display_mailbox(mut mb: *mut mailimf_mailbox) {
|
||||
if !(*mb).mb_display_name.is_null() {
|
||||
print!(
|
||||
"{}",
|
||||
CStr::from_ptr((*mb).mb_display_name).to_str().unwrap()
|
||||
);
|
||||
}
|
||||
print!("<{}>", CStr::from_ptr((*mb).mb_addr_spec).to_str().unwrap());
|
||||
}
|
||||
unsafe fn display_mailbox_list(mut mb_list: *mut mailimf_mailbox_list) {
|
||||
let mut cur: *mut clistiter = 0 as *mut clistiter;
|
||||
cur = (*(*mb_list).mb_list).first;
|
||||
while !cur.is_null() {
|
||||
let mut mb: *mut mailimf_mailbox = 0 as *mut mailimf_mailbox;
|
||||
mb = (if !cur.is_null() {
|
||||
(*cur).data
|
||||
} else {
|
||||
0 as *mut libc::c_void
|
||||
}) as *mut mailimf_mailbox;
|
||||
display_mailbox(mb);
|
||||
if !if !cur.is_null() {
|
||||
(*cur).next
|
||||
} else {
|
||||
0 as *mut clistcell
|
||||
}
|
||||
.is_null()
|
||||
{
|
||||
print!(", ");
|
||||
}
|
||||
cur = if !cur.is_null() {
|
||||
(*cur).next
|
||||
} else {
|
||||
0 as *mut clistcell
|
||||
}
|
||||
}
|
||||
}
|
||||
unsafe fn display_group(mut group: *mut mailimf_group) {
|
||||
let mut cur: *mut clistiter = 0 as *mut clistiter;
|
||||
print!(
|
||||
"{}: ",
|
||||
CStr::from_ptr((*group).grp_display_name).to_str().unwrap()
|
||||
);
|
||||
cur = (*(*(*group).grp_mb_list).mb_list).first;
|
||||
while !cur.is_null() {
|
||||
let mut mb: *mut mailimf_mailbox = 0 as *mut mailimf_mailbox;
|
||||
mb = (if !cur.is_null() {
|
||||
(*cur).data
|
||||
} else {
|
||||
0 as *mut libc::c_void
|
||||
}) as *mut mailimf_mailbox;
|
||||
display_mailbox(mb);
|
||||
cur = if !cur.is_null() {
|
||||
(*cur).next
|
||||
} else {
|
||||
0 as *mut clistcell
|
||||
}
|
||||
}
|
||||
print!("; ");
|
||||
}
|
||||
unsafe fn display_address(mut a: *mut mailimf_address) {
|
||||
match (*a).ad_type {
|
||||
2 => {
|
||||
display_group((*a).ad_data.ad_group);
|
||||
}
|
||||
1 => {
|
||||
display_mailbox((*a).ad_data.ad_mailbox);
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
unsafe fn display_address_list(mut addr_list: *mut mailimf_address_list) {
|
||||
let mut cur: *mut clistiter = 0 as *mut clistiter;
|
||||
cur = (*(*addr_list).ad_list).first;
|
||||
while !cur.is_null() {
|
||||
let mut addr: *mut mailimf_address = 0 as *mut mailimf_address;
|
||||
addr = (if !cur.is_null() {
|
||||
(*cur).data
|
||||
} else {
|
||||
0 as *mut libc::c_void
|
||||
}) as *mut mailimf_address;
|
||||
display_address(addr);
|
||||
if !if !cur.is_null() {
|
||||
(*cur).next
|
||||
} else {
|
||||
0 as *mut clistcell
|
||||
}
|
||||
.is_null()
|
||||
{
|
||||
print!(", ");
|
||||
}
|
||||
cur = if !cur.is_null() {
|
||||
(*cur).next
|
||||
} else {
|
||||
0 as *mut clistcell
|
||||
}
|
||||
}
|
||||
}
|
||||
unsafe fn display_from(mut from: *mut mailimf_from) {
|
||||
display_mailbox_list((*from).frm_mb_list);
|
||||
}
|
||||
unsafe fn display_to(mut to: *mut mailimf_to) {
|
||||
display_address_list((*to).to_addr_list);
|
||||
}
|
||||
unsafe fn display_cc(mut cc: *mut mailimf_cc) {
|
||||
display_address_list((*cc).cc_addr_list);
|
||||
}
|
||||
unsafe fn display_subject(mut subject: *mut mailimf_subject) {
|
||||
print!("{}", CStr::from_ptr((*subject).sbj_value).to_str().unwrap());
|
||||
}
|
||||
unsafe fn display_field(mut field: *mut mailimf_field) {
|
||||
match (*field).fld_type {
|
||||
9 => {
|
||||
print!("Date: ");
|
||||
display_orig_date((*field).fld_data.fld_orig_date);
|
||||
println!("");
|
||||
}
|
||||
10 => {
|
||||
print!("From: ");
|
||||
display_from((*field).fld_data.fld_from);
|
||||
println!("");
|
||||
}
|
||||
13 => {
|
||||
print!("To: ");
|
||||
display_to((*field).fld_data.fld_to);
|
||||
println!("");
|
||||
}
|
||||
14 => {
|
||||
print!("Cc: ");
|
||||
display_cc((*field).fld_data.fld_cc);
|
||||
println!("");
|
||||
}
|
||||
19 => {
|
||||
print!("Subject: ");
|
||||
display_subject((*field).fld_data.fld_subject);
|
||||
println!("");
|
||||
}
|
||||
16 => {
|
||||
println!(
|
||||
"Message-ID: {}",
|
||||
CStr::from_ptr((*(*field).fld_data.fld_message_id).mid_value)
|
||||
.to_str()
|
||||
.unwrap(),
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
unsafe fn display_fields(mut fields: *mut mailimf_fields) {
|
||||
let mut cur: *mut clistiter = 0 as *mut clistiter;
|
||||
cur = (*(*fields).fld_list).first;
|
||||
while !cur.is_null() {
|
||||
let mut f: *mut mailimf_field = 0 as *mut mailimf_field;
|
||||
f = (if !cur.is_null() {
|
||||
(*cur).data
|
||||
} else {
|
||||
0 as *mut libc::c_void
|
||||
}) as *mut mailimf_field;
|
||||
display_field(f);
|
||||
cur = if !cur.is_null() {
|
||||
(*cur).next
|
||||
} else {
|
||||
0 as *mut clistcell
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
#![deny(clippy::correctness)]
|
||||
// TODO: make all of these errors, such that clippy actually passes.
|
||||
#![warn(clippy::all, clippy::perf, clippy::not_unsafe_ptr_arg_deref)]
|
||||
// This is nice, but for now just annoying.
|
||||
#![allow(clippy::unreadable_literal)]
|
||||
#![feature(ptr_wrapping_offset_from)]
|
||||
#![allow(unused_attributes)]
|
||||
#![allow(unused_variables)]
|
||||
#![allow(mutable_transmutes)]
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(non_snake_case)]
|
||||
#![allow(non_upper_case_globals)]
|
||||
#![allow(unused_assignments)]
|
||||
#![allow(unused_mut)]
|
||||
#![allow(unused_must_use)]
|
||||
#![feature(extern_types)]
|
||||
#![feature(const_raw_ptr_to_usize_cast)]
|
||||
|
||||
pub mod charconv;
|
||||
pub mod chash;
|
||||
pub mod clist;
|
||||
pub mod display;
|
||||
pub mod mailimf;
|
||||
pub mod mailmime;
|
||||
pub mod mmapstring;
|
||||
pub mod other;
|
||||
|
||||
pub use self::charconv::*;
|
||||
pub use self::chash::*;
|
||||
pub use self::clist::*;
|
||||
pub use self::display::*;
|
||||
pub use self::mailimf::*;
|
||||
pub use self::mailmime::*;
|
||||
pub use self::mmapstring::*;
|
||||
pub use self::other::*;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn mailmime_parse_test() {
|
||||
unsafe {
|
||||
let data = "MIME-Version: 1.0\
|
||||
Content-Type: multipart/mixed; boundary=frontier\
|
||||
\
|
||||
This is a message with multiple parts in MIME format.\
|
||||
--frontier\
|
||||
Content-Type: text/plain\
|
||||
\
|
||||
This is the body of the message.\
|
||||
--frontier\
|
||||
Content-Type: application/octet-stream\
|
||||
Content-Transfer-Encoding: base64\
|
||||
\
|
||||
PGh0bWw+CiAgPGhlYWQ+CiAgPC9oZWFkPgogIDxib2R5PgogICAgPHA+VGhpcyBpcyB0aGUg\
|
||||
Ym9keSBvZiB0aGUgbWVzc2FnZS48L3A+CiAgPC9ib2R5Pgo8L2h0bWw+Cg==\
|
||||
--frontier--";
|
||||
let c_data = std::ffi::CString::new(data).unwrap();
|
||||
|
||||
let mut current_index = 0;
|
||||
let mut mime = std::ptr::null_mut();
|
||||
let res = crate::mailmime::content::mailmime_parse(
|
||||
c_data.as_ptr(),
|
||||
data.len() as usize,
|
||||
&mut current_index,
|
||||
&mut mime,
|
||||
);
|
||||
|
||||
assert_eq!(res, MAIL_NO_ERROR as libc::c_int);
|
||||
assert!(!mime.is_null());
|
||||
|
||||
display_mime(mime);
|
||||
|
||||
mailmime::types::mailmime_free(mime);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,89 +0,0 @@
|
||||
use crate::clist::*;
|
||||
use crate::mailimf::types::*;
|
||||
use crate::other::*;
|
||||
|
||||
/*
|
||||
this function creates a new mailimf_fields structure with no fields
|
||||
*/
|
||||
pub unsafe fn mailimf_fields_new_empty() -> *mut mailimf_fields {
|
||||
let mut list: *mut clist = 0 as *mut clist;
|
||||
let mut fields_list: *mut mailimf_fields = 0 as *mut mailimf_fields;
|
||||
list = clist_new();
|
||||
if list.is_null() {
|
||||
return 0 as *mut mailimf_fields;
|
||||
}
|
||||
fields_list = mailimf_fields_new(list);
|
||||
if fields_list.is_null() {
|
||||
return 0 as *mut mailimf_fields;
|
||||
}
|
||||
return fields_list;
|
||||
}
|
||||
/*
|
||||
this function adds a field to the mailimf_fields structure
|
||||
|
||||
@return MAILIMF_NO_ERROR will be returned on success,
|
||||
other code will be returned otherwise
|
||||
*/
|
||||
pub unsafe fn mailimf_fields_add(
|
||||
mut fields: *mut mailimf_fields,
|
||||
mut field: *mut mailimf_field,
|
||||
) -> libc::c_int {
|
||||
let mut r: libc::c_int = 0;
|
||||
r = clist_insert_after(
|
||||
(*fields).fld_list,
|
||||
(*(*fields).fld_list).last,
|
||||
field as *mut libc::c_void,
|
||||
);
|
||||
if r < 0i32 {
|
||||
return MAILIMF_ERROR_MEMORY as libc::c_int;
|
||||
}
|
||||
return MAILIMF_NO_ERROR as libc::c_int;
|
||||
}
|
||||
|
||||
/*
|
||||
mailimf_field_new_custom creates a new field of type optional
|
||||
|
||||
@param name should be allocated with malloc()
|
||||
@param value should be allocated with malloc()
|
||||
*/
|
||||
pub unsafe fn mailimf_field_new_custom(
|
||||
mut name: *mut libc::c_char,
|
||||
mut value: *mut libc::c_char,
|
||||
) -> *mut mailimf_field {
|
||||
let mut opt_field: *mut mailimf_optional_field = 0 as *mut mailimf_optional_field;
|
||||
let mut field: *mut mailimf_field = 0 as *mut mailimf_field;
|
||||
opt_field = mailimf_optional_field_new(name, value);
|
||||
if !opt_field.is_null() {
|
||||
field = mailimf_field_new(
|
||||
MAILIMF_FIELD_OPTIONAL_FIELD as libc::c_int,
|
||||
0 as *mut mailimf_return,
|
||||
0 as *mut mailimf_orig_date,
|
||||
0 as *mut mailimf_from,
|
||||
0 as *mut mailimf_sender,
|
||||
0 as *mut mailimf_to,
|
||||
0 as *mut mailimf_cc,
|
||||
0 as *mut mailimf_bcc,
|
||||
0 as *mut mailimf_message_id,
|
||||
0 as *mut mailimf_orig_date,
|
||||
0 as *mut mailimf_from,
|
||||
0 as *mut mailimf_sender,
|
||||
0 as *mut mailimf_reply_to,
|
||||
0 as *mut mailimf_to,
|
||||
0 as *mut mailimf_cc,
|
||||
0 as *mut mailimf_bcc,
|
||||
0 as *mut mailimf_message_id,
|
||||
0 as *mut mailimf_in_reply_to,
|
||||
0 as *mut mailimf_references,
|
||||
0 as *mut mailimf_subject,
|
||||
0 as *mut mailimf_comments,
|
||||
0 as *mut mailimf_keywords,
|
||||
opt_field,
|
||||
);
|
||||
if field.is_null() {
|
||||
mailimf_optional_field_free(opt_field);
|
||||
} else {
|
||||
return field;
|
||||
}
|
||||
}
|
||||
return 0 as *mut mailimf_field;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,860 +0,0 @@
|
||||
use libc;
|
||||
use libc::toupper;
|
||||
|
||||
use crate::charconv::*;
|
||||
use crate::mailimf::*;
|
||||
use crate::mailmime::content::*;
|
||||
use crate::mailmime::types::*;
|
||||
use crate::mmapstring::*;
|
||||
use crate::other::*;
|
||||
|
||||
pub const TYPE_WORD: libc::c_uint = 1;
|
||||
pub const TYPE_ENCODED_WORD: libc::c_uint = 2;
|
||||
pub const MAILMIME_ENCODING_Q: libc::c_uint = 1;
|
||||
pub const MAILMIME_ENCODING_B: libc::c_uint = 0;
|
||||
pub const TYPE_ERROR: libc::c_uint = 0;
|
||||
|
||||
pub unsafe fn mailmime_encoded_phrase_parse(
|
||||
mut default_fromcode: *const libc::c_char,
|
||||
mut message: *const libc::c_char,
|
||||
mut length: size_t,
|
||||
mut indx: *mut size_t,
|
||||
mut tocode: *const libc::c_char,
|
||||
mut result: *mut *mut libc::c_char,
|
||||
) -> libc::c_int {
|
||||
let mut current_block: u64;
|
||||
let mut gphrase: *mut MMAPString = 0 as *mut MMAPString;
|
||||
let mut word: *mut mailmime_encoded_word = 0 as *mut mailmime_encoded_word;
|
||||
let mut first: libc::c_int = 0;
|
||||
let mut cur_token: size_t = 0;
|
||||
let mut r: libc::c_int = 0;
|
||||
let mut res: libc::c_int = 0;
|
||||
let mut str: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut wordutf8: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut type_0: libc::c_int = 0;
|
||||
let mut missing_closing_quote: libc::c_int = 0;
|
||||
cur_token = *indx;
|
||||
gphrase = mmap_string_new(b"\x00" as *const u8 as *const libc::c_char);
|
||||
if gphrase.is_null() {
|
||||
res = MAILIMF_ERROR_MEMORY as libc::c_int
|
||||
} else {
|
||||
first = 1i32;
|
||||
type_0 = TYPE_ERROR as libc::c_int;
|
||||
loop {
|
||||
let mut has_fwd: libc::c_int = 0;
|
||||
word = 0 as *mut mailmime_encoded_word;
|
||||
r = mailmime_encoded_word_parse(
|
||||
message,
|
||||
length,
|
||||
&mut cur_token,
|
||||
&mut word,
|
||||
&mut has_fwd,
|
||||
&mut missing_closing_quote,
|
||||
);
|
||||
if r == MAILIMF_NO_ERROR as libc::c_int {
|
||||
if 0 == first && 0 != has_fwd {
|
||||
if type_0 != TYPE_ENCODED_WORD as libc::c_int {
|
||||
if mmap_string_append_c(gphrase, ' ' as i32 as libc::c_char).is_null() {
|
||||
mailmime_encoded_word_free(word);
|
||||
res = MAILIMF_ERROR_MEMORY as libc::c_int;
|
||||
current_block = 13246848547199022064;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
type_0 = TYPE_ENCODED_WORD as libc::c_int;
|
||||
wordutf8 = 0 as *mut libc::c_char;
|
||||
r = charconv(
|
||||
tocode,
|
||||
(*word).wd_charset,
|
||||
(*word).wd_text,
|
||||
strlen((*word).wd_text),
|
||||
&mut wordutf8,
|
||||
);
|
||||
match r {
|
||||
2 => {
|
||||
mailmime_encoded_word_free(word);
|
||||
res = MAILIMF_ERROR_MEMORY as libc::c_int;
|
||||
current_block = 13246848547199022064;
|
||||
break;
|
||||
}
|
||||
1 => {
|
||||
r = charconv(
|
||||
tocode,
|
||||
b"iso-8859-1\x00" as *const u8 as *const libc::c_char,
|
||||
(*word).wd_text,
|
||||
strlen((*word).wd_text),
|
||||
&mut wordutf8,
|
||||
)
|
||||
}
|
||||
3 => {
|
||||
mailmime_encoded_word_free(word);
|
||||
res = MAILIMF_ERROR_PARSE as libc::c_int;
|
||||
current_block = 13246848547199022064;
|
||||
break;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
match r {
|
||||
2 => {
|
||||
mailmime_encoded_word_free(word);
|
||||
res = MAILIMF_ERROR_MEMORY as libc::c_int;
|
||||
current_block = 13246848547199022064;
|
||||
break;
|
||||
}
|
||||
3 => {
|
||||
mailmime_encoded_word_free(word);
|
||||
res = MAILIMF_ERROR_PARSE as libc::c_int;
|
||||
current_block = 13246848547199022064;
|
||||
break;
|
||||
}
|
||||
_ => {
|
||||
if !wordutf8.is_null() {
|
||||
if mmap_string_append(gphrase, wordutf8).is_null() {
|
||||
mailmime_encoded_word_free(word);
|
||||
free(wordutf8 as *mut libc::c_void);
|
||||
res = MAILIMF_ERROR_MEMORY as libc::c_int;
|
||||
current_block = 13246848547199022064;
|
||||
break;
|
||||
} else {
|
||||
free(wordutf8 as *mut libc::c_void);
|
||||
}
|
||||
}
|
||||
mailmime_encoded_word_free(word);
|
||||
first = 0i32
|
||||
}
|
||||
}
|
||||
} else if !(r == MAILIMF_ERROR_PARSE as libc::c_int) {
|
||||
/* do nothing */
|
||||
res = r;
|
||||
current_block = 13246848547199022064;
|
||||
break;
|
||||
}
|
||||
if !(r == MAILIMF_ERROR_PARSE as libc::c_int) {
|
||||
continue;
|
||||
}
|
||||
let mut raw_word: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
raw_word = 0 as *mut libc::c_char;
|
||||
r = mailmime_non_encoded_word_parse(
|
||||
message,
|
||||
length,
|
||||
&mut cur_token,
|
||||
&mut raw_word,
|
||||
&mut has_fwd,
|
||||
);
|
||||
if r == MAILIMF_NO_ERROR as libc::c_int {
|
||||
if 0 == first && 0 != has_fwd {
|
||||
if mmap_string_append_c(gphrase, ' ' as i32 as libc::c_char).is_null() {
|
||||
free(raw_word as *mut libc::c_void);
|
||||
res = MAILIMF_ERROR_MEMORY as libc::c_int;
|
||||
current_block = 13246848547199022064;
|
||||
break;
|
||||
}
|
||||
}
|
||||
type_0 = TYPE_WORD as libc::c_int;
|
||||
wordutf8 = 0 as *mut libc::c_char;
|
||||
r = charconv(
|
||||
tocode,
|
||||
default_fromcode,
|
||||
raw_word,
|
||||
strlen(raw_word),
|
||||
&mut wordutf8,
|
||||
);
|
||||
match r {
|
||||
2 => {
|
||||
free(raw_word as *mut libc::c_void);
|
||||
res = MAILIMF_ERROR_MEMORY as libc::c_int;
|
||||
current_block = 13246848547199022064;
|
||||
break;
|
||||
}
|
||||
1 | 3 => {
|
||||
free(raw_word as *mut libc::c_void);
|
||||
res = MAILIMF_ERROR_PARSE as libc::c_int;
|
||||
current_block = 13246848547199022064;
|
||||
break;
|
||||
}
|
||||
_ => {
|
||||
if mmap_string_append(gphrase, wordutf8).is_null() {
|
||||
free(wordutf8 as *mut libc::c_void);
|
||||
free(raw_word as *mut libc::c_void);
|
||||
res = MAILIMF_ERROR_MEMORY as libc::c_int;
|
||||
current_block = 13246848547199022064;
|
||||
break;
|
||||
} else {
|
||||
free(wordutf8 as *mut libc::c_void);
|
||||
free(raw_word as *mut libc::c_void);
|
||||
first = 0i32
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if r == MAILIMF_ERROR_PARSE as libc::c_int {
|
||||
r = mailimf_fws_parse(message, length, &mut cur_token);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
current_block = 5005389895767293342;
|
||||
break;
|
||||
}
|
||||
if mmap_string_append_c(gphrase, ' ' as i32 as libc::c_char).is_null() {
|
||||
res = MAILIMF_ERROR_MEMORY as libc::c_int;
|
||||
current_block = 13246848547199022064;
|
||||
break;
|
||||
} else {
|
||||
first = 0i32;
|
||||
current_block = 5005389895767293342;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
res = r;
|
||||
current_block = 13246848547199022064;
|
||||
break;
|
||||
}
|
||||
}
|
||||
match current_block {
|
||||
5005389895767293342 => {
|
||||
if 0 != first {
|
||||
if cur_token != length {
|
||||
res = MAILIMF_ERROR_PARSE as libc::c_int;
|
||||
current_block = 13246848547199022064;
|
||||
} else {
|
||||
current_block = 7072655752890836508;
|
||||
}
|
||||
} else {
|
||||
current_block = 7072655752890836508;
|
||||
}
|
||||
match current_block {
|
||||
13246848547199022064 => {}
|
||||
_ => {
|
||||
str = strdup((*gphrase).str_0);
|
||||
if str.is_null() {
|
||||
res = MAILIMF_ERROR_MEMORY as libc::c_int
|
||||
} else {
|
||||
mmap_string_free(gphrase);
|
||||
*result = str;
|
||||
*indx = cur_token;
|
||||
return MAILIMF_NO_ERROR as libc::c_int;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
mmap_string_free(gphrase);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
unsafe fn mailmime_non_encoded_word_parse(
|
||||
mut message: *const libc::c_char,
|
||||
mut length: size_t,
|
||||
mut indx: *mut size_t,
|
||||
mut result: *mut *mut libc::c_char,
|
||||
mut p_has_fwd: *mut libc::c_int,
|
||||
) -> libc::c_int {
|
||||
let mut end: libc::c_int = 0;
|
||||
let mut cur_token: size_t = 0;
|
||||
let mut res: libc::c_int = 0;
|
||||
let mut text: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut r: libc::c_int = 0;
|
||||
let mut begin: size_t = 0;
|
||||
let mut state: libc::c_int = 0;
|
||||
let mut has_fwd: libc::c_int = 0;
|
||||
cur_token = *indx;
|
||||
has_fwd = 0i32;
|
||||
r = mailimf_fws_parse(message, length, &mut cur_token);
|
||||
if r == MAILIMF_NO_ERROR as libc::c_int {
|
||||
has_fwd = 1i32
|
||||
}
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int && r != MAILIMF_ERROR_PARSE as libc::c_int {
|
||||
res = r
|
||||
} else {
|
||||
begin = cur_token;
|
||||
state = 0i32;
|
||||
end = 0i32;
|
||||
while !(cur_token >= length) {
|
||||
let mut current_block_17: u64;
|
||||
match *message.offset(cur_token as isize) as libc::c_int {
|
||||
32 | 9 | 13 | 10 => {
|
||||
state = 0i32;
|
||||
end = 1i32;
|
||||
current_block_17 = 16924917904204750491;
|
||||
}
|
||||
61 => {
|
||||
state = 1i32;
|
||||
current_block_17 = 16924917904204750491;
|
||||
}
|
||||
63 => {
|
||||
if state == 1i32 {
|
||||
cur_token = cur_token.wrapping_sub(1);
|
||||
end = 1i32
|
||||
}
|
||||
current_block_17 = 10192508258555769664;
|
||||
}
|
||||
_ => {
|
||||
current_block_17 = 10192508258555769664;
|
||||
}
|
||||
}
|
||||
match current_block_17 {
|
||||
10192508258555769664 => state = 0i32,
|
||||
_ => {}
|
||||
}
|
||||
if 0 != end {
|
||||
break;
|
||||
}
|
||||
cur_token = cur_token.wrapping_add(1)
|
||||
}
|
||||
if cur_token.wrapping_sub(begin) == 0i32 as libc::size_t {
|
||||
res = MAILIMF_ERROR_PARSE as libc::c_int
|
||||
} else {
|
||||
text = malloc(
|
||||
cur_token
|
||||
.wrapping_sub(begin)
|
||||
.wrapping_add(1i32 as libc::size_t),
|
||||
) as *mut libc::c_char;
|
||||
if text.is_null() {
|
||||
res = MAILIMF_ERROR_MEMORY as libc::c_int
|
||||
} else {
|
||||
memcpy(
|
||||
text as *mut libc::c_void,
|
||||
message.offset(begin as isize) as *const libc::c_void,
|
||||
cur_token.wrapping_sub(begin),
|
||||
);
|
||||
*text.offset(cur_token.wrapping_sub(begin) as isize) =
|
||||
'\u{0}' as i32 as libc::c_char;
|
||||
*indx = cur_token;
|
||||
*result = text;
|
||||
*p_has_fwd = has_fwd;
|
||||
return MAILIMF_NO_ERROR as libc::c_int;
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_encoded_word_parse(
|
||||
mut message: *const libc::c_char,
|
||||
mut length: size_t,
|
||||
mut indx: *mut size_t,
|
||||
mut result: *mut *mut mailmime_encoded_word,
|
||||
mut p_has_fwd: *mut libc::c_int,
|
||||
mut p_missing_closing_quote: *mut libc::c_int,
|
||||
) -> libc::c_int {
|
||||
let mut current_block: u64;
|
||||
/*
|
||||
Parse the following, when a unicode character encoding is split.
|
||||
=?UTF-8?B?4Lij4Liw4LmA4Lia4Li04LiU4LiE4Lin4Liy4Lih4Lih4Lix4LiZ4Liq4LmM?=
|
||||
=?UTF-8?B?4LmA4LiV4LmH4Lih4Lie4Li04LiB4Lix4LiUIFRSQU5TRk9STUVSUyA0IOC4?=
|
||||
=?UTF-8?B?oeC4seC4meC4quC5jOC4hOC4o+C4muC4l+C4uOC4geC4o+C4sOC4muC4miDg?=
|
||||
=?UTF-8?B?uJfguLXguYjguYDguJTguLXguKLguKfguYPguJnguYDguKHguLfguK3guIfg?=
|
||||
=?UTF-8?B?uYTguJfguKI=?=
|
||||
Expected result:
|
||||
ระเบิดความมันส์เต็มพิกัด TRANSFORMERS 4 มันส์ครบทุกระบบ ที่เดียวในเมืองไทย
|
||||
libetpan result:
|
||||
ระเบิดความมันส์เต็มพิกัด TRANSFORMERS 4 ?ันส์ครบทุกระบบ ??ี่เดียวในเมือง??ทย
|
||||
|
||||
See https://github.com/dinhviethoa/libetpan/pull/211
|
||||
*/
|
||||
let mut cur_token: size_t = 0;
|
||||
let mut charset: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut encoding: libc::c_int = 0;
|
||||
let mut body: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut old_body_len: size_t = 0;
|
||||
let mut text: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut end_encoding: size_t = 0;
|
||||
let mut lookfwd_cur_token: size_t = 0;
|
||||
let mut lookfwd_charset: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut lookfwd_encoding: libc::c_int = 0;
|
||||
let mut copy_len: size_t = 0;
|
||||
let mut decoded_token: size_t = 0;
|
||||
let mut decoded: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut decoded_len: size_t = 0;
|
||||
let mut ew: *mut mailmime_encoded_word = 0 as *mut mailmime_encoded_word;
|
||||
let mut r: libc::c_int = 0;
|
||||
let mut res: libc::c_int = 0;
|
||||
let mut opening_quote: libc::c_int = 0;
|
||||
let mut end: libc::c_int = 0;
|
||||
let mut has_fwd: libc::c_int = 0;
|
||||
let mut missing_closing_quote: libc::c_int = 0;
|
||||
cur_token = *indx;
|
||||
text = 0 as *mut libc::c_char;
|
||||
lookfwd_charset = 0 as *mut libc::c_char;
|
||||
missing_closing_quote = 0i32;
|
||||
has_fwd = 0i32;
|
||||
r = mailimf_fws_parse(message, length, &mut cur_token);
|
||||
if r == MAILIMF_NO_ERROR as libc::c_int {
|
||||
has_fwd = 1i32
|
||||
}
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int && r != MAILIMF_ERROR_PARSE as libc::c_int {
|
||||
res = r
|
||||
} else {
|
||||
opening_quote = 0i32;
|
||||
r = mailimf_char_parse(message, length, &mut cur_token, '\"' as i32 as libc::c_char);
|
||||
if r == MAILIMF_NO_ERROR as libc::c_int {
|
||||
opening_quote = 1i32;
|
||||
current_block = 17788412896529399552;
|
||||
} else if r == MAILIMF_ERROR_PARSE as libc::c_int {
|
||||
current_block = 17788412896529399552;
|
||||
} else {
|
||||
/* do nothing */
|
||||
res = r;
|
||||
current_block = 7995813543095296079;
|
||||
}
|
||||
match current_block {
|
||||
7995813543095296079 => {}
|
||||
_ => {
|
||||
r = mailimf_token_case_insensitive_len_parse(
|
||||
message,
|
||||
length,
|
||||
&mut cur_token,
|
||||
b"=?\x00" as *const u8 as *const libc::c_char as *mut libc::c_char,
|
||||
strlen(b"=?\x00" as *const u8 as *const libc::c_char),
|
||||
);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
res = r
|
||||
} else {
|
||||
r = mailmime_charset_parse(message, length, &mut cur_token, &mut charset);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
res = r
|
||||
} else {
|
||||
r = mailimf_char_parse(
|
||||
message,
|
||||
length,
|
||||
&mut cur_token,
|
||||
'?' as i32 as libc::c_char,
|
||||
);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
res = r
|
||||
} else {
|
||||
r = mailmime_encoding_parse(
|
||||
message,
|
||||
length,
|
||||
&mut cur_token,
|
||||
&mut encoding,
|
||||
);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
res = r
|
||||
} else {
|
||||
r = mailimf_char_parse(
|
||||
message,
|
||||
length,
|
||||
&mut cur_token,
|
||||
'?' as i32 as libc::c_char,
|
||||
);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
res = r
|
||||
} else {
|
||||
lookfwd_cur_token = cur_token;
|
||||
body = 0 as *mut libc::c_char;
|
||||
old_body_len = 0i32 as size_t;
|
||||
loop {
|
||||
let mut has_base64_padding: libc::c_int = 0;
|
||||
end = 0i32;
|
||||
has_base64_padding = 0i32;
|
||||
end_encoding = cur_token;
|
||||
while !(end_encoding >= length) {
|
||||
if end_encoding.wrapping_add(1i32 as libc::size_t)
|
||||
< length
|
||||
{
|
||||
if *message.offset(end_encoding as isize)
|
||||
as libc::c_int
|
||||
== '?' as i32
|
||||
&& *message.offset(
|
||||
end_encoding
|
||||
.wrapping_add(1i32 as libc::size_t)
|
||||
as isize,
|
||||
)
|
||||
as libc::c_int
|
||||
== '=' as i32
|
||||
{
|
||||
end = 1i32
|
||||
}
|
||||
}
|
||||
if 0 != end {
|
||||
break;
|
||||
}
|
||||
end_encoding = end_encoding.wrapping_add(1)
|
||||
}
|
||||
copy_len = end_encoding.wrapping_sub(lookfwd_cur_token);
|
||||
if copy_len > 0i32 as libc::size_t {
|
||||
if encoding == MAILMIME_ENCODING_B as libc::c_int {
|
||||
if end_encoding >= 1i32 as libc::size_t {
|
||||
if *message.offset(
|
||||
end_encoding
|
||||
.wrapping_sub(1i32 as libc::size_t)
|
||||
as isize,
|
||||
)
|
||||
as libc::c_int
|
||||
== '=' as i32
|
||||
{
|
||||
has_base64_padding = 1i32
|
||||
}
|
||||
}
|
||||
}
|
||||
body = realloc(
|
||||
body as *mut libc::c_void,
|
||||
old_body_len
|
||||
.wrapping_add(copy_len)
|
||||
.wrapping_add(1i32 as libc::size_t),
|
||||
)
|
||||
as *mut libc::c_char;
|
||||
if body.is_null() {
|
||||
res = MAILIMF_ERROR_MEMORY as libc::c_int;
|
||||
current_block = 13900684162107791171;
|
||||
break;
|
||||
} else {
|
||||
memcpy(
|
||||
body.offset(old_body_len as isize)
|
||||
as *mut libc::c_void,
|
||||
&*message.offset(cur_token as isize)
|
||||
as *const libc::c_char
|
||||
as *const libc::c_void,
|
||||
copy_len,
|
||||
);
|
||||
*body
|
||||
.offset(old_body_len.wrapping_add(copy_len)
|
||||
as isize) = '\u{0}' as i32 as libc::c_char;
|
||||
old_body_len = (old_body_len as libc::size_t)
|
||||
.wrapping_add(copy_len)
|
||||
as size_t
|
||||
as size_t
|
||||
}
|
||||
}
|
||||
cur_token = end_encoding;
|
||||
r = mailimf_token_case_insensitive_len_parse(
|
||||
message,
|
||||
length,
|
||||
&mut cur_token,
|
||||
b"?=\x00" as *const u8 as *const libc::c_char
|
||||
as *mut libc::c_char,
|
||||
strlen(b"?=\x00" as *const u8 as *const libc::c_char),
|
||||
);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
current_block = 2652804691515851435;
|
||||
break;
|
||||
}
|
||||
if 0 != has_base64_padding {
|
||||
current_block = 2652804691515851435;
|
||||
break;
|
||||
}
|
||||
lookfwd_cur_token = cur_token;
|
||||
r = mailimf_fws_parse(
|
||||
message,
|
||||
length,
|
||||
&mut lookfwd_cur_token,
|
||||
);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int
|
||||
&& r != MAILIMF_ERROR_PARSE as libc::c_int
|
||||
{
|
||||
current_block = 2652804691515851435;
|
||||
break;
|
||||
}
|
||||
r = mailimf_token_case_insensitive_len_parse(
|
||||
message,
|
||||
length,
|
||||
&mut lookfwd_cur_token,
|
||||
b"=?\x00" as *const u8 as *const libc::c_char
|
||||
as *mut libc::c_char,
|
||||
strlen(b"=?\x00" as *const u8 as *const libc::c_char),
|
||||
);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
current_block = 2652804691515851435;
|
||||
break;
|
||||
}
|
||||
r = mailmime_charset_parse(
|
||||
message,
|
||||
length,
|
||||
&mut lookfwd_cur_token,
|
||||
&mut lookfwd_charset,
|
||||
);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
current_block = 2652804691515851435;
|
||||
break;
|
||||
}
|
||||
r = mailimf_char_parse(
|
||||
message,
|
||||
length,
|
||||
&mut lookfwd_cur_token,
|
||||
'?' as i32 as libc::c_char,
|
||||
);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
current_block = 2652804691515851435;
|
||||
break;
|
||||
}
|
||||
r = mailmime_encoding_parse(
|
||||
message,
|
||||
length,
|
||||
&mut lookfwd_cur_token,
|
||||
&mut lookfwd_encoding,
|
||||
);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
current_block = 2652804691515851435;
|
||||
break;
|
||||
}
|
||||
r = mailimf_char_parse(
|
||||
message,
|
||||
length,
|
||||
&mut lookfwd_cur_token,
|
||||
'?' as i32 as libc::c_char,
|
||||
);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
current_block = 2652804691515851435;
|
||||
break;
|
||||
}
|
||||
if strcasecmp(charset, lookfwd_charset) == 0i32
|
||||
&& encoding == lookfwd_encoding
|
||||
{
|
||||
cur_token = lookfwd_cur_token;
|
||||
mailmime_charset_free(lookfwd_charset);
|
||||
lookfwd_charset = 0 as *mut libc::c_char
|
||||
} else {
|
||||
/* the next charset is not matched with the current one,
|
||||
therefore exit the loop to decode the body appended so far */
|
||||
current_block = 2652804691515851435;
|
||||
break;
|
||||
}
|
||||
}
|
||||
match current_block {
|
||||
2652804691515851435 => {
|
||||
if !lookfwd_charset.is_null() {
|
||||
mailmime_charset_free(lookfwd_charset);
|
||||
lookfwd_charset = 0 as *mut libc::c_char
|
||||
}
|
||||
if body.is_null() {
|
||||
body = strdup(
|
||||
b"\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
if body.is_null() {
|
||||
res = MAILIMF_ERROR_MEMORY as libc::c_int;
|
||||
current_block = 13900684162107791171;
|
||||
} else {
|
||||
current_block = 16778110326724371720;
|
||||
}
|
||||
} else {
|
||||
current_block = 16778110326724371720;
|
||||
}
|
||||
match current_block {
|
||||
13900684162107791171 => {}
|
||||
_ => {
|
||||
decoded_token = 0i32 as size_t;
|
||||
decoded_len = 0i32 as size_t;
|
||||
decoded = 0 as *mut libc::c_char;
|
||||
match encoding {
|
||||
0 => {
|
||||
r = mailmime_base64_body_parse(
|
||||
body,
|
||||
strlen(body),
|
||||
&mut decoded_token,
|
||||
&mut decoded,
|
||||
&mut decoded_len,
|
||||
);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int
|
||||
{
|
||||
res = r;
|
||||
current_block =
|
||||
13900684162107791171;
|
||||
} else {
|
||||
current_block = 7337917895049117968;
|
||||
}
|
||||
}
|
||||
1 => {
|
||||
r =
|
||||
mailmime_quoted_printable_body_parse(body,
|
||||
strlen(body),
|
||||
&mut decoded_token,
|
||||
&mut decoded,
|
||||
&mut decoded_len,
|
||||
1i32);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int
|
||||
{
|
||||
res = r;
|
||||
current_block =
|
||||
13900684162107791171;
|
||||
} else {
|
||||
current_block = 7337917895049117968;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
current_block = 7337917895049117968;
|
||||
}
|
||||
}
|
||||
match current_block {
|
||||
13900684162107791171 => {}
|
||||
_ => {
|
||||
text =
|
||||
malloc(decoded_len.wrapping_add(
|
||||
1i32 as libc::size_t,
|
||||
))
|
||||
as *mut libc::c_char;
|
||||
if text.is_null() {
|
||||
res = MAILIMF_ERROR_MEMORY
|
||||
as libc::c_int
|
||||
} else {
|
||||
if decoded_len
|
||||
> 0i32 as libc::size_t
|
||||
{
|
||||
memcpy(
|
||||
text as *mut libc::c_void,
|
||||
decoded
|
||||
as *const libc::c_void,
|
||||
decoded_len,
|
||||
);
|
||||
}
|
||||
*text
|
||||
.offset(decoded_len as isize) =
|
||||
'\u{0}' as i32 as libc::c_char;
|
||||
if 0 != opening_quote {
|
||||
r = mailimf_char_parse(
|
||||
message,
|
||||
length,
|
||||
&mut cur_token,
|
||||
'\"' as i32 as libc::c_char,
|
||||
);
|
||||
if r == MAILIMF_ERROR_PARSE
|
||||
as libc::c_int
|
||||
{
|
||||
missing_closing_quote = 1i32
|
||||
}
|
||||
}
|
||||
if strcasecmp(
|
||||
charset,
|
||||
b"utf8\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
) == 0i32
|
||||
{
|
||||
free(
|
||||
charset
|
||||
as *mut libc::c_void,
|
||||
);
|
||||
charset = strdup(
|
||||
b"utf-8\x00" as *const u8
|
||||
as *const libc::c_char,
|
||||
)
|
||||
}
|
||||
ew = mailmime_encoded_word_new(
|
||||
charset, text,
|
||||
);
|
||||
if ew.is_null() {
|
||||
res = MAILIMF_ERROR_MEMORY
|
||||
as libc::c_int
|
||||
} else {
|
||||
*result = ew;
|
||||
*indx = cur_token;
|
||||
*p_has_fwd = has_fwd;
|
||||
*p_missing_closing_quote =
|
||||
missing_closing_quote;
|
||||
mailmime_decoded_part_free(
|
||||
decoded,
|
||||
);
|
||||
free(body as *mut libc::c_void);
|
||||
return MAILIMF_NO_ERROR
|
||||
as libc::c_int;
|
||||
}
|
||||
}
|
||||
mailmime_decoded_part_free(decoded);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
free(body as *mut libc::c_void);
|
||||
mailmime_encoded_text_free(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
mailmime_charset_free(charset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
unsafe fn mailmime_encoding_parse(
|
||||
mut message: *const libc::c_char,
|
||||
mut length: size_t,
|
||||
mut indx: *mut size_t,
|
||||
mut result: *mut libc::c_int,
|
||||
) -> libc::c_int {
|
||||
let mut cur_token: size_t = 0;
|
||||
let mut encoding: libc::c_int = 0;
|
||||
cur_token = *indx;
|
||||
if cur_token >= length {
|
||||
return MAILIMF_ERROR_PARSE as libc::c_int;
|
||||
}
|
||||
match toupper(*message.offset(cur_token as isize) as libc::c_uchar as libc::c_int)
|
||||
as libc::c_char as libc::c_int
|
||||
{
|
||||
81 => encoding = MAILMIME_ENCODING_Q as libc::c_int,
|
||||
66 => encoding = MAILMIME_ENCODING_B as libc::c_int,
|
||||
_ => return MAILIMF_ERROR_INVAL as libc::c_int,
|
||||
}
|
||||
cur_token = cur_token.wrapping_add(1);
|
||||
*result = encoding;
|
||||
*indx = cur_token;
|
||||
return MAILIMF_NO_ERROR as libc::c_int;
|
||||
}
|
||||
|
||||
/*
|
||||
* libEtPan! -- a mail stuff library
|
||||
*
|
||||
* Copyright (C) 2001, 2005 - DINH Viet Hoa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the libEtPan! project nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
/*
|
||||
* $Id: mailmime_decode.c,v 1.37 2010/11/16 20:52:28 hoa Exp $
|
||||
*/
|
||||
/*
|
||||
RFC 2047 : MIME (Multipurpose Internet Mail Extensions) Part Three:
|
||||
Message Header Extensions for Non-ASCII Text
|
||||
*/
|
||||
unsafe fn mailmime_charset_parse(
|
||||
mut message: *const libc::c_char,
|
||||
mut length: size_t,
|
||||
mut indx: *mut size_t,
|
||||
mut charset: *mut *mut libc::c_char,
|
||||
) -> libc::c_int {
|
||||
return mailmime_etoken_parse(message, length, indx, charset);
|
||||
}
|
||||
unsafe fn mailmime_etoken_parse(
|
||||
mut message: *const libc::c_char,
|
||||
mut length: size_t,
|
||||
mut indx: *mut size_t,
|
||||
mut result: *mut *mut libc::c_char,
|
||||
) -> libc::c_int {
|
||||
return mailimf_custom_string_parse(message, length, indx, result, Some(is_etoken_char));
|
||||
}
|
||||
|
||||
unsafe fn is_etoken_char(mut ch: libc::c_char) -> libc::c_int {
|
||||
let mut uch: libc::c_uchar = ch as libc::c_uchar;
|
||||
if (uch as libc::c_int) < 31i32 {
|
||||
return 0i32;
|
||||
}
|
||||
match uch as libc::c_int {
|
||||
32 | 40 | 41 | 60 | 62 | 64 | 44 | 59 | 58 | 34 | 47 | 91 | 93 | 63 | 61 => return 0i32,
|
||||
_ => {}
|
||||
}
|
||||
return 1i32;
|
||||
}
|
||||
@@ -1,583 +0,0 @@
|
||||
use libc::{self, toupper};
|
||||
|
||||
use crate::clist::*;
|
||||
use crate::mailimf::*;
|
||||
use crate::mailmime::types::*;
|
||||
use crate::mailmime::*;
|
||||
use crate::other::*;
|
||||
|
||||
pub const MAILMIME_DISPOSITION_TYPE_EXTENSION: libc::c_uint = 3;
|
||||
pub const MAILMIME_DISPOSITION_TYPE_ATTACHMENT: libc::c_uint = 2;
|
||||
pub const MAILMIME_DISPOSITION_TYPE_INLINE: libc::c_uint = 1;
|
||||
pub const MAILMIME_DISPOSITION_TYPE_ERROR: libc::c_uint = 0;
|
||||
|
||||
pub unsafe fn mailmime_disposition_parse(
|
||||
mut message: *const libc::c_char,
|
||||
mut length: size_t,
|
||||
mut indx: *mut size_t,
|
||||
mut result: *mut *mut mailmime_disposition,
|
||||
) -> libc::c_int {
|
||||
let mut current_block: u64;
|
||||
let mut final_token: size_t = 0;
|
||||
let mut cur_token: size_t = 0;
|
||||
let mut dsp_type: *mut mailmime_disposition_type = 0 as *mut mailmime_disposition_type;
|
||||
let mut list: *mut clist = 0 as *mut clist;
|
||||
let mut dsp: *mut mailmime_disposition = 0 as *mut mailmime_disposition;
|
||||
let mut r: libc::c_int = 0;
|
||||
let mut res: libc::c_int = 0;
|
||||
cur_token = *indx;
|
||||
r = mailmime_disposition_type_parse(message, length, &mut cur_token, &mut dsp_type);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
res = r
|
||||
} else {
|
||||
list = clist_new();
|
||||
if list.is_null() {
|
||||
res = MAILIMF_ERROR_MEMORY as libc::c_int
|
||||
} else {
|
||||
loop {
|
||||
let mut param: *mut mailmime_disposition_parm = 0 as *mut mailmime_disposition_parm;
|
||||
final_token = cur_token;
|
||||
r = mailimf_unstrict_char_parse(
|
||||
message,
|
||||
length,
|
||||
&mut cur_token,
|
||||
';' as i32 as libc::c_char,
|
||||
);
|
||||
if r == MAILIMF_NO_ERROR as libc::c_int {
|
||||
param = 0 as *mut mailmime_disposition_parm;
|
||||
r = mailmime_disposition_parm_parse(
|
||||
message,
|
||||
length,
|
||||
&mut cur_token,
|
||||
&mut param,
|
||||
);
|
||||
if r == MAILIMF_NO_ERROR as libc::c_int {
|
||||
r = clist_insert_after(list, (*list).last, param as *mut libc::c_void);
|
||||
if !(r < 0i32) {
|
||||
continue;
|
||||
}
|
||||
res = MAILIMF_ERROR_MEMORY as libc::c_int;
|
||||
current_block = 18290070879695007868;
|
||||
break;
|
||||
} else if r == MAILIMF_ERROR_PARSE as libc::c_int {
|
||||
cur_token = final_token;
|
||||
current_block = 652864300344834934;
|
||||
break;
|
||||
} else {
|
||||
res = r;
|
||||
current_block = 18290070879695007868;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* do nothing */
|
||||
if r == MAILIMF_ERROR_PARSE as libc::c_int {
|
||||
current_block = 652864300344834934;
|
||||
break;
|
||||
}
|
||||
res = r;
|
||||
current_block = 18290070879695007868;
|
||||
break;
|
||||
}
|
||||
}
|
||||
match current_block {
|
||||
652864300344834934 => {
|
||||
dsp = mailmime_disposition_new(dsp_type, list);
|
||||
if dsp.is_null() {
|
||||
res = MAILIMF_ERROR_MEMORY as libc::c_int
|
||||
} else {
|
||||
*result = dsp;
|
||||
*indx = cur_token;
|
||||
return MAILIMF_NO_ERROR as libc::c_int;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
clist_foreach(
|
||||
list,
|
||||
::std::mem::transmute::<
|
||||
Option<unsafe fn(_: *mut mailmime_disposition_parm) -> ()>,
|
||||
clist_func,
|
||||
>(Some(mailmime_disposition_parm_free)),
|
||||
0 as *mut libc::c_void,
|
||||
);
|
||||
clist_free(list);
|
||||
}
|
||||
mailmime_disposition_type_free(dsp_type);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
/*
|
||||
* libEtPan! -- a mail stuff library
|
||||
*
|
||||
* Copyright (C) 2001, 2005 - DINH Viet Hoa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the libEtPan! project nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
/*
|
||||
* $Id: mailmime_disposition.c,v 1.17 2011/05/03 16:30:22 hoa Exp $
|
||||
*/
|
||||
unsafe fn mailmime_disposition_parm_parse(
|
||||
mut message: *const libc::c_char,
|
||||
mut length: size_t,
|
||||
mut indx: *mut size_t,
|
||||
mut result: *mut *mut mailmime_disposition_parm,
|
||||
) -> libc::c_int {
|
||||
let mut current_block: u64;
|
||||
let mut filename: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut creation_date: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut modification_date: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut read_date: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut size: size_t = 0;
|
||||
let mut parameter: *mut mailmime_parameter = 0 as *mut mailmime_parameter;
|
||||
let mut cur_token: size_t = 0;
|
||||
let mut dsp_parm: *mut mailmime_disposition_parm = 0 as *mut mailmime_disposition_parm;
|
||||
let mut type_0: libc::c_int = 0;
|
||||
let mut guessed_type: libc::c_int = 0;
|
||||
let mut r: libc::c_int = 0;
|
||||
let mut res: libc::c_int = 0;
|
||||
cur_token = *indx;
|
||||
filename = 0 as *mut libc::c_char;
|
||||
creation_date = 0 as *mut libc::c_char;
|
||||
modification_date = 0 as *mut libc::c_char;
|
||||
read_date = 0 as *mut libc::c_char;
|
||||
size = 0i32 as size_t;
|
||||
parameter = 0 as *mut mailmime_parameter;
|
||||
r = mailimf_cfws_parse(message, length, &mut cur_token);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int && r != MAILIMF_ERROR_PARSE as libc::c_int {
|
||||
res = r
|
||||
} else {
|
||||
guessed_type = mailmime_disposition_guess_type(message, length, cur_token);
|
||||
type_0 = MAILMIME_DISPOSITION_PARM_PARAMETER as libc::c_int;
|
||||
match guessed_type {
|
||||
0 => {
|
||||
r = mailmime_filename_parm_parse(message, length, &mut cur_token, &mut filename);
|
||||
if r == MAILIMF_NO_ERROR as libc::c_int {
|
||||
type_0 = guessed_type;
|
||||
current_block = 13826291924415791078;
|
||||
} else if r == MAILIMF_ERROR_PARSE as libc::c_int {
|
||||
current_block = 13826291924415791078;
|
||||
} else {
|
||||
/* do nothing */
|
||||
res = r;
|
||||
current_block = 9120900589700563584;
|
||||
}
|
||||
}
|
||||
1 => {
|
||||
r = mailmime_creation_date_parm_parse(
|
||||
message,
|
||||
length,
|
||||
&mut cur_token,
|
||||
&mut creation_date,
|
||||
);
|
||||
if r == MAILIMF_NO_ERROR as libc::c_int {
|
||||
type_0 = guessed_type;
|
||||
current_block = 13826291924415791078;
|
||||
} else if r == MAILIMF_ERROR_PARSE as libc::c_int {
|
||||
current_block = 13826291924415791078;
|
||||
} else {
|
||||
/* do nothing */
|
||||
res = r;
|
||||
current_block = 9120900589700563584;
|
||||
}
|
||||
}
|
||||
2 => {
|
||||
r = mailmime_modification_date_parm_parse(
|
||||
message,
|
||||
length,
|
||||
&mut cur_token,
|
||||
&mut modification_date,
|
||||
);
|
||||
if r == MAILIMF_NO_ERROR as libc::c_int {
|
||||
type_0 = guessed_type;
|
||||
current_block = 13826291924415791078;
|
||||
} else if r == MAILIMF_ERROR_PARSE as libc::c_int {
|
||||
current_block = 13826291924415791078;
|
||||
} else {
|
||||
/* do nothing */
|
||||
res = r;
|
||||
current_block = 9120900589700563584;
|
||||
}
|
||||
}
|
||||
3 => {
|
||||
r = mailmime_read_date_parm_parse(message, length, &mut cur_token, &mut read_date);
|
||||
if r == MAILIMF_NO_ERROR as libc::c_int {
|
||||
type_0 = guessed_type;
|
||||
current_block = 13826291924415791078;
|
||||
} else if r == MAILIMF_ERROR_PARSE as libc::c_int {
|
||||
current_block = 13826291924415791078;
|
||||
} else {
|
||||
/* do nothing */
|
||||
res = r;
|
||||
current_block = 9120900589700563584;
|
||||
}
|
||||
}
|
||||
4 => {
|
||||
r = mailmime_size_parm_parse(message, length, &mut cur_token, &mut size);
|
||||
if r == MAILIMF_NO_ERROR as libc::c_int {
|
||||
type_0 = guessed_type;
|
||||
current_block = 13826291924415791078;
|
||||
} else if r == MAILIMF_ERROR_PARSE as libc::c_int {
|
||||
current_block = 13826291924415791078;
|
||||
} else {
|
||||
/* do nothing */
|
||||
res = r;
|
||||
current_block = 9120900589700563584;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
current_block = 13826291924415791078;
|
||||
}
|
||||
}
|
||||
match current_block {
|
||||
9120900589700563584 => {}
|
||||
_ => {
|
||||
if type_0 == MAILMIME_DISPOSITION_PARM_PARAMETER as libc::c_int {
|
||||
r = mailmime_parameter_parse(message, length, &mut cur_token, &mut parameter);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
type_0 = guessed_type;
|
||||
res = r;
|
||||
current_block = 9120900589700563584;
|
||||
} else {
|
||||
current_block = 6721012065216013753;
|
||||
}
|
||||
} else {
|
||||
current_block = 6721012065216013753;
|
||||
}
|
||||
match current_block {
|
||||
9120900589700563584 => {}
|
||||
_ => {
|
||||
dsp_parm = mailmime_disposition_parm_new(
|
||||
type_0,
|
||||
filename,
|
||||
creation_date,
|
||||
modification_date,
|
||||
read_date,
|
||||
size,
|
||||
parameter,
|
||||
);
|
||||
if dsp_parm.is_null() {
|
||||
res = MAILIMF_ERROR_MEMORY as libc::c_int;
|
||||
if !filename.is_null() {
|
||||
mailmime_filename_parm_free(filename);
|
||||
}
|
||||
if !creation_date.is_null() {
|
||||
mailmime_creation_date_parm_free(creation_date);
|
||||
}
|
||||
if !modification_date.is_null() {
|
||||
mailmime_modification_date_parm_free(modification_date);
|
||||
}
|
||||
if !read_date.is_null() {
|
||||
mailmime_read_date_parm_free(read_date);
|
||||
}
|
||||
if !parameter.is_null() {
|
||||
mailmime_parameter_free(parameter);
|
||||
}
|
||||
} else {
|
||||
*result = dsp_parm;
|
||||
*indx = cur_token;
|
||||
return MAILIMF_NO_ERROR as libc::c_int;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
unsafe fn mailmime_size_parm_parse(
|
||||
mut message: *const libc::c_char,
|
||||
mut length: size_t,
|
||||
mut indx: *mut size_t,
|
||||
mut result: *mut size_t,
|
||||
) -> libc::c_int {
|
||||
let mut value: uint32_t = 0;
|
||||
let mut cur_token: size_t = 0;
|
||||
let mut r: libc::c_int = 0;
|
||||
cur_token = *indx;
|
||||
r = mailimf_token_case_insensitive_len_parse(
|
||||
message,
|
||||
length,
|
||||
&mut cur_token,
|
||||
b"size\x00" as *const u8 as *const libc::c_char as *mut libc::c_char,
|
||||
strlen(b"size\x00" as *const u8 as *const libc::c_char),
|
||||
);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
return r;
|
||||
}
|
||||
r = mailimf_unstrict_char_parse(message, length, &mut cur_token, '=' as i32 as libc::c_char);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
return r;
|
||||
}
|
||||
r = mailimf_cfws_parse(message, length, &mut cur_token);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int && r != MAILIMF_ERROR_PARSE as libc::c_int {
|
||||
return r;
|
||||
}
|
||||
r = mailimf_number_parse(message, length, &mut cur_token, &mut value);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
return r;
|
||||
}
|
||||
*indx = cur_token;
|
||||
*result = value as size_t;
|
||||
return MAILIMF_NO_ERROR as libc::c_int;
|
||||
}
|
||||
unsafe fn mailmime_read_date_parm_parse(
|
||||
mut message: *const libc::c_char,
|
||||
mut length: size_t,
|
||||
mut indx: *mut size_t,
|
||||
mut result: *mut *mut libc::c_char,
|
||||
) -> libc::c_int {
|
||||
let mut value: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut cur_token: size_t = 0;
|
||||
let mut r: libc::c_int = 0;
|
||||
cur_token = *indx;
|
||||
r = mailimf_token_case_insensitive_len_parse(
|
||||
message,
|
||||
length,
|
||||
&mut cur_token,
|
||||
b"read-date\x00" as *const u8 as *const libc::c_char as *mut libc::c_char,
|
||||
strlen(b"read-date\x00" as *const u8 as *const libc::c_char),
|
||||
);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
return r;
|
||||
}
|
||||
r = mailimf_unstrict_char_parse(message, length, &mut cur_token, '=' as i32 as libc::c_char);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
return r;
|
||||
}
|
||||
r = mailimf_cfws_parse(message, length, &mut cur_token);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int && r != MAILIMF_ERROR_PARSE as libc::c_int {
|
||||
return r;
|
||||
}
|
||||
r = mailmime_quoted_date_time_parse(message, length, &mut cur_token, &mut value);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
return r;
|
||||
}
|
||||
*indx = cur_token;
|
||||
*result = value;
|
||||
return MAILIMF_NO_ERROR as libc::c_int;
|
||||
}
|
||||
unsafe fn mailmime_quoted_date_time_parse(
|
||||
mut message: *const libc::c_char,
|
||||
mut length: size_t,
|
||||
mut indx: *mut size_t,
|
||||
mut result: *mut *mut libc::c_char,
|
||||
) -> libc::c_int {
|
||||
return mailimf_quoted_string_parse(message, length, indx, result);
|
||||
}
|
||||
unsafe fn mailmime_modification_date_parm_parse(
|
||||
mut message: *const libc::c_char,
|
||||
mut length: size_t,
|
||||
mut indx: *mut size_t,
|
||||
mut result: *mut *mut libc::c_char,
|
||||
) -> libc::c_int {
|
||||
let mut value: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut cur_token: size_t = 0;
|
||||
let mut r: libc::c_int = 0;
|
||||
cur_token = *indx;
|
||||
r = mailimf_token_case_insensitive_len_parse(
|
||||
message,
|
||||
length,
|
||||
&mut cur_token,
|
||||
b"modification-date\x00" as *const u8 as *const libc::c_char as *mut libc::c_char,
|
||||
strlen(b"modification-date\x00" as *const u8 as *const libc::c_char),
|
||||
);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
return r;
|
||||
}
|
||||
r = mailimf_unstrict_char_parse(message, length, &mut cur_token, '=' as i32 as libc::c_char);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
return r;
|
||||
}
|
||||
r = mailimf_cfws_parse(message, length, &mut cur_token);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int && r != MAILIMF_ERROR_PARSE as libc::c_int {
|
||||
return r;
|
||||
}
|
||||
r = mailmime_quoted_date_time_parse(message, length, &mut cur_token, &mut value);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
return r;
|
||||
}
|
||||
*indx = cur_token;
|
||||
*result = value;
|
||||
return MAILIMF_NO_ERROR as libc::c_int;
|
||||
}
|
||||
unsafe fn mailmime_creation_date_parm_parse(
|
||||
mut message: *const libc::c_char,
|
||||
mut length: size_t,
|
||||
mut indx: *mut size_t,
|
||||
mut result: *mut *mut libc::c_char,
|
||||
) -> libc::c_int {
|
||||
let mut value: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut r: libc::c_int = 0;
|
||||
let mut cur_token: size_t = 0;
|
||||
cur_token = *indx;
|
||||
r = mailimf_token_case_insensitive_len_parse(
|
||||
message,
|
||||
length,
|
||||
&mut cur_token,
|
||||
b"creation-date\x00" as *const u8 as *const libc::c_char as *mut libc::c_char,
|
||||
strlen(b"creation-date\x00" as *const u8 as *const libc::c_char),
|
||||
);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
return r;
|
||||
}
|
||||
r = mailimf_unstrict_char_parse(message, length, &mut cur_token, '=' as i32 as libc::c_char);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
return r;
|
||||
}
|
||||
r = mailimf_cfws_parse(message, length, &mut cur_token);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int && r != MAILIMF_ERROR_PARSE as libc::c_int {
|
||||
return r;
|
||||
}
|
||||
r = mailmime_quoted_date_time_parse(message, length, &mut cur_token, &mut value);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
return r;
|
||||
}
|
||||
*indx = cur_token;
|
||||
*result = value;
|
||||
return MAILIMF_NO_ERROR as libc::c_int;
|
||||
}
|
||||
unsafe fn mailmime_filename_parm_parse(
|
||||
mut message: *const libc::c_char,
|
||||
mut length: size_t,
|
||||
mut indx: *mut size_t,
|
||||
mut result: *mut *mut libc::c_char,
|
||||
) -> libc::c_int {
|
||||
let mut value: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut r: libc::c_int = 0;
|
||||
let mut cur_token: size_t = 0;
|
||||
cur_token = *indx;
|
||||
r = mailimf_token_case_insensitive_len_parse(
|
||||
message,
|
||||
length,
|
||||
&mut cur_token,
|
||||
b"filename\x00" as *const u8 as *const libc::c_char as *mut libc::c_char,
|
||||
strlen(b"filename\x00" as *const u8 as *const libc::c_char),
|
||||
);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
return r;
|
||||
}
|
||||
r = mailimf_unstrict_char_parse(message, length, &mut cur_token, '=' as i32 as libc::c_char);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
return r;
|
||||
}
|
||||
r = mailimf_cfws_parse(message, length, &mut cur_token);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int && r != MAILIMF_ERROR_PARSE as libc::c_int {
|
||||
return r;
|
||||
}
|
||||
r = mailmime_value_parse(message, length, &mut cur_token, &mut value);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
return r;
|
||||
}
|
||||
*indx = cur_token;
|
||||
*result = value;
|
||||
return MAILIMF_NO_ERROR as libc::c_int;
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_disposition_guess_type(
|
||||
mut message: *const libc::c_char,
|
||||
mut length: size_t,
|
||||
mut indx: size_t,
|
||||
) -> libc::c_int {
|
||||
if indx >= length {
|
||||
return MAILMIME_DISPOSITION_PARM_PARAMETER as libc::c_int;
|
||||
}
|
||||
match toupper(*message.offset(indx as isize) as libc::c_uchar as libc::c_int) as libc::c_char
|
||||
as libc::c_int
|
||||
{
|
||||
70 => return MAILMIME_DISPOSITION_PARM_FILENAME as libc::c_int,
|
||||
67 => return MAILMIME_DISPOSITION_PARM_CREATION_DATE as libc::c_int,
|
||||
77 => return MAILMIME_DISPOSITION_PARM_MODIFICATION_DATE as libc::c_int,
|
||||
82 => return MAILMIME_DISPOSITION_PARM_READ_DATE as libc::c_int,
|
||||
83 => return MAILMIME_DISPOSITION_PARM_SIZE as libc::c_int,
|
||||
_ => return MAILMIME_DISPOSITION_PARM_PARAMETER as libc::c_int,
|
||||
};
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_disposition_type_parse(
|
||||
mut message: *const libc::c_char,
|
||||
mut length: size_t,
|
||||
mut indx: *mut size_t,
|
||||
mut result: *mut *mut mailmime_disposition_type,
|
||||
) -> libc::c_int {
|
||||
let mut cur_token: size_t = 0;
|
||||
let mut type_0: libc::c_int = 0;
|
||||
let mut extension: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut dsp_type: *mut mailmime_disposition_type = 0 as *mut mailmime_disposition_type;
|
||||
let mut r: libc::c_int = 0;
|
||||
let mut res: libc::c_int = 0;
|
||||
cur_token = *indx;
|
||||
r = mailimf_cfws_parse(message, length, &mut cur_token);
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int && r != MAILIMF_ERROR_PARSE as libc::c_int {
|
||||
res = r
|
||||
} else {
|
||||
type_0 = MAILMIME_DISPOSITION_TYPE_ERROR as libc::c_int;
|
||||
extension = 0 as *mut libc::c_char;
|
||||
r = mailimf_token_case_insensitive_len_parse(
|
||||
message,
|
||||
length,
|
||||
&mut cur_token,
|
||||
b"inline\x00" as *const u8 as *const libc::c_char as *mut libc::c_char,
|
||||
strlen(b"inline\x00" as *const u8 as *const libc::c_char),
|
||||
);
|
||||
if r == MAILIMF_NO_ERROR as libc::c_int {
|
||||
type_0 = MAILMIME_DISPOSITION_TYPE_INLINE as libc::c_int
|
||||
}
|
||||
if r == MAILIMF_ERROR_PARSE as libc::c_int {
|
||||
r = mailimf_token_case_insensitive_len_parse(
|
||||
message,
|
||||
length,
|
||||
&mut cur_token,
|
||||
b"attachment\x00" as *const u8 as *const libc::c_char as *mut libc::c_char,
|
||||
strlen(b"attachment\x00" as *const u8 as *const libc::c_char),
|
||||
);
|
||||
if r == MAILIMF_NO_ERROR as libc::c_int {
|
||||
type_0 = MAILMIME_DISPOSITION_TYPE_ATTACHMENT as libc::c_int
|
||||
}
|
||||
}
|
||||
if r == MAILIMF_ERROR_PARSE as libc::c_int {
|
||||
r = mailmime_extension_token_parse(message, length, &mut cur_token, &mut extension);
|
||||
if r == MAILIMF_NO_ERROR as libc::c_int {
|
||||
type_0 = MAILMIME_DISPOSITION_TYPE_EXTENSION as libc::c_int
|
||||
}
|
||||
}
|
||||
if r != MAILIMF_NO_ERROR as libc::c_int {
|
||||
res = r
|
||||
} else {
|
||||
dsp_type = mailmime_disposition_type_new(type_0, extension);
|
||||
if dsp_type.is_null() {
|
||||
res = MAILIMF_ERROR_MEMORY as libc::c_int;
|
||||
if !extension.is_null() {
|
||||
free(extension as *mut libc::c_void);
|
||||
}
|
||||
} else {
|
||||
*result = dsp_type;
|
||||
*indx = cur_token;
|
||||
return MAILIMF_NO_ERROR as libc::c_int;
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,891 +0,0 @@
|
||||
use crate::clist::*;
|
||||
use crate::mailimf::types::*;
|
||||
use crate::mmapstring::*;
|
||||
use crate::other::*;
|
||||
|
||||
pub const MAILMIME_MECHANISM_TOKEN: libc::c_uint = 6;
|
||||
pub const MAILMIME_MECHANISM_BASE64: libc::c_uint = 5;
|
||||
pub const MAILMIME_MECHANISM_QUOTED_PRINTABLE: libc::c_uint = 4;
|
||||
pub const MAILMIME_MECHANISM_BINARY: libc::c_uint = 3;
|
||||
pub const MAILMIME_MECHANISM_8BIT: libc::c_uint = 2;
|
||||
pub const MAILMIME_MECHANISM_7BIT: libc::c_uint = 1;
|
||||
pub const MAILMIME_MECHANISM_ERROR: libc::c_uint = 0;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct mailmime_composite_type {
|
||||
pub ct_type: libc::c_int,
|
||||
pub ct_token: *mut libc::c_char,
|
||||
}
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct mailmime_content {
|
||||
pub ct_type: *mut mailmime_type,
|
||||
pub ct_subtype: *mut libc::c_char,
|
||||
pub ct_parameters: *mut clist,
|
||||
}
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct mailmime_type {
|
||||
pub tp_type: libc::c_int,
|
||||
pub tp_data: unnamed,
|
||||
}
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub union unnamed {
|
||||
pub tp_discrete_type: *mut mailmime_discrete_type,
|
||||
pub tp_composite_type: *mut mailmime_composite_type,
|
||||
}
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct mailmime_discrete_type {
|
||||
pub dt_type: libc::c_int,
|
||||
pub dt_extension: *mut libc::c_char,
|
||||
}
|
||||
pub type unnamed_0 = libc::c_uint;
|
||||
pub const MAILMIME_FIELD_LOCATION: unnamed_0 = 8;
|
||||
pub const MAILMIME_FIELD_LANGUAGE: unnamed_0 = 7;
|
||||
pub const MAILMIME_FIELD_DISPOSITION: unnamed_0 = 6;
|
||||
pub const MAILMIME_FIELD_VERSION: unnamed_0 = 5;
|
||||
pub const MAILMIME_FIELD_DESCRIPTION: unnamed_0 = 4;
|
||||
pub const MAILMIME_FIELD_ID: unnamed_0 = 3;
|
||||
pub const MAILMIME_FIELD_TRANSFER_ENCODING: unnamed_0 = 2;
|
||||
pub const MAILMIME_FIELD_TYPE: unnamed_0 = 1;
|
||||
pub const MAILMIME_FIELD_NONE: unnamed_0 = 0;
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct mailmime_field {
|
||||
pub fld_type: libc::c_int,
|
||||
pub fld_data: unnamed_1,
|
||||
}
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub union unnamed_1 {
|
||||
pub fld_content: *mut mailmime_content,
|
||||
pub fld_encoding: *mut mailmime_mechanism,
|
||||
pub fld_id: *mut libc::c_char,
|
||||
pub fld_description: *mut libc::c_char,
|
||||
pub fld_version: uint32_t,
|
||||
pub fld_disposition: *mut mailmime_disposition,
|
||||
pub fld_language: *mut mailmime_language,
|
||||
pub fld_location: *mut libc::c_char,
|
||||
}
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct mailmime_language {
|
||||
pub lg_list: *mut clist,
|
||||
}
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct mailmime_disposition {
|
||||
pub dsp_type: *mut mailmime_disposition_type,
|
||||
pub dsp_parms: *mut clist,
|
||||
}
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct mailmime_disposition_type {
|
||||
pub dsp_type: libc::c_int,
|
||||
pub dsp_extension: *mut libc::c_char,
|
||||
}
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct mailmime_mechanism {
|
||||
pub enc_type: libc::c_int,
|
||||
pub enc_token: *mut libc::c_char,
|
||||
}
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct mailmime_fields {
|
||||
pub fld_list: *mut clist,
|
||||
}
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct mailmime_parameter {
|
||||
pub pa_name: *mut libc::c_char,
|
||||
pub pa_value: *mut libc::c_char,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct mailmime_disposition_parm {
|
||||
pub pa_type: libc::c_int,
|
||||
pub pa_data: unnamed_3,
|
||||
}
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub union unnamed_3 {
|
||||
pub pa_filename: *mut libc::c_char,
|
||||
pub pa_creation_date: *mut libc::c_char,
|
||||
pub pa_modification_date: *mut libc::c_char,
|
||||
pub pa_read_date: *mut libc::c_char,
|
||||
pub pa_size: size_t,
|
||||
pub pa_parameter: *mut mailmime_parameter,
|
||||
}
|
||||
pub const MAILMIME_DISPOSITION_PARM_PARAMETER: unnamed_11 = 5;
|
||||
pub const MAILMIME_DISPOSITION_PARM_READ_DATE: unnamed_11 = 3;
|
||||
pub const MAILMIME_DISPOSITION_PARM_MODIFICATION_DATE: unnamed_11 = 2;
|
||||
pub const MAILMIME_DISPOSITION_PARM_CREATION_DATE: unnamed_11 = 1;
|
||||
pub const MAILMIME_DISPOSITION_PARM_FILENAME: unnamed_11 = 0;
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct mailmime_multipart_body {
|
||||
pub bd_list: *mut clist,
|
||||
}
|
||||
pub type unnamed_4 = libc::c_uint;
|
||||
pub const MAILMIME_DATA_FILE: unnamed_4 = 1;
|
||||
pub const MAILMIME_DATA_TEXT: unnamed_4 = 0;
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct mailmime_data {
|
||||
pub dt_type: libc::c_int,
|
||||
pub dt_encoding: libc::c_int,
|
||||
pub dt_encoded: libc::c_int,
|
||||
pub dt_data: unnamed_5,
|
||||
}
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub union unnamed_5 {
|
||||
pub dt_text: unnamed_6,
|
||||
pub dt_filename: *mut libc::c_char,
|
||||
}
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct unnamed_6 {
|
||||
pub dt_data: *const libc::c_char,
|
||||
pub dt_length: size_t,
|
||||
}
|
||||
pub type unnamed_7 = libc::c_uint;
|
||||
pub const MAILMIME_MESSAGE: unnamed_7 = 3;
|
||||
pub const MAILMIME_MULTIPLE: unnamed_7 = 2;
|
||||
pub const MAILMIME_SINGLE: unnamed_7 = 1;
|
||||
pub const MAILMIME_NONE: unnamed_7 = 0;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct Mailmime {
|
||||
pub mm_parent_type: libc::c_int,
|
||||
pub mm_parent: *mut Mailmime,
|
||||
pub mm_multipart_pos: *mut clistiter,
|
||||
pub mm_type: libc::c_int,
|
||||
pub mm_mime_start: *const libc::c_char,
|
||||
pub mm_length: size_t,
|
||||
pub mm_mime_fields: *mut mailmime_fields,
|
||||
pub mm_content_type: *mut mailmime_content,
|
||||
pub mm_body: *mut mailmime_data,
|
||||
pub mm_data: unnamed_8,
|
||||
}
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub union unnamed_8 {
|
||||
pub mm_single: *mut mailmime_data,
|
||||
pub mm_multipart: unnamed_10,
|
||||
pub mm_message: unnamed_9,
|
||||
}
|
||||
/* message */
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct unnamed_9 {
|
||||
pub mm_fields: *mut mailimf_fields,
|
||||
pub mm_msg_mime: *mut Mailmime,
|
||||
}
|
||||
/* multi-part */
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct unnamed_10 {
|
||||
pub mm_preamble: *mut mailmime_data,
|
||||
pub mm_epilogue: *mut mailmime_data,
|
||||
pub mm_mp_list: *mut clist,
|
||||
}
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct mailmime_encoded_word {
|
||||
pub wd_charset: *mut libc::c_char,
|
||||
pub wd_text: *mut libc::c_char,
|
||||
}
|
||||
pub type unnamed_11 = libc::c_uint;
|
||||
pub const MAILMIME_DISPOSITION_PARM_SIZE: unnamed_11 = 4;
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct mailmime_section {
|
||||
pub sec_list: *mut clist,
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_attribute_free(mut attribute: *mut libc::c_char) {
|
||||
mailmime_token_free(attribute);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_token_free(mut token: *mut libc::c_char) {
|
||||
free(token as *mut libc::c_void);
|
||||
}
|
||||
pub unsafe fn mailmime_composite_type_new(
|
||||
mut ct_type: libc::c_int,
|
||||
mut ct_token: *mut libc::c_char,
|
||||
) -> *mut mailmime_composite_type {
|
||||
let mut ct: *mut mailmime_composite_type = 0 as *mut mailmime_composite_type;
|
||||
ct = malloc(::std::mem::size_of::<mailmime_composite_type>() as libc::size_t)
|
||||
as *mut mailmime_composite_type;
|
||||
if ct.is_null() {
|
||||
return 0 as *mut mailmime_composite_type;
|
||||
}
|
||||
(*ct).ct_type = ct_type;
|
||||
(*ct).ct_token = ct_token;
|
||||
return ct;
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_composite_type_free(mut ct: *mut mailmime_composite_type) {
|
||||
if !(*ct).ct_token.is_null() {
|
||||
mailmime_extension_token_free((*ct).ct_token);
|
||||
}
|
||||
free(ct as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_extension_token_free(mut extension: *mut libc::c_char) {
|
||||
mailmime_token_free(extension);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_content_new(
|
||||
mut ct_type: *mut mailmime_type,
|
||||
mut ct_subtype: *mut libc::c_char,
|
||||
mut ct_parameters: *mut clist,
|
||||
) -> *mut mailmime_content {
|
||||
let mut content: *mut mailmime_content = 0 as *mut mailmime_content;
|
||||
content =
|
||||
malloc(::std::mem::size_of::<mailmime_content>() as libc::size_t) as *mut mailmime_content;
|
||||
if content.is_null() {
|
||||
return 0 as *mut mailmime_content;
|
||||
}
|
||||
(*content).ct_type = ct_type;
|
||||
(*content).ct_subtype = ct_subtype;
|
||||
(*content).ct_parameters = ct_parameters;
|
||||
return content;
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_content_free(mut content: *mut mailmime_content) {
|
||||
mailmime_type_free((*content).ct_type);
|
||||
mailmime_subtype_free((*content).ct_subtype);
|
||||
if !(*content).ct_parameters.is_null() {
|
||||
clist_foreach(
|
||||
(*content).ct_parameters,
|
||||
::std::mem::transmute::<Option<unsafe fn(_: *mut mailmime_parameter) -> ()>, clist_func>(
|
||||
Some(mailmime_parameter_free),
|
||||
),
|
||||
0 as *mut libc::c_void,
|
||||
);
|
||||
clist_free((*content).ct_parameters);
|
||||
}
|
||||
free(content as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_parameter_free(mut parameter: *mut mailmime_parameter) {
|
||||
mailmime_attribute_free((*parameter).pa_name);
|
||||
mailmime_value_free((*parameter).pa_value);
|
||||
free(parameter as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_value_free(mut value: *mut libc::c_char) {
|
||||
free(value as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_subtype_free(mut subtype: *mut libc::c_char) {
|
||||
mailmime_extension_token_free(subtype);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_type_free(mut type_0: *mut mailmime_type) {
|
||||
match (*type_0).tp_type {
|
||||
1 => {
|
||||
mailmime_discrete_type_free((*type_0).tp_data.tp_discrete_type);
|
||||
}
|
||||
2 => {
|
||||
mailmime_composite_type_free((*type_0).tp_data.tp_composite_type);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
free(type_0 as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_discrete_type_free(mut discrete_type: *mut mailmime_discrete_type) {
|
||||
if !(*discrete_type).dt_extension.is_null() {
|
||||
mailmime_extension_token_free((*discrete_type).dt_extension);
|
||||
}
|
||||
free(discrete_type as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_description_free(mut description: *mut libc::c_char) {
|
||||
free(description as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_location_free(mut location: *mut libc::c_char) {
|
||||
free(location as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_discrete_type_new(
|
||||
mut dt_type: libc::c_int,
|
||||
mut dt_extension: *mut libc::c_char,
|
||||
) -> *mut mailmime_discrete_type {
|
||||
let mut discrete_type: *mut mailmime_discrete_type = 0 as *mut mailmime_discrete_type;
|
||||
discrete_type = malloc(::std::mem::size_of::<mailmime_discrete_type>() as libc::size_t)
|
||||
as *mut mailmime_discrete_type;
|
||||
if discrete_type.is_null() {
|
||||
return 0 as *mut mailmime_discrete_type;
|
||||
}
|
||||
(*discrete_type).dt_type = dt_type;
|
||||
(*discrete_type).dt_extension = dt_extension;
|
||||
return discrete_type;
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_encoding_free(mut encoding: *mut mailmime_mechanism) {
|
||||
mailmime_mechanism_free(encoding);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_mechanism_free(mut mechanism: *mut mailmime_mechanism) {
|
||||
if !(*mechanism).enc_token.is_null() {
|
||||
mailmime_token_free((*mechanism).enc_token);
|
||||
}
|
||||
free(mechanism as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_id_free(mut id: *mut libc::c_char) {
|
||||
mailimf_msg_id_free(id);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_mechanism_new(
|
||||
mut enc_type: libc::c_int,
|
||||
mut enc_token: *mut libc::c_char,
|
||||
) -> *mut mailmime_mechanism {
|
||||
let mut mechanism: *mut mailmime_mechanism = 0 as *mut mailmime_mechanism;
|
||||
mechanism = malloc(::std::mem::size_of::<mailmime_mechanism>() as libc::size_t)
|
||||
as *mut mailmime_mechanism;
|
||||
if mechanism.is_null() {
|
||||
return 0 as *mut mailmime_mechanism;
|
||||
}
|
||||
(*mechanism).enc_type = enc_type;
|
||||
(*mechanism).enc_token = enc_token;
|
||||
return mechanism;
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_parameter_new(
|
||||
mut pa_name: *mut libc::c_char,
|
||||
mut pa_value: *mut libc::c_char,
|
||||
) -> *mut mailmime_parameter {
|
||||
let mut parameter: *mut mailmime_parameter = 0 as *mut mailmime_parameter;
|
||||
parameter = malloc(::std::mem::size_of::<mailmime_parameter>() as libc::size_t)
|
||||
as *mut mailmime_parameter;
|
||||
if parameter.is_null() {
|
||||
return 0 as *mut mailmime_parameter;
|
||||
}
|
||||
(*parameter).pa_name = pa_name;
|
||||
(*parameter).pa_value = pa_value;
|
||||
return parameter;
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_type_new(
|
||||
mut tp_type: libc::c_int,
|
||||
mut tp_discrete_type: *mut mailmime_discrete_type,
|
||||
mut tp_composite_type: *mut mailmime_composite_type,
|
||||
) -> *mut mailmime_type {
|
||||
let mut mime_type: *mut mailmime_type = 0 as *mut mailmime_type;
|
||||
mime_type =
|
||||
malloc(::std::mem::size_of::<mailmime_type>() as libc::size_t) as *mut mailmime_type;
|
||||
if mime_type.is_null() {
|
||||
return 0 as *mut mailmime_type;
|
||||
}
|
||||
(*mime_type).tp_type = tp_type;
|
||||
match tp_type {
|
||||
1 => (*mime_type).tp_data.tp_discrete_type = tp_discrete_type,
|
||||
2 => (*mime_type).tp_data.tp_composite_type = tp_composite_type,
|
||||
_ => {}
|
||||
}
|
||||
return mime_type;
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_language_new(mut lg_list: *mut clist) -> *mut mailmime_language {
|
||||
let mut lang: *mut mailmime_language = 0 as *mut mailmime_language;
|
||||
lang = malloc(::std::mem::size_of::<mailmime_language>() as libc::size_t)
|
||||
as *mut mailmime_language;
|
||||
if lang.is_null() {
|
||||
return 0 as *mut mailmime_language;
|
||||
}
|
||||
(*lang).lg_list = lg_list;
|
||||
return lang;
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_language_free(mut lang: *mut mailmime_language) {
|
||||
clist_foreach(
|
||||
(*lang).lg_list,
|
||||
::std::mem::transmute::<Option<unsafe fn(_: *mut libc::c_char) -> ()>, clist_func>(Some(
|
||||
mailimf_atom_free,
|
||||
)),
|
||||
0 as *mut libc::c_void,
|
||||
);
|
||||
clist_free((*lang).lg_list);
|
||||
free(lang as *mut libc::c_void);
|
||||
}
|
||||
/*
|
||||
void mailmime_x_token_free(gchar * x_token);
|
||||
*/
|
||||
pub unsafe fn mailmime_field_new(
|
||||
mut fld_type: libc::c_int,
|
||||
mut fld_content: *mut mailmime_content,
|
||||
mut fld_encoding: *mut mailmime_mechanism,
|
||||
mut fld_id: *mut libc::c_char,
|
||||
mut fld_description: *mut libc::c_char,
|
||||
mut fld_version: uint32_t,
|
||||
mut fld_disposition: *mut mailmime_disposition,
|
||||
mut fld_language: *mut mailmime_language,
|
||||
mut fld_location: *mut libc::c_char,
|
||||
) -> *mut mailmime_field {
|
||||
let mut field: *mut mailmime_field = 0 as *mut mailmime_field;
|
||||
field = malloc(::std::mem::size_of::<mailmime_field>() as libc::size_t) as *mut mailmime_field;
|
||||
if field.is_null() {
|
||||
return 0 as *mut mailmime_field;
|
||||
}
|
||||
(*field).fld_type = fld_type;
|
||||
match fld_type {
|
||||
1 => (*field).fld_data.fld_content = fld_content,
|
||||
2 => (*field).fld_data.fld_encoding = fld_encoding,
|
||||
3 => (*field).fld_data.fld_id = fld_id,
|
||||
4 => (*field).fld_data.fld_description = fld_description,
|
||||
5 => (*field).fld_data.fld_version = fld_version,
|
||||
6 => (*field).fld_data.fld_disposition = fld_disposition,
|
||||
7 => (*field).fld_data.fld_language = fld_language,
|
||||
8 => (*field).fld_data.fld_location = fld_location,
|
||||
_ => {}
|
||||
}
|
||||
return field;
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_field_free(mut field: *mut mailmime_field) {
|
||||
match (*field).fld_type {
|
||||
1 => {
|
||||
if !(*field).fld_data.fld_content.is_null() {
|
||||
mailmime_content_free((*field).fld_data.fld_content);
|
||||
}
|
||||
}
|
||||
2 => {
|
||||
if !(*field).fld_data.fld_encoding.is_null() {
|
||||
mailmime_encoding_free((*field).fld_data.fld_encoding);
|
||||
}
|
||||
}
|
||||
3 => {
|
||||
if !(*field).fld_data.fld_id.is_null() {
|
||||
mailmime_id_free((*field).fld_data.fld_id);
|
||||
}
|
||||
}
|
||||
4 => {
|
||||
if !(*field).fld_data.fld_description.is_null() {
|
||||
mailmime_description_free((*field).fld_data.fld_description);
|
||||
}
|
||||
}
|
||||
6 => {
|
||||
if !(*field).fld_data.fld_disposition.is_null() {
|
||||
mailmime_disposition_free((*field).fld_data.fld_disposition);
|
||||
}
|
||||
}
|
||||
7 => {
|
||||
if !(*field).fld_data.fld_language.is_null() {
|
||||
mailmime_language_free((*field).fld_data.fld_language);
|
||||
}
|
||||
}
|
||||
8 => {
|
||||
if !(*field).fld_data.fld_location.is_null() {
|
||||
mailmime_location_free((*field).fld_data.fld_location);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
free(field as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_disposition_free(mut dsp: *mut mailmime_disposition) {
|
||||
mailmime_disposition_type_free((*dsp).dsp_type);
|
||||
clist_foreach(
|
||||
(*dsp).dsp_parms,
|
||||
::std::mem::transmute::<
|
||||
Option<unsafe fn(_: *mut mailmime_disposition_parm) -> ()>,
|
||||
clist_func,
|
||||
>(Some(mailmime_disposition_parm_free)),
|
||||
0 as *mut libc::c_void,
|
||||
);
|
||||
clist_free((*dsp).dsp_parms);
|
||||
free(dsp as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_disposition_parm_free(mut dsp_parm: *mut mailmime_disposition_parm) {
|
||||
match (*dsp_parm).pa_type {
|
||||
0 => {
|
||||
mailmime_filename_parm_free((*dsp_parm).pa_data.pa_filename);
|
||||
}
|
||||
1 => {
|
||||
mailmime_creation_date_parm_free((*dsp_parm).pa_data.pa_creation_date);
|
||||
}
|
||||
2 => {
|
||||
mailmime_modification_date_parm_free((*dsp_parm).pa_data.pa_modification_date);
|
||||
}
|
||||
3 => {
|
||||
mailmime_read_date_parm_free((*dsp_parm).pa_data.pa_read_date);
|
||||
}
|
||||
5 => {
|
||||
mailmime_parameter_free((*dsp_parm).pa_data.pa_parameter);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
free(dsp_parm as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_read_date_parm_free(mut date: *mut libc::c_char) {
|
||||
mailmime_quoted_date_time_free(date);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_quoted_date_time_free(mut date: *mut libc::c_char) {
|
||||
mailimf_quoted_string_free(date);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_modification_date_parm_free(mut date: *mut libc::c_char) {
|
||||
mailmime_quoted_date_time_free(date);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_creation_date_parm_free(mut date: *mut libc::c_char) {
|
||||
mailmime_quoted_date_time_free(date);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_filename_parm_free(mut filename: *mut libc::c_char) {
|
||||
mailmime_value_free(filename);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_disposition_type_free(mut dsp_type: *mut mailmime_disposition_type) {
|
||||
if !(*dsp_type).dsp_extension.is_null() {
|
||||
free((*dsp_type).dsp_extension as *mut libc::c_void);
|
||||
}
|
||||
free(dsp_type as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_fields_new(mut fld_list: *mut clist) -> *mut mailmime_fields {
|
||||
let mut fields: *mut mailmime_fields = 0 as *mut mailmime_fields;
|
||||
fields =
|
||||
malloc(::std::mem::size_of::<mailmime_fields>() as libc::size_t) as *mut mailmime_fields;
|
||||
if fields.is_null() {
|
||||
return 0 as *mut mailmime_fields;
|
||||
}
|
||||
(*fields).fld_list = fld_list;
|
||||
return fields;
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_fields_free(mut fields: *mut mailmime_fields) {
|
||||
clist_foreach(
|
||||
(*fields).fld_list,
|
||||
::std::mem::transmute::<Option<unsafe fn(_: *mut mailmime_field) -> ()>, clist_func>(Some(
|
||||
mailmime_field_free,
|
||||
)),
|
||||
0 as *mut libc::c_void,
|
||||
);
|
||||
clist_free((*fields).fld_list);
|
||||
free(fields as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_multipart_body_new(mut bd_list: *mut clist) -> *mut mailmime_multipart_body {
|
||||
let mut mp_body: *mut mailmime_multipart_body = 0 as *mut mailmime_multipart_body;
|
||||
mp_body = malloc(::std::mem::size_of::<mailmime_multipart_body>() as libc::size_t)
|
||||
as *mut mailmime_multipart_body;
|
||||
if mp_body.is_null() {
|
||||
return 0 as *mut mailmime_multipart_body;
|
||||
}
|
||||
(*mp_body).bd_list = bd_list;
|
||||
return mp_body;
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_multipart_body_free(mut mp_body: *mut mailmime_multipart_body) {
|
||||
clist_foreach(
|
||||
(*mp_body).bd_list,
|
||||
::std::mem::transmute::<Option<unsafe fn(_: *mut mailimf_body) -> ()>, clist_func>(Some(
|
||||
mailimf_body_free,
|
||||
)),
|
||||
0 as *mut libc::c_void,
|
||||
);
|
||||
clist_free((*mp_body).bd_list);
|
||||
free(mp_body as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_data_new(
|
||||
mut dt_type: libc::c_int,
|
||||
mut dt_encoding: libc::c_int,
|
||||
mut dt_encoded: libc::c_int,
|
||||
mut dt_data: *const libc::c_char,
|
||||
mut dt_length: size_t,
|
||||
mut dt_filename: *mut libc::c_char,
|
||||
) -> *mut mailmime_data {
|
||||
let mut mime_data: *mut mailmime_data = 0 as *mut mailmime_data;
|
||||
mime_data =
|
||||
malloc(::std::mem::size_of::<mailmime_data>() as libc::size_t) as *mut mailmime_data;
|
||||
if mime_data.is_null() {
|
||||
return 0 as *mut mailmime_data;
|
||||
}
|
||||
(*mime_data).dt_type = dt_type;
|
||||
(*mime_data).dt_encoding = dt_encoding;
|
||||
(*mime_data).dt_encoded = dt_encoded;
|
||||
match dt_type {
|
||||
0 => {
|
||||
(*mime_data).dt_data.dt_text.dt_data = dt_data;
|
||||
(*mime_data).dt_data.dt_text.dt_length = dt_length
|
||||
}
|
||||
1 => (*mime_data).dt_data.dt_filename = dt_filename,
|
||||
_ => {}
|
||||
}
|
||||
return mime_data;
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_data_free(mut mime_data: *mut mailmime_data) {
|
||||
match (*mime_data).dt_type {
|
||||
1 => {
|
||||
free((*mime_data).dt_data.dt_filename as *mut libc::c_void);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
free(mime_data as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_new(
|
||||
mut mm_type: libc::c_int,
|
||||
mut mm_mime_start: *const libc::c_char,
|
||||
mut mm_length: size_t,
|
||||
mut mm_mime_fields: *mut mailmime_fields,
|
||||
mut mm_content_type: *mut mailmime_content,
|
||||
mut mm_body: *mut mailmime_data,
|
||||
mut mm_preamble: *mut mailmime_data,
|
||||
mut mm_epilogue: *mut mailmime_data,
|
||||
mut mm_mp_list: *mut clist,
|
||||
mut mm_fields: *mut mailimf_fields,
|
||||
mut mm_msg_mime: *mut Mailmime,
|
||||
) -> *mut Mailmime {
|
||||
let mut mime: *mut Mailmime = 0 as *mut Mailmime;
|
||||
let mut cur: *mut clistiter = 0 as *mut clistiter;
|
||||
mime = malloc(::std::mem::size_of::<Mailmime>() as libc::size_t) as *mut Mailmime;
|
||||
if mime.is_null() {
|
||||
return 0 as *mut Mailmime;
|
||||
}
|
||||
(*mime).mm_parent = 0 as *mut Mailmime;
|
||||
(*mime).mm_parent_type = MAILMIME_NONE as libc::c_int;
|
||||
(*mime).mm_multipart_pos = 0 as *mut clistiter;
|
||||
(*mime).mm_type = mm_type;
|
||||
(*mime).mm_mime_start = mm_mime_start;
|
||||
(*mime).mm_length = mm_length;
|
||||
(*mime).mm_mime_fields = mm_mime_fields;
|
||||
(*mime).mm_content_type = mm_content_type;
|
||||
(*mime).mm_body = mm_body;
|
||||
match mm_type {
|
||||
1 => (*mime).mm_data.mm_single = mm_body,
|
||||
2 => {
|
||||
(*mime).mm_data.mm_multipart.mm_preamble = mm_preamble;
|
||||
(*mime).mm_data.mm_multipart.mm_epilogue = mm_epilogue;
|
||||
(*mime).mm_data.mm_multipart.mm_mp_list = mm_mp_list;
|
||||
cur = (*mm_mp_list).first;
|
||||
while !cur.is_null() {
|
||||
let mut submime: *mut Mailmime = 0 as *mut Mailmime;
|
||||
submime = (if !cur.is_null() {
|
||||
(*cur).data
|
||||
} else {
|
||||
0 as *mut libc::c_void
|
||||
}) as *mut Mailmime;
|
||||
(*submime).mm_parent = mime;
|
||||
(*submime).mm_parent_type = MAILMIME_MULTIPLE as libc::c_int;
|
||||
(*submime).mm_multipart_pos = cur;
|
||||
cur = if !cur.is_null() {
|
||||
(*cur).next
|
||||
} else {
|
||||
0 as *mut clistcell
|
||||
}
|
||||
}
|
||||
}
|
||||
3 => {
|
||||
(*mime).mm_data.mm_message.mm_fields = mm_fields;
|
||||
(*mime).mm_data.mm_message.mm_msg_mime = mm_msg_mime;
|
||||
if !mm_msg_mime.is_null() {
|
||||
(*mm_msg_mime).mm_parent = mime;
|
||||
(*mm_msg_mime).mm_parent_type = MAILMIME_MESSAGE as libc::c_int
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
return mime;
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_new_simple(
|
||||
mut mm_type: libc::c_int,
|
||||
mut mm_mime_fields: *mut mailmime_fields,
|
||||
mut mm_content_type: *mut mailmime_content,
|
||||
mut mm_fields: *mut mailimf_fields,
|
||||
mut mm_msg_mime: *mut Mailmime,
|
||||
) -> *mut Mailmime {
|
||||
mailmime_new(
|
||||
mm_type,
|
||||
std::ptr::null(),
|
||||
0,
|
||||
mm_mime_fields,
|
||||
mm_content_type,
|
||||
std::ptr::null_mut(),
|
||||
std::ptr::null_mut(),
|
||||
std::ptr::null_mut(),
|
||||
std::ptr::null_mut(),
|
||||
mm_fields,
|
||||
mm_msg_mime,
|
||||
)
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_free(mut mime: *mut Mailmime) {
|
||||
match (*mime).mm_type {
|
||||
1 => {
|
||||
if (*mime).mm_body.is_null() && !(*mime).mm_data.mm_single.is_null() {
|
||||
mailmime_data_free((*mime).mm_data.mm_single);
|
||||
}
|
||||
}
|
||||
2 => {
|
||||
/* do nothing */
|
||||
if !(*mime).mm_data.mm_multipart.mm_preamble.is_null() {
|
||||
mailmime_data_free((*mime).mm_data.mm_multipart.mm_preamble);
|
||||
}
|
||||
if !(*mime).mm_data.mm_multipart.mm_epilogue.is_null() {
|
||||
mailmime_data_free((*mime).mm_data.mm_multipart.mm_epilogue);
|
||||
}
|
||||
clist_foreach(
|
||||
(*mime).mm_data.mm_multipart.mm_mp_list,
|
||||
::std::mem::transmute::<Option<unsafe fn(_: *mut Mailmime) -> ()>, clist_func>(
|
||||
Some(mailmime_free),
|
||||
),
|
||||
0 as *mut libc::c_void,
|
||||
);
|
||||
clist_free((*mime).mm_data.mm_multipart.mm_mp_list);
|
||||
}
|
||||
3 => {
|
||||
if !(*mime).mm_data.mm_message.mm_fields.is_null() {
|
||||
mailimf_fields_free((*mime).mm_data.mm_message.mm_fields);
|
||||
}
|
||||
if !(*mime).mm_data.mm_message.mm_msg_mime.is_null() {
|
||||
mailmime_free((*mime).mm_data.mm_message.mm_msg_mime);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
if !(*mime).mm_body.is_null() {
|
||||
mailmime_data_free((*mime).mm_body);
|
||||
}
|
||||
if !(*mime).mm_mime_fields.is_null() {
|
||||
mailmime_fields_free((*mime).mm_mime_fields);
|
||||
}
|
||||
if !(*mime).mm_content_type.is_null() {
|
||||
mailmime_content_free((*mime).mm_content_type);
|
||||
}
|
||||
free(mime as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_encoded_word_new(
|
||||
mut wd_charset: *mut libc::c_char,
|
||||
mut wd_text: *mut libc::c_char,
|
||||
) -> *mut mailmime_encoded_word {
|
||||
let mut ew: *mut mailmime_encoded_word = 0 as *mut mailmime_encoded_word;
|
||||
ew = malloc(::std::mem::size_of::<mailmime_encoded_word>() as libc::size_t)
|
||||
as *mut mailmime_encoded_word;
|
||||
if ew.is_null() {
|
||||
return 0 as *mut mailmime_encoded_word;
|
||||
}
|
||||
(*ew).wd_charset = wd_charset;
|
||||
(*ew).wd_text = wd_text;
|
||||
return ew;
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_encoded_word_free(mut ew: *mut mailmime_encoded_word) {
|
||||
mailmime_charset_free((*ew).wd_charset);
|
||||
mailmime_encoded_text_free((*ew).wd_text);
|
||||
free(ew as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_encoded_text_free(mut text: *mut libc::c_char) {
|
||||
free(text as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_charset_free(mut charset: *mut libc::c_char) {
|
||||
free(charset as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_disposition_new(
|
||||
mut dsp_type: *mut mailmime_disposition_type,
|
||||
mut dsp_parms: *mut clist,
|
||||
) -> *mut mailmime_disposition {
|
||||
let mut dsp: *mut mailmime_disposition = 0 as *mut mailmime_disposition;
|
||||
dsp = malloc(::std::mem::size_of::<mailmime_disposition>() as libc::size_t)
|
||||
as *mut mailmime_disposition;
|
||||
if dsp.is_null() {
|
||||
return 0 as *mut mailmime_disposition;
|
||||
}
|
||||
(*dsp).dsp_type = dsp_type;
|
||||
(*dsp).dsp_parms = dsp_parms;
|
||||
return dsp;
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_disposition_type_new(
|
||||
mut dsp_type: libc::c_int,
|
||||
mut dsp_extension: *mut libc::c_char,
|
||||
) -> *mut mailmime_disposition_type {
|
||||
let mut m_dsp_type: *mut mailmime_disposition_type = 0 as *mut mailmime_disposition_type;
|
||||
m_dsp_type = malloc(::std::mem::size_of::<mailmime_disposition_type>() as libc::size_t)
|
||||
as *mut mailmime_disposition_type;
|
||||
if m_dsp_type.is_null() {
|
||||
return 0 as *mut mailmime_disposition_type;
|
||||
}
|
||||
(*m_dsp_type).dsp_type = dsp_type;
|
||||
(*m_dsp_type).dsp_extension = dsp_extension;
|
||||
return m_dsp_type;
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_disposition_parm_new(
|
||||
mut pa_type: libc::c_int,
|
||||
mut pa_filename: *mut libc::c_char,
|
||||
mut pa_creation_date: *mut libc::c_char,
|
||||
mut pa_modification_date: *mut libc::c_char,
|
||||
mut pa_read_date: *mut libc::c_char,
|
||||
mut pa_size: size_t,
|
||||
mut pa_parameter: *mut mailmime_parameter,
|
||||
) -> *mut mailmime_disposition_parm {
|
||||
let mut dsp_parm: *mut mailmime_disposition_parm = 0 as *mut mailmime_disposition_parm;
|
||||
dsp_parm = malloc(::std::mem::size_of::<mailmime_disposition_parm>() as libc::size_t)
|
||||
as *mut mailmime_disposition_parm;
|
||||
if dsp_parm.is_null() {
|
||||
return 0 as *mut mailmime_disposition_parm;
|
||||
}
|
||||
(*dsp_parm).pa_type = pa_type;
|
||||
match pa_type {
|
||||
0 => (*dsp_parm).pa_data.pa_filename = pa_filename,
|
||||
1 => (*dsp_parm).pa_data.pa_creation_date = pa_creation_date,
|
||||
2 => (*dsp_parm).pa_data.pa_modification_date = pa_modification_date,
|
||||
3 => (*dsp_parm).pa_data.pa_read_date = pa_read_date,
|
||||
4 => (*dsp_parm).pa_data.pa_size = pa_size,
|
||||
5 => (*dsp_parm).pa_data.pa_parameter = pa_parameter,
|
||||
_ => {}
|
||||
}
|
||||
return dsp_parm;
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_section_new(mut sec_list: *mut clist) -> *mut mailmime_section {
|
||||
let mut section: *mut mailmime_section = 0 as *mut mailmime_section;
|
||||
section =
|
||||
malloc(::std::mem::size_of::<mailmime_section>() as libc::size_t) as *mut mailmime_section;
|
||||
if section.is_null() {
|
||||
return 0 as *mut mailmime_section;
|
||||
}
|
||||
(*section).sec_list = sec_list;
|
||||
return section;
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_section_free(mut section: *mut mailmime_section) {
|
||||
clist_foreach(
|
||||
(*section).sec_list,
|
||||
::std::mem::transmute::<Option<unsafe extern "C" fn(_: *mut libc::c_void) -> ()>, clist_func>(
|
||||
Some(free),
|
||||
),
|
||||
0 as *mut libc::c_void,
|
||||
);
|
||||
clist_free((*section).sec_list);
|
||||
free(section as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_decoded_part_free(mut part: *mut libc::c_char) {
|
||||
mmap_string_unref(part);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,82 +0,0 @@
|
||||
use crate::mailmime::types::*;
|
||||
use crate::mailmime::write_generic::*;
|
||||
use crate::mmapstring::*;
|
||||
use crate::other::*;
|
||||
|
||||
unsafe fn do_write(
|
||||
mut data: *mut libc::c_void,
|
||||
mut str: *const libc::c_char,
|
||||
mut length: size_t,
|
||||
) -> libc::c_int {
|
||||
let mut f: *mut MMAPString = 0 as *mut MMAPString;
|
||||
f = data as *mut MMAPString;
|
||||
if mmap_string_append_len(f, str, length).is_null() {
|
||||
return 0i32;
|
||||
} else {
|
||||
return length as libc::c_int;
|
||||
};
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_content_write_mem(
|
||||
mut f: *mut MMAPString,
|
||||
mut col: *mut libc::c_int,
|
||||
mut content: *mut mailmime_content,
|
||||
) -> libc::c_int {
|
||||
return mailmime_content_write_driver(Some(do_write), f as *mut libc::c_void, col, content);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_content_type_write_mem(
|
||||
mut f: *mut MMAPString,
|
||||
mut col: *mut libc::c_int,
|
||||
mut content: *mut mailmime_content,
|
||||
) -> libc::c_int {
|
||||
return mailmime_content_type_write_driver(
|
||||
Some(do_write),
|
||||
f as *mut libc::c_void,
|
||||
col,
|
||||
content,
|
||||
);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_write_mem(
|
||||
mut f: *mut MMAPString,
|
||||
mut col: *mut libc::c_int,
|
||||
mut build_info: *mut Mailmime,
|
||||
) -> libc::c_int {
|
||||
return mailmime_write_driver(Some(do_write), f as *mut libc::c_void, col, build_info);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_quoted_printable_write_mem(
|
||||
mut f: *mut MMAPString,
|
||||
mut col: *mut libc::c_int,
|
||||
mut istext: libc::c_int,
|
||||
mut text: *const libc::c_char,
|
||||
mut size: size_t,
|
||||
) -> libc::c_int {
|
||||
return mailmime_quoted_printable_write_driver(
|
||||
Some(do_write),
|
||||
f as *mut libc::c_void,
|
||||
col,
|
||||
istext,
|
||||
text,
|
||||
size,
|
||||
);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_base64_write_mem(
|
||||
mut f: *mut MMAPString,
|
||||
mut col: *mut libc::c_int,
|
||||
mut text: *const libc::c_char,
|
||||
mut size: size_t,
|
||||
) -> libc::c_int {
|
||||
return mailmime_base64_write_driver(Some(do_write), f as *mut libc::c_void, col, text, size);
|
||||
}
|
||||
|
||||
pub unsafe fn mailmime_data_write_mem(
|
||||
mut f: *mut MMAPString,
|
||||
mut col: *mut libc::c_int,
|
||||
mut data: *mut mailmime_data,
|
||||
mut istext: libc::c_int,
|
||||
) -> libc::c_int {
|
||||
return mailmime_data_write_driver(Some(do_write), f as *mut libc::c_void, col, data, istext);
|
||||
}
|
||||
@@ -1,397 +0,0 @@
|
||||
use std::sync::Mutex;
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
use libc;
|
||||
|
||||
use crate::chash::*;
|
||||
use crate::other::*;
|
||||
|
||||
lazy_static! {
|
||||
static ref mmapstring_lock: Mutex<()> = Mutex::new(());
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct MMAPString {
|
||||
pub str_0: *mut libc::c_char,
|
||||
pub len: size_t,
|
||||
pub allocated_len: size_t,
|
||||
pub fd: libc::c_int,
|
||||
pub mmapped_size: size_t,
|
||||
}
|
||||
|
||||
pub const TMPDIR: &'static str = "/tmp";
|
||||
|
||||
pub unsafe fn mmap_string_new(mut init: *const libc::c_char) -> *mut MMAPString {
|
||||
let mut string: *mut MMAPString = 0 as *mut MMAPString;
|
||||
string = mmap_string_sized_new(if !init.is_null() {
|
||||
strlen(init).wrapping_add(2i32 as libc::size_t)
|
||||
} else {
|
||||
2i32 as libc::size_t
|
||||
});
|
||||
if string.is_null() {
|
||||
return 0 as *mut MMAPString;
|
||||
}
|
||||
if !init.is_null() {
|
||||
mmap_string_append(string, init);
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
pub unsafe fn mmap_string_append(
|
||||
mut string: *mut MMAPString,
|
||||
mut val: *const libc::c_char,
|
||||
) -> *mut MMAPString {
|
||||
return mmap_string_insert_len(string, (*string).len, val, strlen(val));
|
||||
}
|
||||
|
||||
pub unsafe fn mmap_string_insert_len(
|
||||
mut string: *mut MMAPString,
|
||||
mut pos: size_t,
|
||||
mut val: *const libc::c_char,
|
||||
mut len: size_t,
|
||||
) -> *mut MMAPString {
|
||||
if mmap_string_maybe_expand(string, len).is_null() {
|
||||
return 0 as *mut MMAPString;
|
||||
}
|
||||
if pos < (*string).len {
|
||||
memmove(
|
||||
(*string).str_0.offset(pos as isize).offset(len as isize) as *mut libc::c_void,
|
||||
(*string).str_0.offset(pos as isize) as *const libc::c_void,
|
||||
(*string).len.wrapping_sub(pos),
|
||||
);
|
||||
}
|
||||
memmove(
|
||||
(*string).str_0.offset(pos as isize) as *mut libc::c_void,
|
||||
val as *const libc::c_void,
|
||||
len,
|
||||
);
|
||||
(*string).len = ((*string).len as libc::size_t).wrapping_add(len) as size_t as size_t;
|
||||
*(*string).str_0.offset((*string).len as isize) = 0i32 as libc::c_char;
|
||||
return string;
|
||||
}
|
||||
unsafe fn mmap_string_maybe_expand(
|
||||
mut string: *mut MMAPString,
|
||||
mut len: size_t,
|
||||
) -> *mut MMAPString {
|
||||
if (*string).len.wrapping_add(len) >= (*string).allocated_len {
|
||||
let mut old_size: size_t = 0;
|
||||
let mut newstring: *mut MMAPString = 0 as *mut MMAPString;
|
||||
old_size = (*string).allocated_len;
|
||||
(*string).allocated_len = nearest_power(
|
||||
1i32 as size_t,
|
||||
(*string)
|
||||
.len
|
||||
.wrapping_add(len)
|
||||
.wrapping_add(1i32 as libc::size_t),
|
||||
);
|
||||
newstring = mmap_string_realloc_memory(string);
|
||||
if newstring.is_null() {
|
||||
(*string).allocated_len = old_size
|
||||
}
|
||||
return newstring;
|
||||
}
|
||||
return string;
|
||||
}
|
||||
/* Strings.
|
||||
*/
|
||||
/* SEB */
|
||||
unsafe fn mmap_string_realloc_memory(mut string: *mut MMAPString) -> *mut MMAPString {
|
||||
let mut tmp: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
tmp = realloc(
|
||||
(*string).str_0 as *mut libc::c_void,
|
||||
(*string).allocated_len,
|
||||
) as *mut libc::c_char;
|
||||
if tmp.is_null() {
|
||||
string = 0 as *mut MMAPString
|
||||
} else {
|
||||
(*string).str_0 = tmp
|
||||
}
|
||||
return string;
|
||||
}
|
||||
/* MMAPString */
|
||||
#[inline]
|
||||
unsafe fn nearest_power(mut base: size_t, mut num: size_t) -> size_t {
|
||||
if num > (-1i32 as size_t).wrapping_div(2i32 as libc::size_t) {
|
||||
return -1i32 as size_t;
|
||||
} else {
|
||||
let mut n: size_t = base;
|
||||
while n < num {
|
||||
n <<= 1i32
|
||||
}
|
||||
return n;
|
||||
};
|
||||
}
|
||||
|
||||
pub unsafe fn mmap_string_sized_new(mut dfl_size: size_t) -> *mut MMAPString {
|
||||
let mut string: *mut MMAPString = 0 as *mut MMAPString;
|
||||
string = malloc(::std::mem::size_of::<MMAPString>() as libc::size_t) as *mut MMAPString;
|
||||
if string.is_null() {
|
||||
return 0 as *mut MMAPString;
|
||||
}
|
||||
(*string).allocated_len = 0i32 as size_t;
|
||||
(*string).len = 0i32 as size_t;
|
||||
(*string).str_0 = 0 as *mut libc::c_char;
|
||||
(*string).fd = -1i32;
|
||||
(*string).mmapped_size = 0i32 as size_t;
|
||||
if mmap_string_maybe_expand(
|
||||
string,
|
||||
if dfl_size > 2i32 as libc::size_t {
|
||||
dfl_size
|
||||
} else {
|
||||
2i32 as libc::size_t
|
||||
},
|
||||
)
|
||||
.is_null()
|
||||
{
|
||||
free(string as *mut libc::c_void);
|
||||
return 0 as *mut MMAPString;
|
||||
}
|
||||
*(*string).str_0.offset(0isize) = 0i32 as libc::c_char;
|
||||
return string;
|
||||
}
|
||||
|
||||
pub unsafe fn mmap_string_new_len(
|
||||
mut init: *const libc::c_char,
|
||||
mut len: size_t,
|
||||
) -> *mut MMAPString {
|
||||
let mut string: *mut MMAPString = 0 as *mut MMAPString;
|
||||
if len <= 0i32 as libc::size_t {
|
||||
return mmap_string_new(b"\x00" as *const u8 as *const libc::c_char);
|
||||
} else {
|
||||
string = mmap_string_sized_new(len);
|
||||
if string.is_null() {
|
||||
return string;
|
||||
}
|
||||
if !init.is_null() {
|
||||
mmap_string_append_len(string, init, len);
|
||||
}
|
||||
return string;
|
||||
};
|
||||
}
|
||||
|
||||
pub unsafe fn mmap_string_append_len(
|
||||
mut string: *mut MMAPString,
|
||||
mut val: *const libc::c_char,
|
||||
mut len: size_t,
|
||||
) -> *mut MMAPString {
|
||||
return mmap_string_insert_len(string, (*string).len, val, len);
|
||||
}
|
||||
|
||||
pub unsafe fn mmap_string_free(mut string: *mut MMAPString) {
|
||||
if string.is_null() {
|
||||
return;
|
||||
}
|
||||
free((*string).str_0 as *mut libc::c_void);
|
||||
free(string as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn mmap_string_assign(
|
||||
mut string: *mut MMAPString,
|
||||
mut rval: *const libc::c_char,
|
||||
) -> *mut MMAPString {
|
||||
mmap_string_truncate(string, 0i32 as size_t);
|
||||
if mmap_string_append(string, rval).is_null() {
|
||||
return 0 as *mut MMAPString;
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
pub unsafe fn mmap_string_truncate(
|
||||
mut string: *mut MMAPString,
|
||||
mut len: size_t,
|
||||
) -> *mut MMAPString {
|
||||
(*string).len = if len < (*string).len {
|
||||
len
|
||||
} else {
|
||||
(*string).len
|
||||
};
|
||||
*(*string).str_0.offset((*string).len as isize) = 0i32 as libc::c_char;
|
||||
return string;
|
||||
}
|
||||
|
||||
pub unsafe fn mmap_string_set_size(
|
||||
mut string: *mut MMAPString,
|
||||
mut len: size_t,
|
||||
) -> *mut MMAPString {
|
||||
if len >= (*string).allocated_len {
|
||||
if mmap_string_maybe_expand(string, len.wrapping_sub((*string).len)).is_null() {
|
||||
return 0 as *mut MMAPString;
|
||||
}
|
||||
}
|
||||
(*string).len = len;
|
||||
*(*string).str_0.offset(len as isize) = 0i32 as libc::c_char;
|
||||
return string;
|
||||
}
|
||||
|
||||
pub unsafe fn mmap_string_append_c(
|
||||
mut string: *mut MMAPString,
|
||||
mut c: libc::c_char,
|
||||
) -> *mut MMAPString {
|
||||
return mmap_string_insert_c(string, (*string).len, c);
|
||||
}
|
||||
|
||||
pub unsafe fn mmap_string_insert_c(
|
||||
mut string: *mut MMAPString,
|
||||
mut pos: size_t,
|
||||
mut c: libc::c_char,
|
||||
) -> *mut MMAPString {
|
||||
if mmap_string_maybe_expand(string, 1i32 as size_t).is_null() {
|
||||
return 0 as *mut MMAPString;
|
||||
}
|
||||
if pos < (*string).len {
|
||||
memmove(
|
||||
(*string).str_0.offset(pos as isize).offset(1isize) as *mut libc::c_void,
|
||||
(*string).str_0.offset(pos as isize) as *const libc::c_void,
|
||||
(*string).len.wrapping_sub(pos),
|
||||
);
|
||||
}
|
||||
*(*string).str_0.offset(pos as isize) = c;
|
||||
(*string).len =
|
||||
((*string).len as libc::size_t).wrapping_add(1i32 as libc::size_t) as size_t as size_t;
|
||||
*(*string).str_0.offset((*string).len as isize) = 0i32 as libc::c_char;
|
||||
return string;
|
||||
}
|
||||
|
||||
pub unsafe fn mmap_string_prepend(
|
||||
mut string: *mut MMAPString,
|
||||
mut val: *const libc::c_char,
|
||||
) -> *mut MMAPString {
|
||||
return mmap_string_insert_len(string, 0i32 as size_t, val, strlen(val));
|
||||
}
|
||||
|
||||
pub unsafe fn mmap_string_prepend_c(
|
||||
mut string: *mut MMAPString,
|
||||
mut c: libc::c_char,
|
||||
) -> *mut MMAPString {
|
||||
return mmap_string_insert_c(string, 0i32 as size_t, c);
|
||||
}
|
||||
|
||||
pub unsafe fn mmap_string_prepend_len(
|
||||
mut string: *mut MMAPString,
|
||||
mut val: *const libc::c_char,
|
||||
mut len: size_t,
|
||||
) -> *mut MMAPString {
|
||||
return mmap_string_insert_len(string, 0i32 as size_t, val, len);
|
||||
}
|
||||
|
||||
pub unsafe fn mmap_string_insert(
|
||||
mut string: *mut MMAPString,
|
||||
mut pos: size_t,
|
||||
mut val: *const libc::c_char,
|
||||
) -> *mut MMAPString {
|
||||
return mmap_string_insert_len(string, pos, val, strlen(val));
|
||||
}
|
||||
|
||||
pub unsafe fn mmap_string_erase(
|
||||
mut string: *mut MMAPString,
|
||||
mut pos: size_t,
|
||||
mut len: size_t,
|
||||
) -> *mut MMAPString {
|
||||
if pos.wrapping_add(len) < (*string).len {
|
||||
memmove(
|
||||
(*string).str_0.offset(pos as isize) as *mut libc::c_void,
|
||||
(*string).str_0.offset(pos as isize).offset(len as isize) as *const libc::c_void,
|
||||
(*string).len.wrapping_sub(pos.wrapping_add(len)),
|
||||
);
|
||||
}
|
||||
(*string).len = ((*string).len as libc::size_t).wrapping_sub(len) as size_t as size_t;
|
||||
*(*string).str_0.offset((*string).len as isize) = 0i32 as libc::c_char;
|
||||
return string;
|
||||
}
|
||||
|
||||
pub unsafe fn mmap_string_set_ceil(mut ceil: size_t) {
|
||||
mmap_string_ceil = ceil;
|
||||
}
|
||||
static mut mmap_string_ceil: size_t = (8i32 * 1024i32 * 1024i32) as size_t;
|
||||
|
||||
pub unsafe fn mmap_string_ref(mut string: *mut MMAPString) -> libc::c_int {
|
||||
let mut ht: *mut chash = 0 as *mut chash;
|
||||
let mut r: libc::c_int = 0;
|
||||
let mut key: chashdatum = chashdatum {
|
||||
data: 0 as *mut libc::c_void,
|
||||
len: 0,
|
||||
};
|
||||
let mut data: chashdatum = chashdatum {
|
||||
data: 0 as *mut libc::c_void,
|
||||
len: 0,
|
||||
};
|
||||
mmapstring_lock.lock().unwrap();
|
||||
if mmapstring_hashtable.is_null() {
|
||||
mmapstring_hashtable_init();
|
||||
}
|
||||
ht = mmapstring_hashtable;
|
||||
if ht.is_null() {
|
||||
return -1i32;
|
||||
}
|
||||
key.data = &mut (*string).str_0 as *mut *mut libc::c_char as *mut libc::c_void;
|
||||
key.len = ::std::mem::size_of::<*mut libc::c_char>() as libc::size_t as libc::c_uint;
|
||||
data.data = string as *mut libc::c_void;
|
||||
data.len = 0i32 as libc::c_uint;
|
||||
r = chash_set(
|
||||
mmapstring_hashtable,
|
||||
&mut key,
|
||||
&mut data,
|
||||
0 as *mut chashdatum,
|
||||
);
|
||||
|
||||
if r < 0i32 {
|
||||
return r;
|
||||
}
|
||||
return 0i32;
|
||||
}
|
||||
|
||||
static mut mmapstring_hashtable: *mut chash = 0 as *const chash as *mut chash;
|
||||
unsafe fn mmapstring_hashtable_init() {
|
||||
mmapstring_hashtable = chash_new(13i32 as libc::c_uint, 1i32);
|
||||
}
|
||||
|
||||
pub unsafe fn mmap_string_unref(mut str: *mut libc::c_char) -> libc::c_int {
|
||||
let mut string: *mut MMAPString = 0 as *mut MMAPString;
|
||||
let mut ht: *mut chash = 0 as *mut chash;
|
||||
let mut key: chashdatum = chashdatum {
|
||||
data: 0 as *mut libc::c_void,
|
||||
len: 0,
|
||||
};
|
||||
let mut data: chashdatum = chashdatum {
|
||||
data: 0 as *mut libc::c_void,
|
||||
len: 0,
|
||||
};
|
||||
let mut r: libc::c_int = 0;
|
||||
if str.is_null() {
|
||||
return -1i32;
|
||||
}
|
||||
mmapstring_lock.lock().unwrap();
|
||||
ht = mmapstring_hashtable;
|
||||
if ht.is_null() {
|
||||
return -1i32;
|
||||
}
|
||||
key.data = &mut str as *mut *mut libc::c_char as *mut libc::c_void;
|
||||
key.len = ::std::mem::size_of::<*mut libc::c_char>() as libc::size_t as libc::c_uint;
|
||||
r = chash_get(ht, &mut key, &mut data);
|
||||
if r < 0i32 {
|
||||
string = 0 as *mut MMAPString
|
||||
} else {
|
||||
string = data.data as *mut MMAPString
|
||||
}
|
||||
if !string.is_null() {
|
||||
chash_delete(ht, &mut key, 0 as *mut chashdatum);
|
||||
if chash_count(ht) == 0i32 as libc::c_uint {
|
||||
chash_free(ht);
|
||||
mmapstring_hashtable = 0 as *mut chash
|
||||
}
|
||||
}
|
||||
if !string.is_null() {
|
||||
mmap_string_free(string);
|
||||
return 0i32;
|
||||
} else {
|
||||
return -1i32;
|
||||
};
|
||||
}
|
||||
#[inline]
|
||||
unsafe fn chash_count(mut hash: *mut chash) -> libc::c_uint {
|
||||
return (*hash).count;
|
||||
}
|
||||
|
||||
pub unsafe fn mmapstring_init_lock() {}
|
||||
pub unsafe fn mmapstring_uninit_lock() {}
|
||||
1728
mmime/src/other.rs
1728
mmime/src/other.rs
File diff suppressed because it is too large
Load Diff
@@ -3,14 +3,12 @@
|
||||
//! Parse and create [Autocrypt-headers](https://autocrypt.org/en/latest/level1.html#the-autocrypt-header).
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::ffi::CStr;
|
||||
use std::str::FromStr;
|
||||
use std::{fmt, str};
|
||||
|
||||
use mmime::mailimf::types::*;
|
||||
|
||||
use crate::constants::*;
|
||||
use crate::contact::*;
|
||||
use crate::context::Context;
|
||||
use crate::key::*;
|
||||
|
||||
/// Possible values for encryption preference
|
||||
@@ -68,45 +66,31 @@ impl Aheader {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_imffields(wanted_from: &str, header: *const mailimf_fields) -> Option<Self> {
|
||||
if header.is_null() {
|
||||
return None;
|
||||
}
|
||||
pub fn from_headers(
|
||||
context: &Context,
|
||||
wanted_from: &str,
|
||||
headers: &[mailparse::MailHeader<'_>],
|
||||
) -> Option<Self> {
|
||||
use mailparse::MailHeaderMap;
|
||||
|
||||
let mut fine_header = None;
|
||||
let mut cur = unsafe { (*(*header).fld_list).first };
|
||||
|
||||
while !cur.is_null() {
|
||||
let field = unsafe { (*cur).data as *mut mailimf_field };
|
||||
if !field.is_null()
|
||||
&& unsafe { (*field).fld_type } == MAILIMF_FIELD_OPTIONAL_FIELD as libc::c_int
|
||||
{
|
||||
let optional_field = unsafe { (*field).fld_data.fld_optional_field };
|
||||
if !optional_field.is_null()
|
||||
&& unsafe { !(*optional_field).fld_name.is_null() }
|
||||
&& unsafe { CStr::from_ptr((*optional_field).fld_name).to_string_lossy() }
|
||||
== "Autocrypt"
|
||||
{
|
||||
let value =
|
||||
unsafe { CStr::from_ptr((*optional_field).fld_value).to_string_lossy() };
|
||||
|
||||
if let Ok(test) = Self::from_str(&value) {
|
||||
if addr_cmp(&test.addr, wanted_from) {
|
||||
if fine_header.is_none() {
|
||||
fine_header = Some(test);
|
||||
} else {
|
||||
// TODO: figure out what kind of error case this is
|
||||
return None;
|
||||
}
|
||||
}
|
||||
if let Ok(Some(value)) = headers.get_first_value("Autocrypt") {
|
||||
match Self::from_str(&value) {
|
||||
Ok(header) => {
|
||||
info!(context, "comparing {} - {}", header.addr, wanted_from);
|
||||
if addr_cmp(&header.addr, wanted_from) {
|
||||
return Some(header);
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
warn!(
|
||||
context,
|
||||
"found invalid autocrypt header {}: {:?}", value, err
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
cur = unsafe { (*cur).next };
|
||||
}
|
||||
|
||||
fine_header
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,12 +11,12 @@ use crate::config::*;
|
||||
use crate::constants::*;
|
||||
use crate::contact::*;
|
||||
use crate::context::Context;
|
||||
use crate::dc_mimeparser::SystemMessage;
|
||||
use crate::dc_tools::*;
|
||||
use crate::error::Error;
|
||||
use crate::events::Event;
|
||||
use crate::job::*;
|
||||
use crate::message::{self, InvalidMsgId, Message, MessageState, MsgId};
|
||||
use crate::mimeparser::SystemMessage;
|
||||
use crate::param::*;
|
||||
use crate::sql::{self, Sql};
|
||||
use crate::stock::StockMessage;
|
||||
|
||||
@@ -86,7 +86,7 @@ pub fn get_info() -> HashMap<&'static str, String> {
|
||||
);
|
||||
res.insert(
|
||||
"arch",
|
||||
(::std::mem::size_of::<*mut libc::c_void>())
|
||||
(std::mem::size_of::<*mut libc::c_void>())
|
||||
.wrapping_mul(8)
|
||||
.to_string(),
|
||||
);
|
||||
|
||||
1312
src/dc_mimeparser.rs
1312
src/dc_mimeparser.rs
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,30 +1,17 @@
|
||||
use itertools::Itertools;
|
||||
use std::borrow::Cow;
|
||||
use std::ffi::CString;
|
||||
use std::ptr;
|
||||
|
||||
use charset::Charset;
|
||||
use libc::free;
|
||||
use mmime::mailmime::decode::mailmime_encoded_phrase_parse;
|
||||
use mmime::other::*;
|
||||
use percent_encoding::{percent_decode, utf8_percent_encode, AsciiSet, CONTROLS};
|
||||
|
||||
use crate::dc_tools::*;
|
||||
|
||||
/**
|
||||
* Encode non-ascii-strings as `=?UTF-8?Q?Bj=c3=b6rn_Petersen?=`.
|
||||
* Belongs to RFC 2047: https://tools.ietf.org/html/rfc2047
|
||||
*
|
||||
* We do not fold at position 72; this would result in empty words as `=?utf-8?Q??=` which are correct,
|
||||
* but cannot be displayed by some mail programs (eg. Android Stock Mail).
|
||||
* however, this is not needed, as long as _one_ word is not longer than 72 characters.
|
||||
* _if_ it is, the display may get weird. This affects the subject only.
|
||||
* the best solution wor all this would be if libetpan encodes the line as only libetpan knowns when a header line is full.
|
||||
*
|
||||
* @param to_encode Null-terminated UTF-8-string to encode.
|
||||
* @return Returns the encoded string which must be free()'d when no longed needed.
|
||||
* On errors, NULL is returned.
|
||||
*/
|
||||
/// Encode non-ascii-strings as `=?UTF-8?Q?Bj=c3=b6rn_Petersen?=`.
|
||||
/// Belongs to RFC 2047: https://tools.ietf.org/html/rfc2047
|
||||
///
|
||||
/// We do not fold at position 72; this would result in empty words as `=?utf-8?Q??=` which are correct,
|
||||
/// but cannot be displayed by some mail programs (eg. Android Stock Mail).
|
||||
/// however, this is not needed, as long as _one_ word is not longer than 72 characters.
|
||||
/// _if_ it is, the display may get weird. This affects the subject only.
|
||||
/// the best solution wor all this would be if libetpan encodes the line as only libetpan knowns when a header line is full.
|
||||
///
|
||||
/// @param to_encode Null-terminated UTF-8-string to encode.
|
||||
/// @return Returns the encoded string which must be free()'d when no longed needed.
|
||||
/// On errors, NULL is returned.
|
||||
pub fn dc_encode_header_words(input: impl AsRef<str>) -> String {
|
||||
let mut result = String::default();
|
||||
for (_, group) in &input.as_ref().chars().group_by(|c| c.is_whitespace()) {
|
||||
@@ -68,31 +55,6 @@ fn quote_word(word: &[u8]) -> String {
|
||||
* Encode/decode header words, RFC 2047
|
||||
******************************************************************************/
|
||||
|
||||
pub(crate) fn dc_decode_header_words(input: &str) -> String {
|
||||
static FROM_ENCODING: &[u8] = b"iso-8859-1\x00";
|
||||
static TO_ENCODING: &[u8] = b"utf-8\x00";
|
||||
let mut out = ptr::null_mut();
|
||||
let mut cur_token = 0;
|
||||
let input_c = CString::yolo(input);
|
||||
unsafe {
|
||||
let r = mailmime_encoded_phrase_parse(
|
||||
FROM_ENCODING.as_ptr().cast(),
|
||||
input_c.as_ptr(),
|
||||
input.len(),
|
||||
&mut cur_token,
|
||||
TO_ENCODING.as_ptr().cast(),
|
||||
&mut out,
|
||||
);
|
||||
if r as u32 != MAILIMF_NO_ERROR || out.is_null() {
|
||||
input.to_string()
|
||||
} else {
|
||||
let res = to_string_lossy(out);
|
||||
free(out.cast());
|
||||
res
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dc_needs_ext_header(to_check: impl AsRef<str>) -> bool {
|
||||
let to_check = to_check.as_ref();
|
||||
|
||||
@@ -110,142 +72,3 @@ pub fn dc_needs_ext_header(to_check: impl AsRef<str>) -> bool {
|
||||
|| c == '%')
|
||||
})
|
||||
}
|
||||
|
||||
const EXT_ASCII_ST: &AsciiSet = &CONTROLS
|
||||
.add(b' ')
|
||||
.add(b'-')
|
||||
.add(b'_')
|
||||
.add(b'.')
|
||||
.add(b'~')
|
||||
.add(b'%');
|
||||
|
||||
/// Encode an UTF-8 string to the extended header format.
|
||||
pub fn dc_encode_ext_header(to_encode: impl AsRef<str>) -> String {
|
||||
let encoded = utf8_percent_encode(to_encode.as_ref(), &EXT_ASCII_ST);
|
||||
format!("utf-8''{}", encoded)
|
||||
}
|
||||
|
||||
/// Decode an extended-header-format strings to UTF-8.
|
||||
pub fn dc_decode_ext_header(to_decode: &[u8]) -> Cow<str> {
|
||||
if let Some(index) = bytes!(b'\'').find(to_decode) {
|
||||
let (charset, rest) = to_decode.split_at(index);
|
||||
if !charset.is_empty() {
|
||||
// skip language
|
||||
if let Some(index2) = bytes!(b'\'').find(&rest[1..]) {
|
||||
let decoded = percent_decode(&rest[index2 + 2..]);
|
||||
|
||||
if charset != b"utf-8" && charset != b"UTF-8" {
|
||||
if let Some(encoding) = Charset::for_label(charset) {
|
||||
let bytes = decoded.collect::<Vec<u8>>();
|
||||
let (res, _, _) = encoding.decode(&bytes);
|
||||
return Cow::Owned(res.into_owned());
|
||||
} else {
|
||||
return decoded.decode_utf8_lossy();
|
||||
}
|
||||
} else {
|
||||
return decoded.decode_utf8_lossy();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String::from_utf8_lossy(to_decode)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_dc_decode_header_words() {
|
||||
assert_eq!(
|
||||
dc_decode_header_words("=?utf-8?B?dGVzdMOkw7bDvC50eHQ=?="),
|
||||
std::string::String::from_utf8(b"test\xc3\xa4\xc3\xb6\xc3\xbc.txt".to_vec()).unwrap(),
|
||||
);
|
||||
|
||||
assert_eq!(dc_decode_header_words("just ascii test"), "just ascii test");
|
||||
|
||||
assert_eq!(dc_encode_header_words("abcdef"), "abcdef");
|
||||
|
||||
let r = dc_encode_header_words(
|
||||
std::string::String::from_utf8(b"test\xc3\xa4\xc3\xb6\xc3\xbc.txt".to_vec()).unwrap(),
|
||||
);
|
||||
assert!(r.starts_with("=?utf-8"));
|
||||
|
||||
assert_eq!(
|
||||
dc_decode_header_words(&r),
|
||||
std::string::String::from_utf8(b"test\xc3\xa4\xc3\xb6\xc3\xbc.txt".to_vec()).unwrap(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
dc_decode_header_words("=?ISO-8859-1?Q?attachment=3B=0D=0A_filename=3D?= =?ISO-8859-1?Q?=22test=E4=F6=FC=2Etxt=22=3B=0D=0A_size=3D39?="),
|
||||
std::string::String::from_utf8(b"attachment;\r\n filename=\"test\xc3\xa4\xc3\xb6\xc3\xbc.txt\";\r\n size=39".to_vec()).unwrap(),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dc_encode_ext_header() {
|
||||
let buf1 = dc_encode_ext_header("Björn Petersen");
|
||||
assert_eq!(&buf1, "utf-8\'\'Bj%C3%B6rn%20Petersen");
|
||||
let buf2 = dc_decode_ext_header(buf1.as_bytes());
|
||||
assert_eq!(&buf2, "Björn Petersen",);
|
||||
|
||||
let buf1 = dc_decode_ext_header(b"iso-8859-1\'en\'%A3%20rates");
|
||||
assert_eq!(buf1, "£ rates",);
|
||||
|
||||
let buf1 = dc_decode_ext_header(b"wrong\'format");
|
||||
assert_eq!(buf1, "wrong\'format",);
|
||||
|
||||
let buf1 = dc_decode_ext_header(b"\'\'");
|
||||
assert_eq!(buf1, "\'\'");
|
||||
|
||||
let buf1 = dc_decode_ext_header(b"x\'\'");
|
||||
assert_eq!(buf1, "");
|
||||
|
||||
let buf1 = dc_decode_ext_header(b"\'");
|
||||
assert_eq!(buf1, "\'");
|
||||
|
||||
let buf1 = dc_decode_ext_header(b"");
|
||||
assert_eq!(buf1, "");
|
||||
|
||||
// regressions
|
||||
assert_eq!(
|
||||
dc_decode_ext_header(dc_encode_ext_header("%0A").as_bytes()),
|
||||
"%0A"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dc_needs_ext_header() {
|
||||
assert_eq!(dc_needs_ext_header("Björn"), true);
|
||||
assert_eq!(dc_needs_ext_header("Bjoern"), false);
|
||||
assert_eq!(dc_needs_ext_header(""), false);
|
||||
assert_eq!(dc_needs_ext_header(" "), true);
|
||||
assert_eq!(dc_needs_ext_header("a b"), true);
|
||||
}
|
||||
|
||||
use proptest::prelude::*;
|
||||
|
||||
proptest! {
|
||||
#[test]
|
||||
fn test_ext_header_roundtrip(buf: String) {
|
||||
let encoded = dc_encode_ext_header(&buf);
|
||||
let decoded = dc_decode_ext_header(encoded.as_bytes());
|
||||
assert_eq!(buf, decoded);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ext_header_decode_anything(buf: Vec<u8>) {
|
||||
// make sure this never panics
|
||||
let _decoded = dc_decode_ext_header(&buf);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dc_header_roundtrip(input: String) {
|
||||
let encoded = dc_encode_header_words(&input);
|
||||
let decoded = dc_decode_header_words(&encoded);
|
||||
|
||||
assert_eq!(input, decoded);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
523
src/dc_tools.rs
523
src/dc_tools.rs
@@ -3,54 +3,22 @@
|
||||
|
||||
use core::cmp::{max, min};
|
||||
use std::borrow::Cow;
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::FromStr;
|
||||
use std::time::SystemTime;
|
||||
use std::{fmt, fs, ptr};
|
||||
use std::{fmt, fs};
|
||||
|
||||
use chrono::{Local, TimeZone};
|
||||
use libc::{memcpy, strlen};
|
||||
use mmime::clist::*;
|
||||
use mmime::mailimf::types::*;
|
||||
use rand::{thread_rng, Rng};
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::error::Error;
|
||||
use crate::events::Event;
|
||||
|
||||
pub(crate) fn dc_exactly_one_bit_set(v: libc::c_int) -> bool {
|
||||
pub(crate) fn dc_exactly_one_bit_set(v: i32) -> bool {
|
||||
0 != v && 0 == v & (v - 1)
|
||||
}
|
||||
|
||||
/// Duplicates a string
|
||||
///
|
||||
/// returns an empty string if NULL is given, never returns NULL (exits on errors)
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use deltachat::dc_tools::{dc_strdup, to_string_lossy};
|
||||
/// unsafe {
|
||||
/// let str_a = b"foobar\x00" as *const u8 as *const libc::c_char;
|
||||
/// let str_a_copy = dc_strdup(str_a);
|
||||
/// assert_eq!(to_string_lossy(str_a_copy), "foobar");
|
||||
/// assert_ne!(str_a, str_a_copy);
|
||||
/// }
|
||||
/// ```
|
||||
pub unsafe fn dc_strdup(s: *const libc::c_char) -> *mut libc::c_char {
|
||||
let ret: *mut libc::c_char;
|
||||
if !s.is_null() {
|
||||
ret = strdup(s);
|
||||
assert!(!ret.is_null());
|
||||
} else {
|
||||
ret = libc::calloc(1, 1) as *mut libc::c_char;
|
||||
assert!(!ret.is_null());
|
||||
}
|
||||
|
||||
ret
|
||||
}
|
||||
|
||||
/// Shortens a string to a specified length and adds "..." or "[...]" to the end of
|
||||
/// the shortened string.
|
||||
pub(crate) fn dc_truncate(buf: &str, approx_chars: usize, do_unwrap: bool) -> Cow<str> {
|
||||
@@ -74,36 +42,12 @@ pub(crate) fn dc_truncate(buf: &str, approx_chars: usize, do_unwrap: bool) -> Co
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn dc_str_from_clist(list: *const clist, delimiter: &str) -> String {
|
||||
let mut res = String::new();
|
||||
|
||||
if !list.is_null() {
|
||||
for rfc724_mid in unsafe { (*list).into_iter() } {
|
||||
if !res.is_empty() {
|
||||
res += delimiter;
|
||||
}
|
||||
res += &to_string_lossy(rfc724_mid as *const libc::c_char);
|
||||
}
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
pub(crate) fn dc_str_to_clist(str: &str, delimiter: &str) -> *mut clist {
|
||||
unsafe {
|
||||
let list: *mut clist = clist_new();
|
||||
for cur in str.split(&delimiter) {
|
||||
clist_insert_after(list, (*list).last, cur.strdup().cast());
|
||||
}
|
||||
list
|
||||
}
|
||||
}
|
||||
|
||||
/* the colors must fulfill some criterions as:
|
||||
- contrast to black and to white
|
||||
- work as a text-color
|
||||
- being noticeable on a typical map
|
||||
- harmonize together while being different enough
|
||||
(therefore, we cannot just use random rgb colors :) */
|
||||
/// the colors must fulfill some criterions as:
|
||||
/// - contrast to black and to white
|
||||
/// - work as a text-color
|
||||
/// - being noticeable on a typical map
|
||||
/// - harmonize together while being different enough
|
||||
/// (therefore, we cannot just use random rgb colors :)
|
||||
const COLORS: [u32; 16] = [
|
||||
0xe56555, 0xf28c48, 0x8e85ee, 0x76c84d, 0x5bb6cc, 0x549cdd, 0xd25c99, 0xb37800, 0xf23030,
|
||||
0x39b249, 0xbb243b, 0x964078, 0x66874f, 0x308ab9, 0x127ed0, 0xbe450c,
|
||||
@@ -122,33 +66,6 @@ pub(crate) fn dc_str_to_color(s: impl AsRef<str>) -> u32 {
|
||||
COLORS[color_index]
|
||||
}
|
||||
|
||||
/* date/time tools */
|
||||
/* the result is UTC or DC_INVALID_TIMESTAMP */
|
||||
pub(crate) fn dc_timestamp_from_date(date_time: *mut mailimf_date_time) -> i64 {
|
||||
assert!(!date_time.is_null());
|
||||
let dt = unsafe { *date_time };
|
||||
|
||||
let sec = dt.dt_sec;
|
||||
let min = dt.dt_min;
|
||||
let hour = dt.dt_hour;
|
||||
let day = dt.dt_day;
|
||||
let month = dt.dt_month;
|
||||
let year = dt.dt_year;
|
||||
|
||||
let ts = chrono::NaiveDateTime::new(
|
||||
chrono::NaiveDate::from_ymd(year, month as u32, day as u32),
|
||||
chrono::NaiveTime::from_hms(hour as u32, min as u32, sec as u32),
|
||||
);
|
||||
|
||||
let (zone_hour, zone_min) = if dt.dt_zone >= 0 {
|
||||
(dt.dt_zone / 100, dt.dt_zone % 100)
|
||||
} else {
|
||||
(-(-dt.dt_zone / 100), -(-dt.dt_zone % 100))
|
||||
};
|
||||
|
||||
ts.timestamp() - (zone_hour * 3600 + zone_min * 60) as i64
|
||||
}
|
||||
|
||||
/* ******************************************************************************
|
||||
* date/time tools
|
||||
******************************************************************************/
|
||||
@@ -318,22 +235,6 @@ pub(crate) fn dc_extract_grpid_from_rfc724_mid(mid: &str) -> Option<&str> {
|
||||
None
|
||||
}
|
||||
|
||||
pub(crate) fn dc_extract_grpid_from_rfc724_mid_list(list: *const clist) -> *mut libc::c_char {
|
||||
if !list.is_null() {
|
||||
unsafe {
|
||||
for cur in (*list).into_iter() {
|
||||
let mid = to_string_lossy(cur as *const libc::c_char);
|
||||
|
||||
if let Some(grpid) = dc_extract_grpid_from_rfc724_mid(&mid) {
|
||||
return grpid.strdup();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
pub(crate) fn dc_ensure_no_slash_safe(path: &str) -> &str {
|
||||
if path.ends_with('/') || path.ends_with('\\') {
|
||||
return &path[..path.len() - 1];
|
||||
@@ -601,212 +502,6 @@ pub(crate) fn dc_get_next_backup_path(
|
||||
bail!("could not create backup file, disk full?");
|
||||
}
|
||||
|
||||
/// Error type for the [OsStrExt] trait
|
||||
#[derive(Debug, Fail, PartialEq)]
|
||||
pub enum CStringError {
|
||||
/// The string contains an interior null byte
|
||||
#[fail(display = "String contains an interior null byte")]
|
||||
InteriorNullByte,
|
||||
/// The string is not valid Unicode
|
||||
#[fail(display = "String is not valid unicode")]
|
||||
NotUnicode,
|
||||
}
|
||||
|
||||
/// Extra convenience methods on [std::ffi::OsStr] to work with `*libc::c_char`.
|
||||
///
|
||||
/// The primary function of this trait is to more easily convert
|
||||
/// [OsStr], [OsString] or [Path] into pointers to C strings. This always
|
||||
/// allocates a new string since it is very common for the source
|
||||
/// string not to have the required terminal null byte.
|
||||
///
|
||||
/// It is implemented for `AsRef<std::ffi::OsStr>>` trait, which
|
||||
/// allows any type which implements this trait to transparently use
|
||||
/// this. This is how the conversion for [Path] works.
|
||||
///
|
||||
/// [OsStr]: std::ffi::OsStr
|
||||
/// [OsString]: std::ffi::OsString
|
||||
/// [Path]: std::path::Path
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use deltachat::dc_tools::{dc_strdup, OsStrExt};
|
||||
/// let path = std::path::Path::new("/some/path");
|
||||
/// let path_c = path.to_c_string().unwrap();
|
||||
/// unsafe {
|
||||
/// let mut c_ptr: *mut libc::c_char = dc_strdup(path_c.as_ptr());
|
||||
/// }
|
||||
/// ```
|
||||
pub trait OsStrExt {
|
||||
/// Convert a [std::ffi::OsStr] to an [std::ffi::CString]
|
||||
///
|
||||
/// This is useful to convert e.g. a [std::path::Path] to
|
||||
/// [*libc::c_char] by using
|
||||
/// [Path::as_os_str()](std::path::Path::as_os_str) and
|
||||
/// [CStr::as_ptr()](std::ffi::CStr::as_ptr).
|
||||
///
|
||||
/// This returns [CString] and not [&CStr] because not all [OsStr]
|
||||
/// slices end with a null byte, particularly those coming from
|
||||
/// [Path] do not have a null byte and having to handle this as
|
||||
/// the caller would defeat the point of this function.
|
||||
///
|
||||
/// On Windows this requires that the [OsStr] contains valid
|
||||
/// unicode, which should normally be the case for a [Path].
|
||||
///
|
||||
/// [CString]: std::ffi::CString
|
||||
/// [CStr]: std::ffi::CStr
|
||||
/// [OsStr]: std::ffi::OsStr
|
||||
/// [Path]: std::path::Path
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Since a C `*char` is terminated by a NULL byte this conversion
|
||||
/// will fail, when the [OsStr] has an interior null byte. The
|
||||
/// function will return
|
||||
/// `[Err]([CStringError::InteriorNullByte])`. When converting
|
||||
/// from a [Path] it should be safe to
|
||||
/// [`.unwrap()`](std::result::Result::unwrap) this anyway since a
|
||||
/// [Path] should not contain interior null bytes.
|
||||
///
|
||||
/// On windows when the string contains invalid Unicode
|
||||
/// `[Err]([CStringError::NotUnicode])` is returned.
|
||||
fn to_c_string(&self) -> Result<CString, CStringError>;
|
||||
}
|
||||
|
||||
impl<T: AsRef<std::ffi::OsStr>> OsStrExt for T {
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
fn to_c_string(&self) -> Result<CString, CStringError> {
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
CString::new(self.as_ref().as_bytes()).map_err(|err| match err {
|
||||
std::ffi::NulError { .. } => CStringError::InteriorNullByte,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn to_c_string(&self) -> Result<CString, CStringError> {
|
||||
os_str_to_c_string_unicode(&self)
|
||||
}
|
||||
}
|
||||
|
||||
// Implementation for os_str_to_c_string on windows.
|
||||
#[allow(dead_code)]
|
||||
fn os_str_to_c_string_unicode(
|
||||
os_str: &dyn AsRef<std::ffi::OsStr>,
|
||||
) -> Result<CString, CStringError> {
|
||||
match os_str.as_ref().to_str() {
|
||||
Some(val) => CString::new(val.as_bytes()).map_err(|err| match err {
|
||||
std::ffi::NulError { .. } => CStringError::InteriorNullByte,
|
||||
}),
|
||||
None => Err(CStringError::NotUnicode),
|
||||
}
|
||||
}
|
||||
|
||||
/// Convenience methods/associated functions for working with [CString]
|
||||
///
|
||||
/// This is helps transitioning from unsafe code.
|
||||
pub trait CStringExt {
|
||||
/// Create a new [CString], yolo style
|
||||
///
|
||||
/// This unwrap the result, panicking when there are embedded NULL
|
||||
/// bytes.
|
||||
fn yolo<T: Into<Vec<u8>>>(t: T) -> CString {
|
||||
CString::new(t).expect("String contains null byte, can not be CString")
|
||||
}
|
||||
}
|
||||
|
||||
impl CStringExt for CString {}
|
||||
|
||||
/// Convenience methods to make transitioning from raw C strings easier.
|
||||
///
|
||||
/// To interact with (legacy) C APIs we often need to convert from
|
||||
/// Rust strings to raw C strings. This can be clumsy to do correctly
|
||||
/// and the compiler sometimes allows it in an unsafe way. These
|
||||
/// methods make it more succinct and help you get it right.
|
||||
pub trait StrExt {
|
||||
/// Allocate a new raw C `*char` version of this string.
|
||||
///
|
||||
/// This allocates a new raw C string which must be freed using
|
||||
/// `free`. It takes care of some common pitfalls with using
|
||||
/// [CString.as_ptr].
|
||||
///
|
||||
/// [CString.as_ptr]: std::ffi::CString.as_ptr
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function will panic when the original string contains an
|
||||
/// interior null byte as this can not be represented in raw C
|
||||
/// strings.
|
||||
unsafe fn strdup(&self) -> *mut libc::c_char;
|
||||
}
|
||||
|
||||
impl<T: AsRef<str>> StrExt for T {
|
||||
unsafe fn strdup(&self) -> *mut libc::c_char {
|
||||
let tmp = CString::yolo(self.as_ref());
|
||||
dc_strdup(tmp.as_ptr())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_string_lossy(s: *const libc::c_char) -> String {
|
||||
if s.is_null() {
|
||||
return "".into();
|
||||
}
|
||||
|
||||
let cstr = unsafe { CStr::from_ptr(s) };
|
||||
|
||||
cstr.to_string_lossy().to_string()
|
||||
}
|
||||
|
||||
pub fn to_opt_string_lossy(s: *const libc::c_char) -> Option<String> {
|
||||
if s.is_null() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(to_string_lossy(s))
|
||||
}
|
||||
|
||||
/// Convert a C `*char` pointer to a [std::path::Path] slice.
|
||||
///
|
||||
/// This converts a `*libc::c_char` pointer to a [Path] slice. This
|
||||
/// essentially has to convert the pointer to [std::ffi::OsStr] to do
|
||||
/// so and thus is the inverse of [OsStrExt::to_c_string]. Just like
|
||||
/// [OsStrExt::to_c_string] requires valid Unicode on Windows, this
|
||||
/// requires that the pointer contains valid UTF-8 on Windows.
|
||||
///
|
||||
/// Because this returns a reference the [Path] silce can not outlive
|
||||
/// the original pointer.
|
||||
///
|
||||
/// [Path]: std::path::Path
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
pub fn as_path<'a>(s: *const libc::c_char) -> &'a std::path::Path {
|
||||
assert!(!s.is_null(), "cannot be used on null pointers");
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
unsafe {
|
||||
let c_str = std::ffi::CStr::from_ptr(s).to_bytes();
|
||||
let os_str = std::ffi::OsStr::from_bytes(c_str);
|
||||
std::path::Path::new(os_str)
|
||||
}
|
||||
}
|
||||
|
||||
// as_path() implementation for windows, documented above.
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn as_path<'a>(s: *const libc::c_char) -> &'a std::path::Path {
|
||||
as_path_unicode(s)
|
||||
}
|
||||
|
||||
// Implementation for as_path() on Windows.
|
||||
//
|
||||
// Having this as a separate function means it can be tested on unix
|
||||
// too.
|
||||
#[allow(dead_code)]
|
||||
fn as_path_unicode<'a>(s: *const libc::c_char) -> &'a std::path::Path {
|
||||
assert!(!s.is_null(), "cannot be used on null pointers");
|
||||
|
||||
let cstr = unsafe { CStr::from_ptr(s) };
|
||||
let str = cstr.to_str().unwrap_or_else(|err| panic!("{}", err));
|
||||
|
||||
std::path::Path::new(str)
|
||||
}
|
||||
|
||||
pub(crate) fn time() -> i64 {
|
||||
SystemTime::now()
|
||||
.duration_since(SystemTime::UNIX_EPOCH)
|
||||
@@ -884,71 +579,14 @@ pub(crate) fn listflags_has(listflags: u32, bitindex: usize) -> bool {
|
||||
(listflags & bitindex) == bitindex
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn strdup(s: *const libc::c_char) -> *mut libc::c_char {
|
||||
if s.is_null() {
|
||||
return std::ptr::null_mut();
|
||||
}
|
||||
|
||||
let slen = strlen(s);
|
||||
let result = libc::malloc(slen + 1);
|
||||
if result.is_null() {
|
||||
return std::ptr::null_mut();
|
||||
}
|
||||
|
||||
memcpy(result, s as *const _, slen + 1);
|
||||
result as *mut _
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn strcasecmp(s1: *const libc::c_char, s2: *const libc::c_char) -> libc::c_int {
|
||||
let s1 = std::ffi::CStr::from_ptr(s1)
|
||||
.to_string_lossy()
|
||||
.to_lowercase();
|
||||
let s2 = std::ffi::CStr::from_ptr(s2)
|
||||
.to_string_lossy()
|
||||
.to_lowercase();
|
||||
if s1 == s2 {
|
||||
0
|
||||
} else {
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use libc::{free, strcmp};
|
||||
use std::convert::TryInto;
|
||||
use std::ffi::CStr;
|
||||
|
||||
use crate::constants::*;
|
||||
use crate::test_utils::*;
|
||||
|
||||
#[test]
|
||||
fn test_dc_strdup() {
|
||||
unsafe {
|
||||
let str_a = b"foobar\x00" as *const u8 as *const libc::c_char;
|
||||
let str_a_copy = dc_strdup(str_a);
|
||||
|
||||
// Value of str_a_copy should equal foobar
|
||||
assert_eq!(
|
||||
CStr::from_ptr(str_a_copy),
|
||||
CString::new("foobar").unwrap().as_c_str()
|
||||
);
|
||||
// Address of str_a should be different from str_a_copy
|
||||
assert_ne!(str_a, str_a_copy);
|
||||
|
||||
let str_a = std::ptr::null() as *const libc::c_char;
|
||||
let str_a_copy = dc_strdup(str_a);
|
||||
// Value of str_a_copy should equal ""
|
||||
assert_eq!(
|
||||
CStr::from_ptr(str_a_copy),
|
||||
CString::new("").unwrap().as_c_str()
|
||||
);
|
||||
assert_ne!(str_a, str_a_copy);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rust_ftoa() {
|
||||
assert_eq!("1.22", format!("{}", 1.22));
|
||||
@@ -1009,44 +647,6 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
/* calls free() for each item content */
|
||||
unsafe fn clist_free_content(haystack: *const clist) {
|
||||
let mut iter = (*haystack).first;
|
||||
|
||||
while !iter.is_null() {
|
||||
free((*iter).data);
|
||||
(*iter).data = ptr::null_mut();
|
||||
iter = if !iter.is_null() {
|
||||
(*iter).next
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dc_str_to_clist_1() {
|
||||
unsafe {
|
||||
let list = dc_str_to_clist("", " ");
|
||||
assert_eq!((*list).count, 1);
|
||||
clist_free_content(list);
|
||||
clist_free(list);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dc_str_to_clist_4() {
|
||||
unsafe {
|
||||
let list: *mut clist = dc_str_to_clist("foo bar test", " ");
|
||||
assert_eq!((*list).count, 3);
|
||||
let str = dc_str_from_clist(list, " ");
|
||||
assert_eq!(str, "foo bar test");
|
||||
|
||||
clist_free_content(list);
|
||||
clist_free(list);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dc_create_id() {
|
||||
let buf = dc_create_id();
|
||||
@@ -1074,113 +674,6 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_os_str_to_c_string_cwd() {
|
||||
let some_dir = std::env::current_dir().unwrap();
|
||||
some_dir.as_os_str().to_c_string().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_os_str_to_c_string_unicode() {
|
||||
let some_str = String::from("/some/valid/utf8");
|
||||
let some_dir = std::path::Path::new(&some_str);
|
||||
assert_eq!(
|
||||
some_dir.as_os_str().to_c_string().unwrap(),
|
||||
CString::new("/some/valid/utf8").unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_os_str_to_c_string_nul() {
|
||||
let some_str = std::ffi::OsString::from("foo\x00bar");
|
||||
assert_eq!(
|
||||
some_str.to_c_string().err().unwrap(),
|
||||
CStringError::InteriorNullByte
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_path_to_c_string_cwd() {
|
||||
let some_dir = std::env::current_dir().unwrap();
|
||||
some_dir.to_c_string().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_path_to_c_string_unicode() {
|
||||
let some_str = String::from("/some/valid/utf8");
|
||||
let some_dir = std::path::Path::new(&some_str);
|
||||
assert_eq!(
|
||||
some_dir.as_os_str().to_c_string().unwrap(),
|
||||
CString::new("/some/valid/utf8").unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_os_str_to_c_string_unicode_fn() {
|
||||
let some_str = std::ffi::OsString::from("foo");
|
||||
assert_eq!(
|
||||
os_str_to_c_string_unicode(&some_str).unwrap(),
|
||||
CString::new("foo").unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_path_to_c_string_unicode_fn() {
|
||||
let some_str = String::from("/some/path");
|
||||
let some_path = std::path::Path::new(&some_str);
|
||||
assert_eq!(
|
||||
os_str_to_c_string_unicode(&some_path).unwrap(),
|
||||
CString::new("/some/path").unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_os_str_to_c_string_unicode_fn_nul() {
|
||||
let some_str = std::ffi::OsString::from("fooz\x00bar");
|
||||
assert_eq!(
|
||||
os_str_to_c_string_unicode(&some_str).err().unwrap(),
|
||||
CStringError::InteriorNullByte
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_as_path() {
|
||||
let some_path = CString::new("/some/path").unwrap();
|
||||
let ptr = some_path.as_ptr();
|
||||
assert_eq!(as_path(ptr), std::ffi::OsString::from("/some/path"))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_as_path_unicode_fn() {
|
||||
let some_path = CString::new("/some/path").unwrap();
|
||||
let ptr = some_path.as_ptr();
|
||||
assert_eq!(as_path_unicode(ptr), std::ffi::OsString::from("/some/path"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cstring_yolo() {
|
||||
assert_eq!(CString::new("hello").unwrap(), CString::yolo("hello"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_strdup_str() {
|
||||
unsafe {
|
||||
let s = "hello".strdup();
|
||||
let cmp = strcmp(s, b"hello\x00" as *const u8 as *const libc::c_char);
|
||||
free(s as *mut libc::c_void);
|
||||
assert_eq!(cmp, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_strdup_string() {
|
||||
unsafe {
|
||||
let s = String::from("hello").strdup();
|
||||
let cmp = strcmp(s, b"hello\x00" as *const u8 as *const libc::c_char);
|
||||
free(s as *mut libc::c_void);
|
||||
assert_eq!(cmp, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dc_extract_grpid_from_rfc724_mid() {
|
||||
// Should return None if we pass invalid mid
|
||||
|
||||
572
src/e2ee.rs
572
src/e2ee.rs
@@ -1,41 +1,20 @@
|
||||
//! End-to-end encryption support.
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::ptr;
|
||||
use std::str::FromStr;
|
||||
|
||||
use libc::strlen;
|
||||
use mmime::clist::*;
|
||||
use mmime::mailimf::types::*;
|
||||
use mmime::mailimf::types_helper::*;
|
||||
use mmime::mailimf::*;
|
||||
use mmime::mailmime::content::*;
|
||||
use mmime::mailmime::types::*;
|
||||
use mmime::mailmime::types_helper::*;
|
||||
use mmime::mailmime::write_mem::*;
|
||||
use mmime::mailmime::*;
|
||||
use mmime::mailprivacy_prepare_mime;
|
||||
use mmime::mmapstring::*;
|
||||
use mmime::{mailmime_substitute, MAILIMF_NO_ERROR, MAIL_NO_ERROR};
|
||||
use mailparse::MailHeaderMap;
|
||||
use num_traits::FromPrimitive;
|
||||
|
||||
use crate::aheader::*;
|
||||
use crate::config::Config;
|
||||
use crate::context::Context;
|
||||
use crate::dc_tools::*;
|
||||
use crate::error::*;
|
||||
use crate::key::*;
|
||||
use crate::keyring::*;
|
||||
use crate::mimefactory::MimeFactory;
|
||||
use crate::peerstate::*;
|
||||
use crate::pgp;
|
||||
use crate::securejoin::handle_degrade_event;
|
||||
use crate::wrapmime;
|
||||
use crate::wrapmime::*;
|
||||
|
||||
// standard mime-version header aka b"Version: 1\r\n\x00"
|
||||
static mut VERSION_CONTENT: [libc::c_char; 13] =
|
||||
[86, 101, 114, 115, 105, 111, 110, 58, 32, 49, 13, 10, 0];
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct EncryptHelper {
|
||||
@@ -71,39 +50,27 @@ impl EncryptHelper {
|
||||
Aheader::new(addr, pk, self.prefer_encrypt)
|
||||
}
|
||||
|
||||
pub fn try_encrypt(
|
||||
&mut self,
|
||||
factory: &mut MimeFactory,
|
||||
/// Determines if we can and should encrypt.
|
||||
pub fn should_encrypt(
|
||||
&self,
|
||||
context: &Context,
|
||||
e2ee_guaranteed: bool,
|
||||
min_verified: PeerstateVerifiedStatus,
|
||||
do_gossip: bool,
|
||||
mut in_out_message: *mut Mailmime,
|
||||
imffields_unprotected: *mut mailimf_fields,
|
||||
peerstates: &[(Option<Peerstate>, &str)],
|
||||
) -> Result<bool> {
|
||||
// libEtPan's pgp_encrypt_mime() takes the parent as the new root.
|
||||
// We just expect the root as being given to this function.
|
||||
ensure!(
|
||||
!in_out_message.is_null() && unsafe { (*in_out_message).mm_parent.is_null() },
|
||||
"corrupted inputs"
|
||||
);
|
||||
|
||||
if !(self.prefer_encrypt == EncryptPreference::Mutual || e2ee_guaranteed) {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
let context = &factory.context;
|
||||
let mut keyring = Keyring::default();
|
||||
let mut gossip_headers: Vec<String> = Vec::with_capacity(factory.recipients_addr.len());
|
||||
|
||||
// determine if we can and should encrypt
|
||||
for recipient_addr in factory.recipients_addr.iter() {
|
||||
if recipient_addr == &self.addr {
|
||||
continue;
|
||||
}
|
||||
let peerstate = match Peerstate::from_addr(context, &context.sql, recipient_addr) {
|
||||
Some(peerstate) => peerstate,
|
||||
for (peerstate, addr) in peerstates {
|
||||
match peerstate {
|
||||
Some(peerstate) => {
|
||||
if peerstate.prefer_encrypt != EncryptPreference::Mutual && !e2ee_guaranteed {
|
||||
info!(context, "peerstate for {:?} is no-encrypt", addr);
|
||||
return Ok(false);
|
||||
}
|
||||
}
|
||||
None => {
|
||||
let msg = format!("peerstate for {} missing, cannot encrypt", recipient_addr);
|
||||
let msg = format!("peerstate for {:?} missing, cannot encrypt", addr);
|
||||
if e2ee_guaranteed {
|
||||
return Err(format_err!("{}", msg));
|
||||
} else {
|
||||
@@ -111,169 +78,62 @@ impl EncryptHelper {
|
||||
return Ok(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if peerstate.prefer_encrypt != EncryptPreference::Mutual && !e2ee_guaranteed {
|
||||
info!(context, "peerstate for {} is no-encrypt", recipient_addr);
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
if let Some(key) = peerstate.peek_key(min_verified) {
|
||||
keyring.add_owned(key.clone());
|
||||
if do_gossip {
|
||||
if let Some(header) = peerstate.render_gossip_header(min_verified) {
|
||||
gossip_headers.push(header.to_string());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
bail!(
|
||||
"proper enc-key for {} missing, cannot encrypt",
|
||||
recipient_addr
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let sign_key = {
|
||||
keyring.add_ref(&self.public_key);
|
||||
let key = Key::from_self_private(context, self.addr.clone(), &context.sql);
|
||||
ensure!(key.is_some(), "no own private key found");
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
key
|
||||
};
|
||||
/// Tries to encrypt the passed in `mail`.
|
||||
pub fn encrypt(
|
||||
&mut self,
|
||||
context: &Context,
|
||||
min_verified: PeerstateVerifiedStatus,
|
||||
mail_to_encrypt: lettre_email::PartBuilder,
|
||||
peerstates: &[(Option<Peerstate>, &str)],
|
||||
) -> Result<String> {
|
||||
let mut keyring = Keyring::default();
|
||||
|
||||
// encrypt message
|
||||
unsafe {
|
||||
mailprivacy_prepare_mime(in_out_message);
|
||||
let mut part_to_encrypt = (*in_out_message).mm_data.mm_message.mm_msg_mime;
|
||||
(*part_to_encrypt).mm_parent = ptr::null_mut();
|
||||
let imffields_encrypted = mailimf_fields_new_empty();
|
||||
|
||||
// mailmime_new_message_data() calls mailmime_fields_new_with_version()
|
||||
// which would add the unwanted MIME-Version:-header
|
||||
let message_to_encrypt = mailmime_new_simple(
|
||||
MAILMIME_MESSAGE as libc::c_int,
|
||||
mailmime_fields_new_empty(),
|
||||
mailmime_get_content_message(),
|
||||
imffields_encrypted,
|
||||
part_to_encrypt,
|
||||
);
|
||||
|
||||
for header in &gossip_headers {
|
||||
wrapmime::new_custom_field(imffields_encrypted, "Autocrypt-Gossip", &header)
|
||||
}
|
||||
|
||||
// memoryhole headers: move some headers into encrypted part
|
||||
// XXX note we can't use clist's into_iter() because the loop body also removes items
|
||||
let mut cur = (*(*imffields_unprotected).fld_list).first;
|
||||
while !cur.is_null() {
|
||||
let field = (*cur).data as *mut mailimf_field;
|
||||
let mut move_to_encrypted = false;
|
||||
|
||||
if !field.is_null() {
|
||||
if (*field).fld_type == MAILIMF_FIELD_SUBJECT as libc::c_int {
|
||||
move_to_encrypted = true;
|
||||
} else if (*field).fld_type == MAILIMF_FIELD_OPTIONAL_FIELD as libc::c_int {
|
||||
let opt_field = (*field).fld_data.fld_optional_field;
|
||||
if !opt_field.is_null() && !(*opt_field).fld_name.is_null() {
|
||||
let fld_name = to_string_lossy((*opt_field).fld_name);
|
||||
if fld_name.starts_with("Secure-Join")
|
||||
|| (fld_name.starts_with("Chat-") && fld_name != "Chat-Version")
|
||||
{
|
||||
move_to_encrypted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if move_to_encrypted {
|
||||
mailimf_fields_add(imffields_encrypted, field);
|
||||
cur = clist_delete((*imffields_unprotected).fld_list, cur);
|
||||
} else {
|
||||
cur = (*cur).next;
|
||||
}
|
||||
}
|
||||
|
||||
let subject = mailimf_subject_new("...".strdup());
|
||||
mailimf_fields_add(imffields_unprotected, mailimf_field_new_subject(subject));
|
||||
|
||||
wrapmime::append_ct_param(
|
||||
(*part_to_encrypt).mm_content_type,
|
||||
"protected-headers",
|
||||
"v1",
|
||||
)?;
|
||||
let plain = mmap_string_new(b"\x00" as *const u8 as *const libc::c_char);
|
||||
let mut col = 0;
|
||||
mailmime_write_mem(plain, &mut col, message_to_encrypt);
|
||||
mailmime_free(message_to_encrypt);
|
||||
|
||||
ensure!(
|
||||
!(*plain).str_0.is_null() && (*plain).len > 0,
|
||||
"could not write/allocate"
|
||||
);
|
||||
|
||||
let ctext = pgp::pk_encrypt(
|
||||
std::slice::from_raw_parts((*plain).str_0 as *const u8, (*plain).len),
|
||||
&keyring,
|
||||
sign_key.as_ref(),
|
||||
);
|
||||
mmap_string_free(plain);
|
||||
|
||||
let ctext_v = ctext?;
|
||||
|
||||
// create MIME-structure that will contain the encrypted text
|
||||
let mut encrypted_part = new_data_part(
|
||||
ptr::null_mut(),
|
||||
0 as libc::size_t,
|
||||
"multipart/encrypted",
|
||||
MAILMIME_MECHANISM_BASE64,
|
||||
)?;
|
||||
let content = (*encrypted_part).mm_content_type;
|
||||
wrapmime::append_ct_param(content, "protocol", "application/pgp-encrypted")?;
|
||||
|
||||
let version_mime = new_data_part(
|
||||
VERSION_CONTENT.as_mut_ptr() as *mut libc::c_void,
|
||||
strlen(VERSION_CONTENT.as_mut_ptr()),
|
||||
"application/pgp-encrypted",
|
||||
MAILMIME_MECHANISM_7BIT,
|
||||
)?;
|
||||
mailmime_smart_add_part(encrypted_part, version_mime);
|
||||
|
||||
// we assume that ctext_v is not dropped until the end
|
||||
// of this if-scope
|
||||
let ctext_part = new_data_part(
|
||||
ctext_v.as_ptr() as *mut libc::c_void,
|
||||
ctext_v.len(),
|
||||
"application/octet-stream",
|
||||
MAILMIME_MECHANISM_7BIT,
|
||||
)?;
|
||||
|
||||
mailmime_smart_add_part(encrypted_part, ctext_part);
|
||||
(*in_out_message).mm_data.mm_message.mm_msg_mime = encrypted_part;
|
||||
(*encrypted_part).mm_parent = in_out_message;
|
||||
let gossiped = !&gossip_headers.is_empty();
|
||||
factory.finalize_mime_message(in_out_message, true, gossiped)?;
|
||||
|
||||
Ok(true)
|
||||
for (peerstate, addr) in peerstates
|
||||
.iter()
|
||||
.filter_map(|(state, addr)| state.as_ref().map(|s| (s, addr)))
|
||||
{
|
||||
info!(context, "adding for {}: {:?}", addr, peerstate);
|
||||
let key = peerstate.peek_key(min_verified).ok_or_else(|| {
|
||||
format_err!("proper enc-key for {} missing, cannot encrypt", addr)
|
||||
})?;
|
||||
keyring.add_ref(key);
|
||||
}
|
||||
|
||||
keyring.add_ref(&self.public_key);
|
||||
let sign_key = Key::from_self_private(context, self.addr.clone(), &context.sql)
|
||||
.ok_or_else(|| format_err!("missing own private key"))?;
|
||||
|
||||
let raw_message = mail_to_encrypt.build().as_string().into_bytes();
|
||||
|
||||
let ctext = pgp::pk_encrypt(&raw_message, &keyring, Some(&sign_key))?;
|
||||
|
||||
Ok(ctext)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_decrypt(
|
||||
context: &Context,
|
||||
in_out_message: *mut Mailmime,
|
||||
) -> Result<(bool, HashSet<String>, HashSet<String>)> {
|
||||
// just a pointer into mailmime structure, must not be freed
|
||||
let imffields = mailmime_find_mailimf_fields(in_out_message);
|
||||
ensure!(
|
||||
!in_out_message.is_null() && !imffields.is_null(),
|
||||
"corrupt invalid mime inputs"
|
||||
);
|
||||
mail: &mailparse::ParsedMail<'_>,
|
||||
message_time: i64,
|
||||
) -> Result<(Option<Vec<u8>>, HashSet<String>)> {
|
||||
info!(context, "trying to decrypt");
|
||||
|
||||
let from = wrapmime::get_field_from(imffields)?;
|
||||
let message_time = wrapmime::get_field_date(imffields)?;
|
||||
let from = mail
|
||||
.headers
|
||||
.get_first_value("From")?
|
||||
.and_then(|from_addr| mailparse::addrparse(&from_addr).ok())
|
||||
.and_then(|from| from.extract_single_info())
|
||||
.map(|from| from.addr)
|
||||
.unwrap_or_default();
|
||||
|
||||
let mut peerstate = None;
|
||||
let autocryptheader = Aheader::from_imffields(&from, imffields);
|
||||
let autocryptheader = Aheader::from_headers(context, &from, &mail.headers);
|
||||
|
||||
if message_time > 0 {
|
||||
peerstate = Peerstate::from_addr(context, &context.sql, &from);
|
||||
@@ -282,9 +142,7 @@ pub fn try_decrypt(
|
||||
if let Some(ref header) = autocryptheader {
|
||||
peerstate.apply_header(&header, message_time);
|
||||
peerstate.save_to_db(&context.sql, false)?;
|
||||
} else if message_time > peerstate.last_seen_autocrypt
|
||||
&& !contains_report(in_out_message)
|
||||
{
|
||||
} else if message_time > peerstate.last_seen_autocrypt && !contains_report(mail) {
|
||||
peerstate.degrade_encryption(message_time);
|
||||
peerstate.save_to_db(&context.sql, false)?;
|
||||
}
|
||||
@@ -294,13 +152,12 @@ pub fn try_decrypt(
|
||||
peerstate = Some(p);
|
||||
}
|
||||
}
|
||||
|
||||
/* possibly perform decryption */
|
||||
let mut private_keyring = Keyring::default();
|
||||
let mut public_keyring_for_validate = Keyring::default();
|
||||
let mut encrypted = false;
|
||||
let mut out_mail = None;
|
||||
let mut signatures = HashSet::default();
|
||||
let mut gossipped_addr = HashSet::default();
|
||||
|
||||
let self_addr = context.get_config(Config::ConfiguredAddr);
|
||||
|
||||
if let Some(self_addr) = self_addr {
|
||||
@@ -320,60 +177,16 @@ pub fn try_decrypt(
|
||||
}
|
||||
}
|
||||
|
||||
let mut gossip_headers = ptr::null_mut();
|
||||
encrypted = decrypt_if_autocrypt_message(
|
||||
out_mail = decrypt_if_autocrypt_message(
|
||||
context,
|
||||
in_out_message,
|
||||
mail,
|
||||
&private_keyring,
|
||||
&public_keyring_for_validate,
|
||||
&mut signatures,
|
||||
&mut gossip_headers,
|
||||
)?;
|
||||
if !gossip_headers.is_null() {
|
||||
gossipped_addr =
|
||||
update_gossip_peerstates(context, message_time, imffields, gossip_headers)?;
|
||||
unsafe { mailimf_fields_free(gossip_headers) };
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok((encrypted, signatures, gossipped_addr))
|
||||
}
|
||||
|
||||
fn new_data_part(
|
||||
data: *mut libc::c_void,
|
||||
data_bytes: libc::size_t,
|
||||
content_type: &str,
|
||||
default_encoding: u32,
|
||||
) -> Result<*mut Mailmime> {
|
||||
let content = new_content_type(&content_type)?;
|
||||
let mut encoding = ptr::null_mut();
|
||||
if wrapmime::content_type_needs_encoding(content) {
|
||||
encoding = unsafe { mailmime_mechanism_new(default_encoding as i32, ptr::null_mut()) };
|
||||
ensure!(!encoding.is_null(), "failed to create encoding");
|
||||
}
|
||||
let mime_fields = {
|
||||
unsafe {
|
||||
mailmime_fields_new_with_data(
|
||||
encoding,
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
)
|
||||
}
|
||||
};
|
||||
ensure!(!mime_fields.is_null(), "internal mime error");
|
||||
|
||||
let mime = unsafe { mailmime_new_empty(content, mime_fields) };
|
||||
ensure!(!mime.is_null(), "internal mime error");
|
||||
|
||||
if unsafe { (*mime).mm_type } == MAILMIME_SINGLE as libc::c_int {
|
||||
if !data.is_null() && data_bytes > 0 {
|
||||
unsafe { mailmime_set_body_text(mime, data as *mut libc::c_char, data_bytes) };
|
||||
}
|
||||
}
|
||||
|
||||
Ok(mime)
|
||||
Ok((out_mail, signatures))
|
||||
}
|
||||
|
||||
/// Load public key from database or generate a new one.
|
||||
@@ -423,204 +236,65 @@ fn load_or_generate_self_public_key(context: &Context, self_addr: impl AsRef<str
|
||||
}
|
||||
}
|
||||
|
||||
fn update_gossip_peerstates(
|
||||
fn decrypt_if_autocrypt_message<'a>(
|
||||
context: &Context,
|
||||
message_time: i64,
|
||||
imffields: *mut mailimf_fields,
|
||||
gossip_headers: *const mailimf_fields,
|
||||
) -> Result<HashSet<String>> {
|
||||
// XXX split the parsing from the modification part
|
||||
let mut recipients: Option<HashSet<String>> = None;
|
||||
let mut gossipped_addr: HashSet<String> = Default::default();
|
||||
|
||||
for cur_data in unsafe { (*(*gossip_headers).fld_list).into_iter() } {
|
||||
let field = cur_data as *mut mailimf_field;
|
||||
if field.is_null() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let field = unsafe { *field };
|
||||
|
||||
if field.fld_type == MAILIMF_FIELD_OPTIONAL_FIELD as libc::c_int {
|
||||
let optional_field = unsafe { field.fld_data.fld_optional_field };
|
||||
if optional_field.is_null() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let optional_field = unsafe { *optional_field };
|
||||
if !optional_field.fld_name.is_null()
|
||||
&& to_string_lossy(optional_field.fld_name) == "Autocrypt-Gossip"
|
||||
{
|
||||
let value = to_string_lossy(optional_field.fld_value);
|
||||
let gossip_header = Aheader::from_str(&value);
|
||||
|
||||
if let Ok(ref header) = gossip_header {
|
||||
if recipients.is_none() {
|
||||
recipients = Some(mailimf_get_recipients(imffields));
|
||||
}
|
||||
if recipients.as_ref().unwrap().contains(&header.addr) {
|
||||
let mut peerstate =
|
||||
Peerstate::from_addr(context, &context.sql, &header.addr);
|
||||
if let Some(ref mut peerstate) = peerstate {
|
||||
peerstate.apply_gossip(header, message_time);
|
||||
peerstate.save_to_db(&context.sql, false)?;
|
||||
} else {
|
||||
let p = Peerstate::from_gossip(context, header, message_time);
|
||||
p.save_to_db(&context.sql, true)?;
|
||||
peerstate = Some(p);
|
||||
}
|
||||
if let Some(peerstate) = peerstate {
|
||||
if peerstate.degrade_event.is_some() {
|
||||
handle_degrade_event(context, &peerstate)?;
|
||||
}
|
||||
}
|
||||
|
||||
gossipped_addr.insert(header.addr.clone());
|
||||
} else {
|
||||
info!(
|
||||
context,
|
||||
"Ignoring gossipped \"{}\" as the address is not in To/Cc list.",
|
||||
&header.addr,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(gossipped_addr)
|
||||
}
|
||||
|
||||
fn decrypt_if_autocrypt_message(
|
||||
context: &Context,
|
||||
mime_undetermined: *mut Mailmime,
|
||||
mail: &mailparse::ParsedMail<'a>,
|
||||
private_keyring: &Keyring,
|
||||
public_keyring_for_validate: &Keyring,
|
||||
ret_valid_signatures: &mut HashSet<String>,
|
||||
ret_gossip_headers: *mut *mut mailimf_fields,
|
||||
) -> Result<bool> {
|
||||
/* The returned bool is true if we detected an Autocrypt-encrypted
|
||||
message and successfully decrypted it. Decryption then modifies the
|
||||
passed in mime structure in place. The returned bool is false
|
||||
if it was not an Autocrypt message.
|
||||
) -> Result<Option<Vec<u8>>> {
|
||||
// The returned bool is true if we detected an Autocrypt-encrypted
|
||||
// message and successfully decrypted it. Decryption then modifies the
|
||||
// passed in mime structure in place. The returned bool is false
|
||||
// if it was not an Autocrypt message.
|
||||
//
|
||||
// Errors are returned for failures related to decryption of AC-messages.
|
||||
|
||||
Errors are returned for failures related to decryption of AC-messages.
|
||||
*/
|
||||
ensure!(!mime_undetermined.is_null(), "Invalid mime reference");
|
||||
|
||||
let (mime, encrypted_data_part) = match wrapmime::get_autocrypt_mime(mime_undetermined) {
|
||||
Err(_) => {
|
||||
let encrypted_data_part = match wrapmime::get_autocrypt_mime(mail) {
|
||||
Err(err) => {
|
||||
// not a proper autocrypt message, abort and ignore
|
||||
return Ok(false);
|
||||
warn!(context, "Invalid autocrypt message: {:?}", err);
|
||||
return Ok(None);
|
||||
}
|
||||
Ok(res) => res,
|
||||
};
|
||||
|
||||
let decrypted_mime = decrypt_part(
|
||||
decrypt_part(
|
||||
context,
|
||||
encrypted_data_part,
|
||||
private_keyring,
|
||||
public_keyring_for_validate,
|
||||
ret_valid_signatures,
|
||||
)?;
|
||||
// decrypted_mime is a dangling pointer which we now put into mailmime's Ownership
|
||||
unsafe {
|
||||
mailmime_substitute(mime, decrypted_mime);
|
||||
mailmime_free(mime);
|
||||
}
|
||||
|
||||
// finally, let's also return gossip headers
|
||||
// XXX better return parsed headers so that upstream
|
||||
// does not need to dive into mmime-stuff again.
|
||||
unsafe {
|
||||
if (*ret_gossip_headers).is_null() && !ret_valid_signatures.is_empty() {
|
||||
let mut dummy: libc::size_t = 0;
|
||||
let mut test: *mut mailimf_fields = ptr::null_mut();
|
||||
if mailimf_envelope_and_optional_fields_parse(
|
||||
(*decrypted_mime).mm_mime_start,
|
||||
(*decrypted_mime).mm_length,
|
||||
&mut dummy,
|
||||
&mut test,
|
||||
) == MAILIMF_NO_ERROR as libc::c_int
|
||||
&& !test.is_null()
|
||||
{
|
||||
*ret_gossip_headers = test;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(true)
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns Ok(None) if nothing encrypted was found.
|
||||
fn decrypt_part(
|
||||
_context: &Context,
|
||||
mime: *mut Mailmime,
|
||||
context: &Context,
|
||||
mail: &mailparse::ParsedMail<'_>,
|
||||
private_keyring: &Keyring,
|
||||
public_keyring_for_validate: &Keyring,
|
||||
ret_valid_signatures: &mut HashSet<String>,
|
||||
) -> Result<*mut Mailmime> {
|
||||
let mime_data: *mut mailmime_data;
|
||||
let mut mime_transfer_encoding = MAILMIME_MECHANISM_BINARY as libc::c_int;
|
||||
|
||||
unsafe {
|
||||
mime_data = (*mime).mm_data.mm_single;
|
||||
}
|
||||
if !wrapmime::has_decryptable_data(mime_data) {
|
||||
return Ok(ptr::null_mut());
|
||||
}
|
||||
|
||||
if let Some(enc) = wrapmime::get_mime_transfer_encoding(mime) {
|
||||
mime_transfer_encoding = enc;
|
||||
}
|
||||
|
||||
let data: Vec<u8> = wrapmime::decode_dt_data(mime_data, mime_transfer_encoding)?;
|
||||
|
||||
let mut ret_decrypted_mime = ptr::null_mut();
|
||||
) -> Result<Option<Vec<u8>>> {
|
||||
info!(context, "decrypting part");
|
||||
let data = mail.get_body_raw()?;
|
||||
|
||||
if has_decrypted_pgp_armor(&data) {
|
||||
// we should only have one decryption happening
|
||||
ensure!(ret_valid_signatures.is_empty(), "corrupt signatures");
|
||||
|
||||
let plain = match pgp::pk_decrypt(
|
||||
let plain = pgp::pk_decrypt(
|
||||
&data,
|
||||
&private_keyring,
|
||||
&public_keyring_for_validate,
|
||||
Some(ret_valid_signatures),
|
||||
) {
|
||||
Ok(plain) => {
|
||||
ensure!(!ret_valid_signatures.is_empty(), "no valid signatures");
|
||||
plain
|
||||
}
|
||||
Err(err) => bail!("could not decrypt: {}", err),
|
||||
};
|
||||
let plain_bytes = plain.len();
|
||||
let plain_buf = plain.as_ptr() as *const libc::c_char;
|
||||
)?;
|
||||
|
||||
let mut index = 0;
|
||||
let mut decrypted_mime = ptr::null_mut();
|
||||
if unsafe {
|
||||
mailmime_parse(
|
||||
plain_buf as *const _,
|
||||
plain_bytes,
|
||||
&mut index,
|
||||
&mut decrypted_mime,
|
||||
)
|
||||
} != MAIL_NO_ERROR as libc::c_int
|
||||
|| decrypted_mime.is_null()
|
||||
{
|
||||
if !decrypted_mime.is_null() {
|
||||
unsafe { mailmime_free(decrypted_mime) };
|
||||
}
|
||||
} else {
|
||||
// decrypted_mime points into `plain`.
|
||||
// FIXME(@dignifiedquire): this still leaks memory I believe, as mailmime_free
|
||||
// does not free the underlying buffer. But for now we have to live with it
|
||||
std::mem::forget(plain);
|
||||
ret_decrypted_mime = decrypted_mime;
|
||||
}
|
||||
ensure!(!ret_valid_signatures.is_empty(), "no valid signatures");
|
||||
return Ok(Some(plain));
|
||||
}
|
||||
|
||||
Ok(ret_decrypted_mime)
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn has_decrypted_pgp_armor(input: &[u8]) -> bool {
|
||||
@@ -644,36 +318,8 @@ fn has_decrypted_pgp_armor(input: &[u8]) -> bool {
|
||||
/// However, Delta Chat itself has no problem with encrypted multipart/report
|
||||
/// parts and MUAs should be encouraged to encrpyt multipart/reports as well so
|
||||
/// that we could use the normal Autocrypt processing.
|
||||
fn contains_report(mime: *mut Mailmime) -> bool {
|
||||
assert!(!mime.is_null());
|
||||
let mime = unsafe { *mime };
|
||||
|
||||
if mime.mm_type == MAILMIME_MULTIPLE as libc::c_int {
|
||||
let tp_type = unsafe { (*(*mime.mm_content_type).ct_type).tp_type };
|
||||
let ct_type =
|
||||
unsafe { (*(*(*mime.mm_content_type).ct_type).tp_data.tp_composite_type).ct_type };
|
||||
|
||||
if tp_type == MAILMIME_TYPE_COMPOSITE_TYPE as libc::c_int
|
||||
&& ct_type == MAILMIME_COMPOSITE_TYPE_MULTIPART as libc::c_int
|
||||
&& to_string_lossy(unsafe { (*mime.mm_content_type).ct_subtype }) == "report"
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
for cur_data in unsafe { (*(*mime.mm_mime_fields).fld_list).into_iter() } {
|
||||
if contains_report(cur_data as *mut Mailmime) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else if mime.mm_type == MAILMIME_MESSAGE as libc::c_int {
|
||||
let m = unsafe { mime.mm_data.mm_message.mm_msg_mime };
|
||||
|
||||
if contains_report(m) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
fn contains_report(mail: &mailparse::ParsedMail<'_>) -> bool {
|
||||
mail.ctype.mimetype == "multipart/report"
|
||||
}
|
||||
|
||||
/// Ensures a private key exists for the configured user.
|
||||
@@ -699,7 +345,6 @@ pub fn ensure_secret_key_exists(context: &Context) -> Result<String> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use libc::free;
|
||||
|
||||
use crate::test_utils::*;
|
||||
|
||||
@@ -722,7 +367,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_mailmime_parse() {
|
||||
let plain = b"Chat-Disposition-Notification-To: holger@deltachat.de
|
||||
let plain = b"Chat-Disposition-Notification-To: hello@world.de
|
||||
Chat-Group-ID: CovhGgau8M-
|
||||
Chat-Group-Name: Delta Chat Dev
|
||||
Subject: =?utf-8?Q?Chat=3A?= Delta Chat =?utf-8?Q?Dev=3A?= sidenote for
|
||||
@@ -730,35 +375,18 @@ Subject: =?utf-8?Q?Chat=3A?= Delta Chat =?utf-8?Q?Dev=3A?= sidenote for
|
||||
Content-Type: text/plain; charset=\"utf-8\"; protected-headers=\"v1\"
|
||||
Content-Transfer-Encoding: quoted-printable
|
||||
|
||||
sidenote for all: rust core master is broken currently ... so dont recomm=
|
||||
end to try to run with desktop or ios unless you are ready to hunt bugs
|
||||
sidenote for all: things are trick atm recomm=
|
||||
end not to try to run with desktop or ios unless you are ready to hunt bugs
|
||||
|
||||
-- =20
|
||||
Sent with my Delta Chat Messenger: https://delta.chat";
|
||||
let plain_bytes = plain.len();
|
||||
let plain_buf = plain.as_ptr() as *const libc::c_char;
|
||||
let mail = mailparse::parse_mail(plain).expect("failed to parse valid message");
|
||||
|
||||
let mut index = 0;
|
||||
let mut decrypted_mime = std::ptr::null_mut();
|
||||
|
||||
let res = unsafe {
|
||||
mailmime_parse(
|
||||
plain_buf as *const _,
|
||||
plain_bytes,
|
||||
&mut index,
|
||||
&mut decrypted_mime,
|
||||
)
|
||||
};
|
||||
unsafe {
|
||||
let msg1 = (*decrypted_mime).mm_data.mm_message.mm_msg_mime;
|
||||
let data = mailmime_transfer_decode(msg1).unwrap();
|
||||
println!("{:?}", String::from_utf8_lossy(&data));
|
||||
}
|
||||
|
||||
assert_eq!(res, 0);
|
||||
assert!(!decrypted_mime.is_null());
|
||||
|
||||
unsafe { free(decrypted_mime as *mut _) };
|
||||
assert_eq!(mail.headers.len(), 6);
|
||||
assert!(
|
||||
mail.get_body().unwrap().starts_with(
|
||||
"sidenote for all: things are trick atm recommend not to try to run with desktop or ios unless you are ready to hunt bugs")
|
||||
);
|
||||
}
|
||||
|
||||
mod load_or_generate_self_public_key {
|
||||
|
||||
33
src/error.rs
33
src/error.rs
@@ -1,4 +1,5 @@
|
||||
use failure::Fail;
|
||||
use lettre_email::mime;
|
||||
|
||||
#[derive(Debug, Fail)]
|
||||
pub enum Error {
|
||||
@@ -14,8 +15,6 @@ pub enum Error {
|
||||
Image(image_meta::ImageError),
|
||||
#[fail(display = "{:?}", _0)]
|
||||
Utf8(std::str::Utf8Error),
|
||||
#[fail(display = "{:?}", _0)]
|
||||
CStringError(crate::dc_tools::CStringError),
|
||||
#[fail(display = "PGP: {:?}", _0)]
|
||||
Pgp(pgp::errors::Error),
|
||||
#[fail(display = "Base64Decode: {:?}", _0)]
|
||||
@@ -28,6 +27,12 @@ pub enum Error {
|
||||
InvalidMsgId,
|
||||
#[fail(display = "Watch folder not found {:?}", _0)]
|
||||
WatchFolderNotFound(String),
|
||||
#[fail(display = "Inalid Email: {:?}", _0)]
|
||||
MailParseError(#[cause] mailparse::MailParseError),
|
||||
#[fail(display = "Building invalid Email: {:?}", _0)]
|
||||
LettreError(#[cause] lettre_email::error::Error),
|
||||
#[fail(display = "FromStr error: {:?}", _0)]
|
||||
FromStr(#[cause] mime::FromStrError),
|
||||
}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
@@ -68,12 +73,6 @@ impl From<image_meta::ImageError> for Error {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::dc_tools::CStringError> for Error {
|
||||
fn from(err: crate::dc_tools::CStringError) -> Error {
|
||||
Error::CStringError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<pgp::errors::Error> for Error {
|
||||
fn from(err: pgp::errors::Error) -> Error {
|
||||
Error::Pgp(err)
|
||||
@@ -98,6 +97,24 @@ impl From<crate::message::InvalidMsgId> for Error {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<mailparse::MailParseError> for Error {
|
||||
fn from(err: mailparse::MailParseError) -> Error {
|
||||
Error::MailParseError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<lettre_email::error::Error> for Error {
|
||||
fn from(err: lettre_email::error::Error) -> Error {
|
||||
Error::LettreError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<mime::FromStrError> for Error {
|
||||
fn from(err: mime::FromStrError) -> Error {
|
||||
Error::FromStr(err)
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! bail {
|
||||
($e:expr) => {
|
||||
|
||||
@@ -825,9 +825,7 @@ impl Imap {
|
||||
|
||||
if !is_deleted && msg.body().is_some() {
|
||||
let body = msg.body().unwrap_or_default();
|
||||
unsafe {
|
||||
dc_receive_imf(context, &body, folder.as_ref(), server_uid, flags as u32);
|
||||
}
|
||||
dc_receive_imf(context, &body, folder.as_ref(), server_uid, flags as u32);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ use crate::config::Config;
|
||||
use crate::configure::*;
|
||||
use crate::constants::*;
|
||||
use crate::context::Context;
|
||||
use crate::dc_mimeparser::SystemMessage;
|
||||
use crate::dc_tools::*;
|
||||
use crate::e2ee;
|
||||
use crate::error::*;
|
||||
@@ -20,6 +19,7 @@ use crate::events::Event;
|
||||
use crate::job::*;
|
||||
use crate::key::*;
|
||||
use crate::message::{Message, MsgId};
|
||||
use crate::mimeparser::SystemMessage;
|
||||
use crate::param::*;
|
||||
use crate::pgp;
|
||||
use crate::sql::{self, Sql};
|
||||
|
||||
131
src/job.rs
131
src/job.rs
@@ -18,7 +18,7 @@ use crate::location;
|
||||
use crate::login_param::LoginParam;
|
||||
use crate::message::MsgId;
|
||||
use crate::message::{self, Message, MessageState};
|
||||
use crate::mimefactory::{vec_contains_lowercase, Loaded, MimeFactory};
|
||||
use crate::mimefactory::{vec_contains_lowercase, MimeFactory, RenderedEmail};
|
||||
use crate::param::*;
|
||||
use crate::sql;
|
||||
|
||||
@@ -604,42 +604,38 @@ fn set_delivered(context: &Context, msg_id: MsgId) {
|
||||
/* special case for DC_JOB_SEND_MSG_TO_SMTP */
|
||||
#[allow(non_snake_case)]
|
||||
pub fn job_send_msg(context: &Context, msg_id: MsgId) -> Result<(), Error> {
|
||||
let mut mimefactory = MimeFactory::load_msg(context, msg_id)?;
|
||||
let mut msg = Message::load_from_db(context, msg_id)?;
|
||||
|
||||
if chat::msgtype_has_file(mimefactory.msg.type_0) {
|
||||
let file_param = mimefactory.msg.param.get_path(Param::File, context)?;
|
||||
if chat::msgtype_has_file(msg.type_0) {
|
||||
let file_param = msg.param.get_path(Param::File, context)?;
|
||||
if let Some(pathNfilename) = file_param {
|
||||
if (mimefactory.msg.type_0 == Viewtype::Image
|
||||
|| mimefactory.msg.type_0 == Viewtype::Gif)
|
||||
&& !mimefactory.msg.param.exists(Param::Width)
|
||||
if (msg.type_0 == Viewtype::Image || msg.type_0 == Viewtype::Gif)
|
||||
&& !msg.param.exists(Param::Width)
|
||||
{
|
||||
mimefactory.msg.param.set_int(Param::Width, 0);
|
||||
mimefactory.msg.param.set_int(Param::Height, 0);
|
||||
msg.param.set_int(Param::Width, 0);
|
||||
msg.param.set_int(Param::Height, 0);
|
||||
|
||||
if let Ok(buf) = dc_read_file(context, pathNfilename) {
|
||||
if let Ok((width, height)) = dc_get_filemeta(&buf) {
|
||||
mimefactory.msg.param.set_int(Param::Width, width as i32);
|
||||
mimefactory.msg.param.set_int(Param::Height, height as i32);
|
||||
msg.param.set_int(Param::Width, width as i32);
|
||||
msg.param.set_int(Param::Height, height as i32);
|
||||
}
|
||||
}
|
||||
mimefactory.msg.save_param_to_disk(context);
|
||||
msg.save_param_to_disk(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* create message */
|
||||
if let Err(msg) = unsafe { mimefactory.render() } {
|
||||
let e = msg.to_string();
|
||||
message::set_msg_failed(context, msg_id, Some(e));
|
||||
return Err(msg);
|
||||
}
|
||||
if 0 != mimefactory
|
||||
.msg
|
||||
.param
|
||||
.get_int(Param::GuaranteeE2ee)
|
||||
.unwrap_or_default()
|
||||
&& !mimefactory.out_encrypted
|
||||
{
|
||||
let needs_encryption = msg.param.get_int(Param::GuaranteeE2ee).unwrap_or_default();
|
||||
|
||||
let mimefactory = MimeFactory::from_msg(context, &msg)?;
|
||||
let mut rendered_msg = mimefactory.render().map_err(|err| {
|
||||
message::set_msg_failed(context, msg_id, Some(err.to_string()));
|
||||
err
|
||||
})?;
|
||||
|
||||
if 0 != needs_encryption && !rendered_msg.is_encrypted {
|
||||
/* unrecoverable */
|
||||
message::set_msg_failed(
|
||||
context,
|
||||
@@ -649,19 +645,17 @@ pub fn job_send_msg(context: &Context, msg_id: MsgId) -> Result<(), Error> {
|
||||
bail!(
|
||||
"e2e encryption unavailable {} - {:?}",
|
||||
msg_id,
|
||||
mimefactory.msg.param.get_int(Param::GuaranteeE2ee),
|
||||
needs_encryption
|
||||
);
|
||||
}
|
||||
|
||||
if context.get_config_bool(Config::BccSelf)
|
||||
&& !vec_contains_lowercase(&mimefactory.recipients_addr, &mimefactory.from_addr)
|
||||
&& !vec_contains_lowercase(&rendered_msg.recipients, &rendered_msg.from)
|
||||
{
|
||||
mimefactory.recipients_names.push("".to_string());
|
||||
mimefactory
|
||||
.recipients_addr
|
||||
.push(mimefactory.from_addr.to_string());
|
||||
rendered_msg.recipients.push(rendered_msg.from.clone());
|
||||
}
|
||||
|
||||
if mimefactory.recipients_addr.is_empty() {
|
||||
if rendered_msg.recipients.is_empty() {
|
||||
// may happen eg. for groups with only SELF and bcc_self disabled
|
||||
info!(
|
||||
context,
|
||||
@@ -671,36 +665,27 @@ pub fn job_send_msg(context: &Context, msg_id: MsgId) -> Result<(), Error> {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if mimefactory.out_gossiped {
|
||||
chat::set_gossiped_timestamp(context, mimefactory.msg.chat_id, time());
|
||||
if rendered_msg.is_gossiped {
|
||||
chat::set_gossiped_timestamp(context, msg.chat_id, time());
|
||||
}
|
||||
if 0 != mimefactory.out_last_added_location_id {
|
||||
if let Err(err) = location::set_kml_sent_timestamp(context, mimefactory.msg.chat_id, time())
|
||||
{
|
||||
if 0 != rendered_msg.last_added_location_id {
|
||||
if let Err(err) = location::set_kml_sent_timestamp(context, msg.chat_id, time()) {
|
||||
error!(context, "Failed to set kml sent_timestamp: {:?}", err);
|
||||
}
|
||||
if !mimefactory.msg.hidden {
|
||||
if let Err(err) = location::set_msg_location_id(
|
||||
context,
|
||||
mimefactory.msg.id,
|
||||
mimefactory.out_last_added_location_id,
|
||||
) {
|
||||
if !msg.hidden {
|
||||
if let Err(err) =
|
||||
location::set_msg_location_id(context, msg.id, rendered_msg.last_added_location_id)
|
||||
{
|
||||
error!(context, "Failed to set msg_location_id: {:?}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
if mimefactory.out_encrypted
|
||||
&& mimefactory
|
||||
.msg
|
||||
.param
|
||||
.get_int(Param::GuaranteeE2ee)
|
||||
.unwrap_or_default()
|
||||
== 0
|
||||
{
|
||||
mimefactory.msg.param.set_int(Param::GuaranteeE2ee, 1);
|
||||
mimefactory.msg.save_param_to_disk(context);
|
||||
if rendered_msg.is_encrypted && needs_encryption == 0 {
|
||||
msg.param.set_int(Param::GuaranteeE2ee, 1);
|
||||
msg.save_param_to_disk(context);
|
||||
}
|
||||
add_smtp_job(context, Action::SendMsgToSmtp, &mut mimefactory)?;
|
||||
|
||||
add_smtp_job(context, Action::SendMsgToSmtp, &rendered_msg)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -886,38 +871,40 @@ fn suspend_smtp_thread(context: &Context, suspend: bool) {
|
||||
}
|
||||
|
||||
fn send_mdn(context: &Context, msg_id: MsgId) -> Result<(), Error> {
|
||||
let mut mimefactory = MimeFactory::load_mdn(context, msg_id)?;
|
||||
unsafe { mimefactory.render()? };
|
||||
add_smtp_job(context, Action::SendMdn, &mut mimefactory)?;
|
||||
let msg = Message::load_from_db(context, msg_id)?;
|
||||
let mimefactory = MimeFactory::from_mdn(context, &msg)?;
|
||||
let rendered_msg = mimefactory.render()?;
|
||||
|
||||
add_smtp_job(context, Action::SendMdn, &rendered_msg)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
fn add_smtp_job(context: &Context, action: Action, mimefactory: &MimeFactory) -> Result<(), Error> {
|
||||
fn add_smtp_job(
|
||||
context: &Context,
|
||||
action: Action,
|
||||
rendered_msg: &RenderedEmail,
|
||||
) -> Result<(), Error> {
|
||||
ensure!(
|
||||
!mimefactory.recipients_addr.is_empty(),
|
||||
!rendered_msg.recipients.is_empty(),
|
||||
"no recipients for smtp job set"
|
||||
);
|
||||
let mut param = Params::new();
|
||||
let bytes = unsafe {
|
||||
std::slice::from_raw_parts(
|
||||
(*mimefactory.out).str_0 as *const u8,
|
||||
(*mimefactory.out).len,
|
||||
)
|
||||
};
|
||||
let blob = BlobObject::create(context, &mimefactory.rfc724_mid, bytes)?;
|
||||
let recipients = mimefactory.recipients_addr.join("\x1e");
|
||||
let bytes = &rendered_msg.message;
|
||||
let blob = BlobObject::create(context, &rendered_msg.rfc724_mid, bytes)?;
|
||||
|
||||
let recipients = rendered_msg.recipients.join("\x1e");
|
||||
param.set(Param::File, blob.as_name());
|
||||
param.set(Param::Recipients, &recipients);
|
||||
|
||||
job_add(
|
||||
context,
|
||||
action,
|
||||
(if mimefactory.loaded == Loaded::Message {
|
||||
mimefactory.msg.id.to_u32() as i32
|
||||
} else {
|
||||
0
|
||||
}) as libc::c_int,
|
||||
rendered_msg
|
||||
.foreign_id
|
||||
.map(|v| v.to_u32() as i32)
|
||||
.unwrap_or_default(),
|
||||
param,
|
||||
0,
|
||||
);
|
||||
@@ -928,7 +915,7 @@ fn add_smtp_job(context: &Context, action: Action, mimefactory: &MimeFactory) ->
|
||||
pub fn job_add(
|
||||
context: &Context,
|
||||
action: Action,
|
||||
foreign_id: libc::c_int,
|
||||
foreign_id: i32,
|
||||
param: Params,
|
||||
delay_seconds: i64,
|
||||
) {
|
||||
|
||||
@@ -17,8 +17,6 @@ extern crate strum;
|
||||
#[macro_use]
|
||||
extern crate strum_macros;
|
||||
#[macro_use]
|
||||
extern crate jetscii;
|
||||
#[macro_use]
|
||||
extern crate debug_stub_derive;
|
||||
|
||||
#[macro_use]
|
||||
@@ -51,6 +49,7 @@ mod login_param;
|
||||
pub mod lot;
|
||||
pub mod message;
|
||||
mod mimefactory;
|
||||
pub mod mimeparser;
|
||||
pub mod oauth2;
|
||||
mod param;
|
||||
pub mod peerstate;
|
||||
@@ -63,14 +62,13 @@ pub mod stock;
|
||||
mod token;
|
||||
#[macro_use]
|
||||
mod wrapmime;
|
||||
mod dehtml;
|
||||
|
||||
pub mod dc_array;
|
||||
pub mod dc_mimeparser;
|
||||
pub mod dc_receive_imf;
|
||||
mod dc_simplify;
|
||||
mod dc_strencode;
|
||||
pub mod dc_tools;
|
||||
mod dehtml;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_utils;
|
||||
|
||||
@@ -8,12 +8,12 @@ use crate::chat;
|
||||
use crate::config::Config;
|
||||
use crate::constants::*;
|
||||
use crate::context::*;
|
||||
use crate::dc_mimeparser::SystemMessage;
|
||||
use crate::dc_tools::*;
|
||||
use crate::error::Error;
|
||||
use crate::events::Event;
|
||||
use crate::job::*;
|
||||
use crate::message::{Message, MsgId};
|
||||
use crate::mimeparser::SystemMessage;
|
||||
use crate::param::*;
|
||||
use crate::sql;
|
||||
use crate::stock::StockMessage;
|
||||
@@ -229,7 +229,7 @@ pub fn send_locations_to_chat(context: &Context, chat_id: u32, seconds: i64) {
|
||||
job_add(
|
||||
context,
|
||||
Action::MaybeSendLocationsEnded,
|
||||
chat_id as libc::c_int,
|
||||
chat_id as i32,
|
||||
Params::new(),
|
||||
seconds + 1,
|
||||
);
|
||||
|
||||
@@ -7,12 +7,12 @@ use crate::chat::{self, Chat};
|
||||
use crate::constants::*;
|
||||
use crate::contact::*;
|
||||
use crate::context::*;
|
||||
use crate::dc_mimeparser::SystemMessage;
|
||||
use crate::dc_tools::*;
|
||||
use crate::error::Error;
|
||||
use crate::events::Event;
|
||||
use crate::job::*;
|
||||
use crate::lot::{Lot, LotState, Meaning};
|
||||
use crate::mimeparser::SystemMessage;
|
||||
use crate::param::*;
|
||||
use crate::pgp::*;
|
||||
use crate::sql;
|
||||
@@ -431,8 +431,8 @@ impl Message {
|
||||
return ret;
|
||||
};
|
||||
|
||||
let contact = if self.from_id != DC_CONTACT_ID_SELF as libc::c_uint
|
||||
&& ((*chat).typ == Chattype::Group || (*chat).typ == Chattype::VerifiedGroup)
|
||||
let contact = if self.from_id != DC_CONTACT_ID_SELF as u32
|
||||
&& (chat.typ == Chattype::Group || chat.typ == Chattype::VerifiedGroup)
|
||||
{
|
||||
Contact::get_by_id(context, self.from_id).ok()
|
||||
} else {
|
||||
@@ -444,11 +444,11 @@ impl Message {
|
||||
ret
|
||||
}
|
||||
|
||||
pub fn get_summarytext(&mut self, context: &Context, approx_characters: usize) -> String {
|
||||
pub fn get_summarytext(&self, context: &Context, approx_characters: usize) -> String {
|
||||
get_summarytext_by_raw(
|
||||
self.type_0,
|
||||
self.text.as_ref(),
|
||||
&mut self.param,
|
||||
&self.param,
|
||||
approx_characters,
|
||||
context,
|
||||
)
|
||||
@@ -476,8 +476,8 @@ impl Message {
|
||||
|
||||
pub fn is_info(&self) -> bool {
|
||||
let cmd = self.param.get_cmd();
|
||||
self.from_id == DC_CONTACT_ID_INFO as libc::c_uint
|
||||
|| self.to_id == DC_CONTACT_ID_INFO as libc::c_uint
|
||||
self.from_id == DC_CONTACT_ID_INFO as u32
|
||||
|| self.to_id == DC_CONTACT_ID_INFO as u32
|
||||
|| cmd != SystemMessage::Unknown && cmd != SystemMessage::AutocryptSetupMessage
|
||||
}
|
||||
|
||||
@@ -704,7 +704,7 @@ pub fn get_msg_info(context: &Context, msg_id: MsgId) -> String {
|
||||
ret += &format!(" by {}", name);
|
||||
ret += "\n";
|
||||
|
||||
if msg.from_id != DC_CONTACT_ID_SELF as libc::c_uint {
|
||||
if msg.from_id != DC_CONTACT_ID_SELF as u32 {
|
||||
let s = dc_timestamp_to_str(if 0 != msg.timestamp_rcvd {
|
||||
msg.timestamp_rcvd
|
||||
} else {
|
||||
@@ -987,7 +987,7 @@ pub fn star_msgs(context: &Context, msg_ids: &[MsgId], star: bool) -> bool {
|
||||
pub fn get_summarytext_by_raw(
|
||||
viewtype: Viewtype,
|
||||
text: Option<impl AsRef<str>>,
|
||||
param: &mut Params,
|
||||
param: &Params,
|
||||
approx_characters: usize,
|
||||
context: &Context,
|
||||
) -> String {
|
||||
@@ -1111,7 +1111,7 @@ pub fn mdn_from_ext(
|
||||
return None;
|
||||
}
|
||||
|
||||
if let Ok((msg_id, chat_id, chat_type, msg_state)) = context.sql.query_row(
|
||||
let res = context.sql.query_row(
|
||||
concat!(
|
||||
"SELECT",
|
||||
" m.id AS msg_id,",
|
||||
@@ -1131,7 +1131,12 @@ pub fn mdn_from_ext(
|
||||
row.get::<_, MessageState>("state")?,
|
||||
))
|
||||
},
|
||||
) {
|
||||
);
|
||||
if let Err(ref err) = res {
|
||||
info!(context, "Failed to select MDN {:?}", err);
|
||||
}
|
||||
|
||||
if let Ok((msg_id, chat_id, chat_type, msg_state)) = res {
|
||||
let mut read_by_all = false;
|
||||
|
||||
// if already marked as MDNS_RCVD msgstate_can_fail() returns false.
|
||||
@@ -1196,7 +1201,7 @@ pub fn mdn_from_ext(
|
||||
}
|
||||
|
||||
/// The number of messages assigned to real chat (!=deaddrop, !=trash)
|
||||
pub fn get_real_msg_cnt(context: &Context) -> libc::c_int {
|
||||
pub fn get_real_msg_cnt(context: &Context) -> i32 {
|
||||
match context.sql.query_row(
|
||||
"SELECT COUNT(*) \
|
||||
FROM msgs m LEFT JOIN chats c ON c.id=m.chat_id \
|
||||
@@ -1212,7 +1217,7 @@ pub fn get_real_msg_cnt(context: &Context) -> libc::c_int {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_deaddrop_msg_cnt(context: &Context) -> libc::size_t {
|
||||
pub fn get_deaddrop_msg_cnt(context: &Context) -> usize {
|
||||
match context.sql.query_row(
|
||||
"SELECT COUNT(*) \
|
||||
FROM msgs m LEFT JOIN chats c ON c.id=m.chat_id \
|
||||
@@ -1220,7 +1225,7 @@ pub fn get_deaddrop_msg_cnt(context: &Context) -> libc::size_t {
|
||||
rusqlite::NO_PARAMS,
|
||||
|row| row.get::<_, isize>(0),
|
||||
) {
|
||||
Ok(res) => res as libc::size_t,
|
||||
Ok(res) => res as usize,
|
||||
Err(err) => {
|
||||
error!(context, "dc_get_deaddrop_msg_cnt() failed. {}", err);
|
||||
0
|
||||
@@ -1228,7 +1233,7 @@ pub fn get_deaddrop_msg_cnt(context: &Context) -> libc::size_t {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rfc724_mid_cnt(context: &Context, rfc724_mid: &str) -> libc::c_int {
|
||||
pub fn rfc724_mid_cnt(context: &Context, rfc724_mid: &str) -> i32 {
|
||||
// check the number of messages with the same rfc724_mid
|
||||
match context.sql.query_row(
|
||||
"SELECT COUNT(*) FROM msgs WHERE rfc724_mid=?;",
|
||||
|
||||
1523
src/mimefactory.rs
1523
src/mimefactory.rs
File diff suppressed because it is too large
Load Diff
1109
src/mimeparser.rs
Normal file
1109
src/mimeparser.rs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -7,8 +7,8 @@ use num_traits::FromPrimitive;
|
||||
|
||||
use crate::blob::{BlobError, BlobObject};
|
||||
use crate::context::Context;
|
||||
use crate::dc_mimeparser::SystemMessage;
|
||||
use crate::error;
|
||||
use crate::mimeparser::SystemMessage;
|
||||
|
||||
/// Available param keys.
|
||||
#[derive(PartialEq, Eq, Debug, Clone, Copy, Hash, PartialOrd, Ord, FromPrimitive)]
|
||||
|
||||
@@ -8,13 +8,13 @@ use crate::config::*;
|
||||
use crate::constants::*;
|
||||
use crate::contact::*;
|
||||
use crate::context::Context;
|
||||
use crate::dc_mimeparser::*;
|
||||
use crate::e2ee::*;
|
||||
use crate::error::Error;
|
||||
use crate::events::Event;
|
||||
use crate::key::*;
|
||||
use crate::lot::LotState;
|
||||
use crate::message::Message;
|
||||
use crate::mimeparser::*;
|
||||
use crate::param::*;
|
||||
use crate::peerstate::*;
|
||||
use crate::qr::check_qr;
|
||||
@@ -337,7 +337,7 @@ impl Default for HandshakeMessageStatus {
|
||||
}
|
||||
}
|
||||
|
||||
/* library private: secure-join */
|
||||
/// Handle incoming secure-join handshake.
|
||||
pub(crate) fn handle_securejoin_handshake(
|
||||
context: &Context,
|
||||
mimeparser: &MimeParser,
|
||||
@@ -349,22 +349,22 @@ pub(crate) fn handle_securejoin_handshake(
|
||||
contact_id > DC_CONTACT_ID_LAST_SPECIAL,
|
||||
"handle_securejoin_handshake(): called with special contact id"
|
||||
);
|
||||
let step = match mimeparser.lookup_optional_field("Secure-Join") {
|
||||
Some(s) => s,
|
||||
None => {
|
||||
bail!("This message is not a Secure-Join message");
|
||||
}
|
||||
};
|
||||
let step = mimeparser
|
||||
.lookup_field("Secure-Join")
|
||||
.ok_or_else(|| format_err!("This message is not a Secure-Join message"))?;
|
||||
|
||||
info!(
|
||||
context,
|
||||
">>>>>>>>>>>>>>>>>>>>>>>>> secure-join message \'{}\' received", step,
|
||||
);
|
||||
|
||||
let (contact_chat_id, contact_chat_id_blocked) =
|
||||
chat::create_or_lookup_by_contact_id(context, contact_id, Blocked::Not).unwrap_or_default();
|
||||
|
||||
if contact_chat_id_blocked != Blocked::Not {
|
||||
chat::unblock(context, contact_chat_id);
|
||||
}
|
||||
|
||||
let join_vg = step.starts_with("vg-");
|
||||
let mut ret = HandshakeMessageStatus::default();
|
||||
|
||||
@@ -378,7 +378,7 @@ pub(crate) fn handle_securejoin_handshake(
|
||||
// it just ensures, we have Bobs key now. If we do _not_ have the key because eg. MitM has removed it,
|
||||
// send_message() will fail with the error "End-to-end-encryption unavailable unexpectedly.", so, there is no additional check needed here.
|
||||
// verify that the `Secure-Join-Invitenumber:`-header matches invitenumber written to the QR code
|
||||
let invitenumber = match mimeparser.lookup_optional_field("Secure-Join-Invitenumber") {
|
||||
let invitenumber = match mimeparser.lookup_field("Secure-Join-Invitenumber") {
|
||||
Some(n) => n,
|
||||
None => {
|
||||
warn!(context, "Secure-join denied (invitenumber missing).",);
|
||||
@@ -467,7 +467,7 @@ pub(crate) fn handle_securejoin_handshake(
|
||||
==== Step 6 in "Out-of-band verified groups" protocol ====
|
||||
============================================================ */
|
||||
// verify that Secure-Join-Fingerprint:-header matches the fingerprint of Bob
|
||||
let fingerprint = match mimeparser.lookup_optional_field("Secure-Join-Fingerprint") {
|
||||
let fingerprint = match mimeparser.lookup_field("Secure-Join-Fingerprint") {
|
||||
Some(fp) => fp,
|
||||
None => {
|
||||
could_not_establish_secure_connection(
|
||||
@@ -496,7 +496,7 @@ pub(crate) fn handle_securejoin_handshake(
|
||||
}
|
||||
info!(context, "Fingerprint verified.",);
|
||||
// verify that the `Secure-Join-Auth:`-header matches the secret written to the QR code
|
||||
let auth_0 = match mimeparser.lookup_optional_field("Secure-Join-Auth") {
|
||||
let auth_0 = match mimeparser.lookup_field("Secure-Join-Auth") {
|
||||
Some(auth) => auth,
|
||||
None => {
|
||||
could_not_establish_secure_connection(
|
||||
@@ -526,9 +526,10 @@ pub(crate) fn handle_securejoin_handshake(
|
||||
inviter_progress!(context, contact_id, 600);
|
||||
if join_vg {
|
||||
let field_grpid = mimeparser
|
||||
.lookup_optional_field("Secure-Join-Group")
|
||||
.unwrap_or_default();
|
||||
let (group_chat_id, _, _) = chat::get_chat_id_by_grpid(context, &field_grpid);
|
||||
.lookup_field("Secure-Join-Group")
|
||||
.map(|s| s.as_str())
|
||||
.unwrap_or_else(|| "");
|
||||
let (group_chat_id, _, _) = chat::get_chat_id_by_grpid(context, field_grpid);
|
||||
if group_chat_id == 0 {
|
||||
error!(context, "Chat {} not found.", &field_grpid);
|
||||
return Ok(ret);
|
||||
@@ -601,8 +602,9 @@ pub(crate) fn handle_securejoin_handshake(
|
||||
Contact::scaleup_origin_by_id(context, contact_id, Origin::SecurejoinJoined);
|
||||
emit_event!(context, Event::ContactsChanged(None));
|
||||
let cg_member_added = mimeparser
|
||||
.lookup_optional_field("Chat-Group-Member-Added")
|
||||
.unwrap_or_default();
|
||||
.lookup_field("Chat-Group-Member-Added")
|
||||
.map(|s| s.as_str())
|
||||
.unwrap_or_else(|| "");
|
||||
if join_vg && !addr_equals_self(context, cg_member_added) {
|
||||
info!(context, "Message belongs to a different handshake (scaled up contact anyway to allow creation of group).");
|
||||
return Ok(ret);
|
||||
@@ -635,8 +637,9 @@ pub(crate) fn handle_securejoin_handshake(
|
||||
inviter_progress!(context, contact_id, 800);
|
||||
inviter_progress!(context, contact_id, 1000);
|
||||
let field_grpid = mimeparser
|
||||
.lookup_optional_field("Secure-Join-Group")
|
||||
.unwrap_or_default();
|
||||
.lookup_field("Secure-Join-Group")
|
||||
.map(|s| s.as_str())
|
||||
.unwrap_or_else(|| "");
|
||||
let (group_chat_id, _, _) = chat::get_chat_id_by_grpid(context, &field_grpid);
|
||||
context.call_cb(Event::SecurejoinMemberAdded {
|
||||
chat_id: group_chat_id,
|
||||
@@ -651,9 +654,11 @@ pub(crate) fn handle_securejoin_handshake(
|
||||
warn!(context, "invalid step: {}", step);
|
||||
}
|
||||
}
|
||||
|
||||
if ret.hide_this_msg {
|
||||
ret.delete_this_msg = true;
|
||||
}
|
||||
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
|
||||
564
src/wrapmime.rs
564
src/wrapmime.rs
@@ -1,552 +1,50 @@
|
||||
use std::collections::HashSet;
|
||||
use std::ffi::CString;
|
||||
use std::ptr;
|
||||
use mailparse::ParsedMail;
|
||||
|
||||
use crate::contact::addr_normalize;
|
||||
use crate::dc_strencode::*;
|
||||
use crate::dc_tools::*;
|
||||
use crate::error::Error;
|
||||
use mmime::clist::*;
|
||||
// use mmime::display::*;
|
||||
use mmime::mailimf::mailimf_msg_id_parse;
|
||||
use mmime::mailimf::types::*;
|
||||
use mmime::mailimf::types_helper::*;
|
||||
use mmime::mailmime::content::*;
|
||||
use mmime::mailmime::disposition::*;
|
||||
use mmime::mailmime::types::*;
|
||||
use mmime::mailmime::types_helper::*;
|
||||
use mmime::mailmime::*;
|
||||
use mmime::mmapstring::*;
|
||||
use mmime::other::*;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! clist_append {
|
||||
($clist:expr, $item:expr) => {
|
||||
if clist_insert_after(
|
||||
$clist as *mut clist,
|
||||
(*$clist).last,
|
||||
$item as *mut libc::c_void,
|
||||
) != 0
|
||||
{
|
||||
bail!("could not allocate or append list item");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**************************************
|
||||
* mime parsing API
|
||||
**************************************/
|
||||
|
||||
pub fn get_ct_subtype(mime: *mut Mailmime) -> Option<String> {
|
||||
unsafe {
|
||||
let ct: *mut mailmime_content = (*mime).mm_content_type;
|
||||
|
||||
if !ct.is_null() && !(*ct).ct_subtype.is_null() {
|
||||
Some(to_string_lossy((*ct).ct_subtype))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_message_id(message_id: &[u8]) -> Result<String, Error> {
|
||||
let mut dummy = 0;
|
||||
let mut rfc724_mid_c = std::ptr::null_mut();
|
||||
if unsafe {
|
||||
mailimf_msg_id_parse(
|
||||
message_id.as_ptr() as *const libc::c_char,
|
||||
message_id.len(),
|
||||
&mut dummy,
|
||||
&mut rfc724_mid_c,
|
||||
)
|
||||
} == MAIL_NO_ERROR as libc::c_int
|
||||
&& !rfc724_mid_c.is_null()
|
||||
{
|
||||
let res = to_string_lossy(rfc724_mid_c);
|
||||
unsafe { libc::free(rfc724_mid_c.cast()) };
|
||||
Ok(res)
|
||||
} else {
|
||||
bail!(
|
||||
"could not parse message_id: {}",
|
||||
String::from_utf8_lossy(message_id)
|
||||
);
|
||||
let value = std::str::from_utf8(message_id)?;
|
||||
let addrs = mailparse::addrparse(value)
|
||||
.map_err(|err| format_err!("failed to parse message id {:?}", err))?;
|
||||
|
||||
if let Some(info) = addrs.extract_single_info() {
|
||||
return Ok(info.addr);
|
||||
}
|
||||
|
||||
bail!("could not parse message_id: {}", value);
|
||||
}
|
||||
|
||||
pub fn get_autocrypt_mime(
|
||||
mime_undetermined: *mut Mailmime,
|
||||
) -> Result<(*mut Mailmime, *mut Mailmime), Error> {
|
||||
/* return Result with two mime pointers:
|
||||
/// Returns a reference to the encrypted payload and validates the autocrypt structure.
|
||||
pub fn get_autocrypt_mime<'a, 'b>(mail: &'a ParsedMail<'b>) -> Result<&'a ParsedMail<'b>, Error> {
|
||||
ensure!(
|
||||
mail.ctype.mimetype == "multipart/encrypted",
|
||||
"Not a multipart/encrypted message: {}",
|
||||
mail.ctype.mimetype
|
||||
);
|
||||
ensure!(
|
||||
mail.subparts.len() == 2,
|
||||
"Invalid Autocrypt Level 1 Mime Parts"
|
||||
);
|
||||
|
||||
First mime pointer is to the multipart-mime message
|
||||
(which is replaced with a decrypted version later)
|
||||
ensure!(
|
||||
mail.subparts[0].ctype.mimetype == "application/pgp-encrypted",
|
||||
"Invalid Autocrypt Level 1 version part: {:?}",
|
||||
mail.subparts[0].ctype,
|
||||
);
|
||||
|
||||
Second one is to the encrypted payload.
|
||||
For non-autocrypt message an Error is returned.
|
||||
*/
|
||||
unsafe {
|
||||
ensure!(
|
||||
(*mime_undetermined).mm_type == MAILMIME_MESSAGE as libc::c_int,
|
||||
"Not a root mime message"
|
||||
);
|
||||
let mime = (*mime_undetermined).mm_data.mm_message.mm_msg_mime;
|
||||
ensure!(
|
||||
mail.subparts[1].ctype.mimetype == "application/octet-stream",
|
||||
"Invalid Autocrypt Level 1 encrypted part: {:?}",
|
||||
mail.subparts[1].ctype
|
||||
);
|
||||
|
||||
ensure!(
|
||||
(*mime).mm_type == MAILMIME_MULTIPLE as libc::c_int
|
||||
&& "encrypted" == get_ct_subtype(mime).unwrap_or_default(),
|
||||
"Not a multipart/encrypted message"
|
||||
);
|
||||
let parts: Vec<_> = (*(*mime).mm_data.mm_multipart.mm_mp_list)
|
||||
.into_iter()
|
||||
.map(|c| c as *mut Mailmime)
|
||||
.collect();
|
||||
ensure!(parts.len() == 2, "Invalid Autocrypt Level 1 Mime Parts");
|
||||
// XXX ensure protocol-parameter "application/pgp-encrypted")
|
||||
// XXX ensure wrapmime::get_content_type(parts[1])) == "application/octetstream"
|
||||
// a proper OpenPGP multipart/encrypted Autocrypt Level 1 message
|
||||
// https://tools.ietf.org/html/rfc3156.html#section-4
|
||||
Ok((mime, parts[1]))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has_decryptable_data(mime_data: *mut mailmime_data) -> bool {
|
||||
/* MAILMIME_DATA_FILE indicates, the data is in a file; AFAIK this is not used on parsing */
|
||||
unsafe {
|
||||
(*mime_data).dt_type == MAILMIME_DATA_TEXT as libc::c_int
|
||||
&& !(*mime_data).dt_data.dt_text.dt_data.is_null()
|
||||
&& (*mime_data).dt_data.dt_text.dt_length > 0
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_field_from(imffields: *mut mailimf_fields) -> Result<String, Error> {
|
||||
let field = mailimf_find_field(imffields, MAILIMF_FIELD_FROM as libc::c_int);
|
||||
if !field.is_null() && unsafe { !(*field).fld_data.fld_from.is_null() } {
|
||||
let mb_list = unsafe { (*(*field).fld_data.fld_from).frm_mb_list };
|
||||
if let Some(addr) = mailimf_find_first_addr(mb_list) {
|
||||
return Ok(addr);
|
||||
}
|
||||
}
|
||||
bail!("not From field found");
|
||||
}
|
||||
|
||||
pub fn get_field_date(imffields: *mut mailimf_fields) -> Result<i64, Error> {
|
||||
let field = mailimf_find_field(imffields, MAILIMF_FIELD_ORIG_DATE as libc::c_int);
|
||||
let mut message_time = 0;
|
||||
|
||||
if !field.is_null() && unsafe { !(*field).fld_data.fld_orig_date.is_null() } {
|
||||
let orig_date = unsafe { (*field).fld_data.fld_orig_date };
|
||||
|
||||
if !orig_date.is_null() {
|
||||
let dt = unsafe { (*orig_date).dt_date_time };
|
||||
message_time = dc_timestamp_from_date(dt);
|
||||
if message_time != 0 && message_time > time() {
|
||||
message_time = time()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(message_time)
|
||||
}
|
||||
|
||||
fn mailimf_get_recipients_add_addr(recipients: &mut HashSet<String>, mb: *mut mailimf_mailbox) {
|
||||
if !mb.is_null() {
|
||||
let addr = to_string_lossy(unsafe { (*mb).mb_addr_spec });
|
||||
let addr_norm = addr_normalize(&addr);
|
||||
recipients.insert(addr_norm.into());
|
||||
}
|
||||
}
|
||||
|
||||
/*the result is a pointer to mime, must not be freed*/
|
||||
pub fn mailimf_find_field(
|
||||
header: *mut mailimf_fields,
|
||||
wanted_fld_type: libc::c_int,
|
||||
) -> *mut mailimf_field {
|
||||
if header.is_null() {
|
||||
return ptr::null_mut();
|
||||
}
|
||||
|
||||
let header = unsafe { (*header) };
|
||||
if header.fld_list.is_null() {
|
||||
return ptr::null_mut();
|
||||
}
|
||||
|
||||
for cur in unsafe { &(*header.fld_list) } {
|
||||
let field = cur as *mut mailimf_field;
|
||||
if !field.is_null() {
|
||||
if unsafe { (*field).fld_type } == wanted_fld_type {
|
||||
return field;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
/*the result is a pointer to mime, must not be freed*/
|
||||
pub fn mailmime_find_mailimf_fields(mime: *mut Mailmime) -> *mut mailimf_fields {
|
||||
if mime.is_null() {
|
||||
return ptr::null_mut();
|
||||
}
|
||||
|
||||
match unsafe { (*mime).mm_type as _ } {
|
||||
MAILMIME_MULTIPLE => {
|
||||
for cur_data in unsafe { (*(*mime).mm_data.mm_multipart.mm_mp_list).into_iter() } {
|
||||
let header = mailmime_find_mailimf_fields(cur_data as *mut _);
|
||||
if !header.is_null() {
|
||||
return header;
|
||||
}
|
||||
}
|
||||
}
|
||||
MAILMIME_MESSAGE => return unsafe { (*mime).mm_data.mm_message.mm_fields },
|
||||
_ => {}
|
||||
}
|
||||
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
pub unsafe fn mailimf_find_optional_field(
|
||||
header: *mut mailimf_fields,
|
||||
wanted_fld_name: *const libc::c_char,
|
||||
) -> *mut mailimf_optional_field {
|
||||
if header.is_null() || (*header).fld_list.is_null() {
|
||||
return ptr::null_mut();
|
||||
}
|
||||
for cur_data in (*(*header).fld_list).into_iter() {
|
||||
let field: *mut mailimf_field = cur_data as *mut _;
|
||||
|
||||
if (*field).fld_type == MAILIMF_FIELD_OPTIONAL_FIELD as libc::c_int {
|
||||
let optional_field: *mut mailimf_optional_field = (*field).fld_data.fld_optional_field;
|
||||
if !optional_field.is_null()
|
||||
&& !(*optional_field).fld_name.is_null()
|
||||
&& !(*optional_field).fld_value.is_null()
|
||||
&& strcasecmp((*optional_field).fld_name, wanted_fld_name) == 0i32
|
||||
{
|
||||
return optional_field;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
pub fn mailimf_get_recipients(imffields: *mut mailimf_fields) -> HashSet<String> {
|
||||
/* returned addresses are normalized. */
|
||||
let mut recipients: HashSet<String> = Default::default();
|
||||
|
||||
for cur in unsafe { (*(*imffields).fld_list).into_iter() } {
|
||||
let fld = cur as *mut mailimf_field;
|
||||
|
||||
let fld_to: *mut mailimf_to;
|
||||
let fld_cc: *mut mailimf_cc;
|
||||
|
||||
let mut addr_list: *mut mailimf_address_list = ptr::null_mut();
|
||||
if fld.is_null() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let fld = unsafe { *fld };
|
||||
|
||||
// TODO match on enums /rtn
|
||||
match fld.fld_type {
|
||||
13 => {
|
||||
fld_to = unsafe { fld.fld_data.fld_to };
|
||||
if !fld_to.is_null() {
|
||||
addr_list = unsafe { (*fld_to).to_addr_list };
|
||||
}
|
||||
}
|
||||
14 => {
|
||||
fld_cc = unsafe { fld.fld_data.fld_cc };
|
||||
if !fld_cc.is_null() {
|
||||
addr_list = unsafe { (*fld_cc).cc_addr_list };
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if !addr_list.is_null() {
|
||||
for cur2 in unsafe { &(*(*addr_list).ad_list) } {
|
||||
let adr = cur2 as *mut mailimf_address;
|
||||
|
||||
if adr.is_null() {
|
||||
continue;
|
||||
}
|
||||
let adr = unsafe { *adr };
|
||||
|
||||
if adr.ad_type == MAILIMF_ADDRESS_MAILBOX as libc::c_int {
|
||||
mailimf_get_recipients_add_addr(&mut recipients, unsafe {
|
||||
adr.ad_data.ad_mailbox
|
||||
});
|
||||
} else if adr.ad_type == MAILIMF_ADDRESS_GROUP as libc::c_int {
|
||||
let group = unsafe { adr.ad_data.ad_group };
|
||||
if !group.is_null() && unsafe { !(*group).grp_mb_list.is_null() } {
|
||||
for cur3 in unsafe { &(*(*(*group).grp_mb_list).mb_list) } {
|
||||
mailimf_get_recipients_add_addr(
|
||||
&mut recipients,
|
||||
cur3 as *mut mailimf_mailbox,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
recipients
|
||||
}
|
||||
|
||||
pub fn mailmime_transfer_decode(mime: *mut Mailmime) -> Result<Vec<u8>, Error> {
|
||||
ensure!(!mime.is_null(), "invalid inputs");
|
||||
|
||||
let mime_transfer_encoding =
|
||||
get_mime_transfer_encoding(mime).unwrap_or(MAILMIME_MECHANISM_BINARY as i32);
|
||||
|
||||
let mime_data = unsafe { (*mime).mm_data.mm_single };
|
||||
|
||||
decode_dt_data(mime_data, mime_transfer_encoding)
|
||||
}
|
||||
|
||||
pub fn get_mime_transfer_encoding(mime: *mut Mailmime) -> Option<libc::c_int> {
|
||||
unsafe {
|
||||
let mm_mime_fields = (*mime).mm_mime_fields;
|
||||
if !mm_mime_fields.is_null() {
|
||||
for cur_data in (*(*mm_mime_fields).fld_list).into_iter() {
|
||||
let field: *mut mailmime_field = cur_data as *mut _;
|
||||
if (*field).fld_type == MAILMIME_FIELD_TRANSFER_ENCODING as libc::c_int
|
||||
&& !(*field).fld_data.fld_encoding.is_null()
|
||||
{
|
||||
return Some((*(*field).fld_data.fld_encoding).enc_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn decode_dt_data(
|
||||
mime_data: *mut mailmime_data,
|
||||
mime_transfer_encoding: libc::c_int,
|
||||
) -> Result<Vec<u8>, Error> {
|
||||
// Decode data according to mime_transfer_encoding
|
||||
// returns Ok with a (decoded_data,decoded_data_bytes) pointer
|
||||
// where the caller must make sure to free it.
|
||||
// It may return Ok(ptr::null_mut(), 0)
|
||||
if mime_transfer_encoding == MAILMIME_MECHANISM_7BIT as libc::c_int
|
||||
|| mime_transfer_encoding == MAILMIME_MECHANISM_8BIT as libc::c_int
|
||||
|| mime_transfer_encoding == MAILMIME_MECHANISM_BINARY as libc::c_int
|
||||
{
|
||||
let decoded_data = unsafe { (*mime_data).dt_data.dt_text.dt_data };
|
||||
let decoded_data_bytes = unsafe { (*mime_data).dt_data.dt_text.dt_length };
|
||||
|
||||
if decoded_data.is_null() || decoded_data_bytes == 0 {
|
||||
bail!("No data to decode found");
|
||||
} else {
|
||||
let result = unsafe {
|
||||
std::slice::from_raw_parts(decoded_data as *const u8, decoded_data_bytes)
|
||||
};
|
||||
return Ok(result.to_vec());
|
||||
}
|
||||
}
|
||||
// unsafe { display_mime_data(mime_data) };
|
||||
|
||||
let mut current_index = 0;
|
||||
let mut transfer_decoding_buffer = ptr::null_mut();
|
||||
let mut decoded_data_bytes = 0;
|
||||
|
||||
let r = unsafe {
|
||||
mailmime_part_parse(
|
||||
(*mime_data).dt_data.dt_text.dt_data,
|
||||
(*mime_data).dt_data.dt_text.dt_length,
|
||||
&mut current_index,
|
||||
mime_transfer_encoding,
|
||||
&mut transfer_decoding_buffer,
|
||||
&mut decoded_data_bytes,
|
||||
)
|
||||
};
|
||||
|
||||
if r == MAILIMF_NO_ERROR as libc::c_int
|
||||
&& !transfer_decoding_buffer.is_null()
|
||||
&& decoded_data_bytes > 0
|
||||
{
|
||||
let result = unsafe {
|
||||
std::slice::from_raw_parts(transfer_decoding_buffer as *const u8, decoded_data_bytes)
|
||||
}
|
||||
.to_vec();
|
||||
// we return a fresh vec and transfer_decoding_buffer is not used or passed anywhere
|
||||
// so it's safe to free it right away, as mailman_part_parse has
|
||||
// allocated it fresh.
|
||||
unsafe { mmap_string_unref(transfer_decoding_buffer) };
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
Err(format_err!("Failed to to decode"))
|
||||
}
|
||||
|
||||
pub fn mailimf_find_first_addr(mb_list: *const mailimf_mailbox_list) -> Option<String> {
|
||||
if mb_list.is_null() {
|
||||
return None;
|
||||
}
|
||||
|
||||
for cur in unsafe { (*(*mb_list).mb_list).into_iter() } {
|
||||
let mb = cur as *mut mailimf_mailbox;
|
||||
if !mb.is_null() && !unsafe { (*mb).mb_addr_spec.is_null() } {
|
||||
let addr = unsafe { to_string_lossy((*mb).mb_addr_spec) };
|
||||
return Some(addr_normalize(&addr).to_string());
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/**************************************
|
||||
* mime creation API
|
||||
**************************************/
|
||||
|
||||
pub fn add_filename_part(
|
||||
message: *mut Mailmime,
|
||||
basename: &str,
|
||||
mime_type: &str,
|
||||
file_content: &str,
|
||||
) -> Result<(), Error> {
|
||||
let mime_type_c = CString::new(mime_type.to_string()).expect("failed to create CString");
|
||||
unsafe {
|
||||
let content_type = mailmime_content_new_with_str(mime_type_c.as_ptr());
|
||||
let mime_fields = mailmime_fields_new_filename(
|
||||
MAILMIME_DISPOSITION_TYPE_ATTACHMENT as libc::c_int,
|
||||
basename.strdup(),
|
||||
MAILMIME_MECHANISM_8BIT as libc::c_int,
|
||||
);
|
||||
let file_mime_part = mailmime_new_empty(content_type, mime_fields);
|
||||
set_body_text(file_mime_part, file_content)?;
|
||||
mailmime_smart_add_part(message, file_mime_part);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn new_custom_field(fields: *mut mailimf_fields, name: &str, value: &str) {
|
||||
unsafe {
|
||||
let field = mailimf_field_new_custom(name.strdup(), value.strdup());
|
||||
let res = mailimf_fields_add(fields, field);
|
||||
assert!(
|
||||
res as u32 == MAILIMF_NO_ERROR,
|
||||
"could not create mailimf field"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build_body_text(text: &str) -> Result<*mut Mailmime, Error> {
|
||||
let mime_fields: *mut mailmime_fields;
|
||||
let message_part: *mut Mailmime;
|
||||
|
||||
let content = new_content_type("text/plain")?;
|
||||
append_ct_param(content, "charset", "utf-8")?;
|
||||
|
||||
unsafe {
|
||||
mime_fields = mailmime_fields_new_encoding(MAILMIME_MECHANISM_8BIT as libc::c_int);
|
||||
message_part = mailmime_new_empty(content, mime_fields);
|
||||
}
|
||||
set_body_text(message_part, text)?;
|
||||
|
||||
Ok(message_part)
|
||||
}
|
||||
|
||||
pub fn append_ct_param(
|
||||
content: *mut mailmime_content,
|
||||
name: &str,
|
||||
value: &str,
|
||||
) -> Result<(), Error> {
|
||||
unsafe {
|
||||
let name_c = CString::new(name).unwrap_or_default();
|
||||
let value_c = CString::new(value).unwrap_or_default();
|
||||
|
||||
clist_append!(
|
||||
(*content).ct_parameters,
|
||||
mailmime_param_new_with_data(
|
||||
name_c.as_ptr() as *const u8 as *const libc::c_char as *mut libc::c_char,
|
||||
value_c.as_ptr() as *const u8 as *const libc::c_char as *mut libc::c_char
|
||||
)
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn new_content_type(content_type: &str) -> Result<*mut mailmime_content, Error> {
|
||||
let ct = CString::new(content_type).unwrap_or_default();
|
||||
let content: *mut mailmime_content;
|
||||
// mailmime_content_new_with_str only parses but does not retain/own ct
|
||||
unsafe {
|
||||
content = mailmime_content_new_with_str(ct.as_ptr());
|
||||
}
|
||||
ensure!(!content.is_null(), "mailimf failed to allocate");
|
||||
Ok(content)
|
||||
}
|
||||
|
||||
pub fn set_body_text(part: *mut Mailmime, text: &str) -> Result<(), Error> {
|
||||
use libc::strlen;
|
||||
unsafe {
|
||||
let text_c = text.strdup();
|
||||
if 0 != mailmime_set_body_text(part, text_c, strlen(text_c)) {
|
||||
bail!("could not set body text on mime-structure");
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn content_type_needs_encoding(content: *const mailmime_content) -> bool {
|
||||
unsafe {
|
||||
if (*(*content).ct_type).tp_type == MAILMIME_TYPE_COMPOSITE_TYPE as libc::c_int {
|
||||
let composite = (*(*content).ct_type).tp_data.tp_composite_type;
|
||||
match (*composite).ct_type as u32 {
|
||||
MAILMIME_COMPOSITE_TYPE_MESSAGE => {
|
||||
to_string_lossy((*content).ct_subtype) != "rfc822"
|
||||
}
|
||||
MAILMIME_COMPOSITE_TYPE_MULTIPART => false,
|
||||
_ => false,
|
||||
}
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_mailbox_list(displayname: &str, addr: &str) -> *mut mailimf_mailbox_list {
|
||||
let mbox: *mut mailimf_mailbox_list = unsafe { mailimf_mailbox_list_new_empty() };
|
||||
unsafe {
|
||||
mailimf_mailbox_list_add(
|
||||
mbox,
|
||||
mailimf_mailbox_new(
|
||||
if !displayname.is_empty() {
|
||||
dc_encode_header_words(&displayname).strdup()
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
},
|
||||
addr.strdup(),
|
||||
),
|
||||
);
|
||||
}
|
||||
mbox
|
||||
Ok(&mail.subparts[1])
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_needs_encoding() {
|
||||
assert!(content_type_needs_encoding(
|
||||
new_content_type("text/plain").unwrap()
|
||||
));
|
||||
assert!(content_type_needs_encoding(
|
||||
new_content_type("application/octect-stream").unwrap()
|
||||
));
|
||||
assert!(!content_type_needs_encoding(
|
||||
new_content_type("multipart/encrypted").unwrap()
|
||||
));
|
||||
assert!(content_type_needs_encoding(
|
||||
new_content_type("application/pgp-encrypted").unwrap()
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_message_id() {
|
||||
assert_eq!(
|
||||
|
||||
@@ -14,7 +14,7 @@ use tempfile::{tempdir, TempDir};
|
||||
/* some data used for testing
|
||||
******************************************************************************/
|
||||
|
||||
unsafe fn stress_functions(context: &Context) {
|
||||
fn stress_functions(context: &Context) {
|
||||
let res = context.get_config(config::Config::SysConfigKeys).unwrap();
|
||||
|
||||
assert!(!res.contains(" probably_never_a_key "));
|
||||
@@ -224,10 +224,8 @@ fn create_test_context() -> TestContext {
|
||||
|
||||
#[test]
|
||||
fn test_stress_tests() {
|
||||
unsafe {
|
||||
let context = create_test_context();
|
||||
stress_functions(&context.ctx);
|
||||
}
|
||||
let context = create_test_context();
|
||||
stress_functions(&context.ctx);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user