summaryrefslogtreecommitdiffstats
path: root/melib
diff options
context:
space:
mode:
authorManos Pitsidianakis <el13635@mail.ntua.gr>2020-01-06 16:10:36 +0200
committerManos Pitsidianakis <el13635@mail.ntua.gr>2020-01-06 16:10:36 +0200
commitc0ac643f0545a0364c3b18c0fa92705399f8b238 (patch)
treef89f7a73c1c578a84712e116fa38c6644b21ff76 /melib
parentf6de511abdafb4cb08c0264df6e2c88cf88faaab (diff)
melib: add datetime module
Datetime module adds POSIX time functions interface
Diffstat (limited to 'melib')
-rw-r--r--melib/src/addressbook.rs18
-rw-r--r--melib/src/addressbook/vcard.rs3
-rw-r--r--melib/src/datetime.rs131
-rw-r--r--melib/src/email.rs19
-rw-r--r--melib/src/email/compose.rs7
-rw-r--r--melib/src/email/parser.rs10
-rw-r--r--melib/src/lib.rs4
-rw-r--r--melib/src/logging.rs5
-rw-r--r--melib/src/thread.rs8
9 files changed, 160 insertions, 45 deletions
diff --git a/melib/src/addressbook.rs b/melib/src/addressbook.rs
index 714d462c..3b592090 100644
--- a/melib/src/addressbook.rs
+++ b/melib/src/addressbook.rs
@@ -22,7 +22,7 @@
#[cfg(feature = "vcard")]
pub mod vcard;
-use chrono::{DateTime, Local};
+use crate::datetime::{self, UnixTimestamp};
use fnv::FnvHashMap;
use uuid::Uuid;
@@ -59,8 +59,8 @@ impl From<String> for CardId {
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct AddressBook {
display_name: String,
- created: DateTime<Local>,
- last_edited: DateTime<Local>,
+ created: UnixTimestamp,
+ last_edited: UnixTimestamp,
pub cards: FnvHashMap<CardId, Card>,
}
@@ -73,13 +73,13 @@ pub struct Card {
name_prefix: String,
name_suffix: String,
//address
- birthday: Option<DateTime<Local>>,
+ birthday: Option<UnixTimestamp>,
email: String,
url: String,
key: String,
color: u8,
- last_edited: DateTime<Local>,
+ last_edited: UnixTimestamp,
extra_properties: FnvHashMap<String, String>,
/// If true, we can't make any changes because we do not manage this resource.
@@ -90,8 +90,8 @@ impl AddressBook {
pub fn new(display_name: String) -> AddressBook {
AddressBook {
display_name,
- created: Local::now(),
- last_edited: Local::now(),
+ created: datetime::now(),
+ last_edited: datetime::now(),
cards: FnvHashMap::default(),
}
}
@@ -154,7 +154,7 @@ impl Card {
url: String::new(),
key: String::new(),
- last_edited: Local::now(),
+ last_edited: datetime::now(),
external_resource: false,
extra_properties: FnvHashMap::default(),
color: 0,
@@ -190,7 +190,7 @@ impl Card {
self.key.as_str()
}
pub fn last_edited(&self) -> String {
- self.last_edited.to_rfc2822()
+ datetime::timestamp_to_string(self.last_edited, None)
}
pub fn set_id(&mut self, new_val: CardId) {
diff --git a/melib/src/addressbook/vcard.rs b/melib/src/addressbook/vcard.rs
index 65488246..bc57e739 100644
--- a/melib/src/addressbook/vcard.rs
+++ b/melib/src/addressbook/vcard.rs
@@ -21,7 +21,6 @@
/// Convert VCard strings to meli Cards (contacts).
use super::*;
-use crate::chrono::TimeZone;
use crate::error::{MeliError, Result};
use crate::parsec::{match_literal_anycase, one_or_more, peek, prefix, take_until, Parser};
use fnv::FnvHashMap;
@@ -202,7 +201,7 @@ impl<V: VCardVersion> TryInto<Card> for VCard<V> {
T102200Z
T102200-0800
*/
- card.birthday = chrono::Local.datetime_from_str(&val.value, "%Y%m%d").ok();
+ card.birthday = crate::datetime::timestamp_from_string(val.value.as_str(), "%Y%m%d");
}
if let Some(val) = self.0.remove("EMAIL") {
card.set_email(val.value);
diff --git a/melib/src/datetime.rs b/melib/src/datetime.rs
new file mode 100644
index 00000000..7c56686f
--- /dev/null
+++ b/melib/src/datetime.rs
@@ -0,0 +1,131 @@
+/*
+ * meli - melib POSIX libc time interface
+ *
+ * Copyright 2020 Manos Pitsidianakis
+ *
+ * This file is part of meli.
+ *
+ * meli is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * meli is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with meli. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+use std::convert::TryInto;
+use std::ffi::{CStr, CString};
+
+pub type UnixTimestamp = u64;
+
+use libc::{timeval, timezone};
+
+extern "C" {
+ fn strptime(
+ s: *const ::std::os::raw::c_char,
+ format: *const ::std::os::raw::c_char,
+ tm: *mut ::libc::tm,
+ ) -> *const ::std::os::raw::c_char;
+
+ fn strftime(
+ s: *mut ::std::os::raw::c_char,
+ max: ::libc::size_t,
+ format: *const ::std::os::raw::c_char,
+ tm: *const ::libc::tm,
+ ) -> ::libc::size_t;
+
+ fn mktime(tm: *const ::libc::tm) -> ::libc::time_t;
+
+ fn localtime_r(timep: *const ::libc::time_t, tm: *mut ::libc::tm) -> *mut ::libc::tm;
+
+ fn gettimeofday(tv: *mut timeval, tz: *mut timezone) -> i32;
+}
+
+pub fn timestamp_to_string(timestamp: UnixTimestamp, fmt: Option<&str>) -> String {
+ let mut new_tm: ::libc::tm = unsafe { std::mem::zeroed() };
+ unsafe {
+ let i: i64 = timestamp.try_into().unwrap_or(0);
+ localtime_r(&i as *const i64, &mut new_tm as *mut ::libc::tm);
+ }
+ let fmt = fmt.map(|slice| CString::new(slice).unwrap());
+ let format: &CStr = if let Some(ref s) = fmt {
+ &s
+ } else {
+ unsafe { CStr::from_bytes_with_nul_unchecked(b"%a, %d %b %Y %T %z\0") }
+ };
+ let s: CString;
+ unsafe {
+ let mut vec: Vec<u8> = vec![0; 256];
+ let ret = strftime(
+ vec.as_mut_ptr() as *mut _,
+ 256,
+ format.as_ptr(),
+ &new_tm as *const _,
+ );
+ s = CString::new(&vec[0..ret]).unwrap();
+ }
+
+ s.to_string_lossy().to_string()
+}
+
+pub fn rfc822_to_timestamp<T>(s: T) -> UnixTimestamp
+where
+ T: Into<Vec<u8>>,
+{
+ let mut new_tm: ::libc::tm = unsafe { std::mem::zeroed() };
+ unsafe {
+ let fmt = CStr::from_bytes_with_nul_unchecked(b"%a, %e %h %Y %H:%M:%S %z\0");
+ let ret = strptime(
+ CString::new(s).unwrap().as_ptr(),
+ fmt.as_ptr(),
+ &mut new_tm as *mut _,
+ );
+ if ret.is_null() {
+ return 0;
+ }
+ return mktime(&new_tm as *const _) as u64;
+ }
+}
+
+pub fn timestamp_from_string<T>(s: T, fmt: &str) -> Option<UnixTimestamp>
+where
+ T: Into<Vec<u8>>,
+{
+ let mut new_tm: ::libc::tm = unsafe { std::mem::zeroed() };
+ let fmt = CString::new(fmt).unwrap();
+ unsafe {
+ let ret = strptime(
+ CString::new(s).unwrap().as_ptr(),
+ fmt.as_ptr(),
+ &mut new_tm as *mut _,
+ );
+ if ret.is_null() {
+ return None;
+ }
+ return Some(mktime(&new_tm as *const _) as u64);
+ }
+}
+
+pub fn now() -> UnixTimestamp {
+ use std::mem::MaybeUninit;
+ let mut tv = MaybeUninit::<::libc::timeval>::uninit();
+ let mut tz = MaybeUninit::<::libc::timezone>::uninit();
+ unsafe {
+ let ret = gettimeofday(tv.as_mut_ptr(), tz.as_mut_ptr());
+ if ret == -1 {
+ unreachable!("gettimeofday returned -1");
+ }
+ (tv.assume_init()).tv_sec as UnixTimestamp
+ }
+}
+
+#[test]
+fn test_timestamp() {
+ timestamp_to_string(0);
+}
diff --git a/melib/src/email.rs b/melib/src/email.rs
index 48f7c76b..cab8565e 100644
--- a/melib/src/email.rs
+++ b/melib/src/email.rs
@@ -39,6 +39,7 @@ pub use address::*;
pub mod signatures;
use crate::backends::BackendOp;
+use crate::datetime::UnixTimestamp;
use crate::error::{MeliError, Result};
use crate::thread::ThreadHash;
@@ -51,9 +52,6 @@ use std::option::Option;
use std::str;
use std::string::String;
-use chrono;
-use chrono::TimeZone;
-
bitflags! {
#[derive(Default, Serialize, Deserialize)]
pub struct Flag: u8 {
@@ -105,7 +103,6 @@ impl EnvelopeWrapper {
}
}
-pub type UnixTimestamp = u64;
pub type EnvelopeHash = u64;
/// `Envelope` represents all the data of an email we need to know.
@@ -350,14 +347,10 @@ impl Envelope {
self.timestamp
}
- pub fn datetime(&self) -> chrono::DateTime<chrono::FixedOffset> {
- if let Ok(d) = parser::date(&self.date.as_bytes()) {
- return d;
- }
- chrono::FixedOffset::west(0)
- .ymd(1970, 1, 1)
- .and_hms(0, 0, 0)
+ pub fn datetime(&self) -> UnixTimestamp {
+ self.timestamp
}
+
pub fn date_as_str(&self) -> &str {
&self.date
}
@@ -572,8 +565,8 @@ impl Envelope {
pub fn set_thread(&mut self, new_val: ThreadHash) {
self.thread = new_val;
}
- pub fn set_datetime(&mut self, new_val: chrono::DateTime<chrono::FixedOffset>) {
- self.timestamp = new_val.timestamp() as UnixTimestamp;
+ pub fn set_datetime(&mut self, new_val: UnixTimestamp) {
+ self.timestamp = new_val;
}
pub fn set_flag(
&mut self,
diff --git a/melib/src/email/compose.rs b/melib/src/email/compose.rs
index 594ae1ba..47b24f86 100644
--- a/melib/src/email/compose.rs
+++ b/melib/src/email/compose.rs
@@ -2,7 +2,6 @@ use super::*;
use crate::backends::BackendOp;
use crate::email::attachments::AttachmentBuilder;
use crate::shellexpand::ShellExpandTrait;
-use chrono::{DateTime, Local};
use data_encoding::BASE64_MIME;
use std::ffi::OsStr;
use std::io::Read;
@@ -35,8 +34,10 @@ impl Default for Draft {
headers.insert("Cc".into(), "".into());
headers.insert("Bcc".into(), "".into());
- let now: DateTime<Local> = Local::now();
- headers.insert("Date".into(), now.to_rfc2822());
+ headers.insert(
+ "Date".into(),
+ crate::datetime::timestamp_to_string(crate::datetime::now(), None),
+ );
headers.insert("Subject".into(), "".into());
headers.insert(
"User-Agent".into(),
diff --git a/melib/src/email/parser.rs b/melib/src/email/parser.rs
index 7a2aad28..b392f04e 100644
--- a/melib/src/email/parser.rs
+++ b/melib/src/email/parser.rs
@@ -19,7 +19,6 @@
* along with meli. If not, see <http://www.gnu.org/licenses/>.
*/
use super::*;
-use chrono;
use data_encoding::BASE64_MIME;
use encoding::{DecoderTrap, Encoding};
use nom::{is_hex_digit, le_u8};
@@ -658,18 +657,13 @@ fn eat_comments(input: &[u8]) -> Vec<u8> {
* right now we expect input will have no extra spaces in between tokens
*
* We should use a custom parser here*/
-pub fn date(input: &[u8]) -> Result<chrono::DateTime<chrono::FixedOffset>> {
+pub fn date(input: &[u8]) -> Result<UnixTimestamp> {
let mut parsed_result = phrase(&eat_comments(input)).to_full_result()?;
if let Some(pos) = parsed_result.find(b"-0000") {
parsed_result[pos] = b'+';
}
- Ok(
- chrono::DateTime::parse_from_rfc2822(
- String::from_utf8_lossy(parsed_result.trim()).as_ref(),
- )
- .map_err(|err| MeliError::new(err.to_string()))?,
- )
+ Ok(crate::datetime::rfc822_to_timestamp(parsed_result.trim()))
}
named!(pub message_id<&[u8]>,
diff --git a/melib/src/lib.rs b/melib/src/lib.rs
index 0ff5c75a..36cc0e72 100644
--- a/melib/src/lib.rs
+++ b/melib/src/lib.rs
@@ -104,6 +104,9 @@ pub mod dbg {
#[cfg(feature = "unicode_algorithms")]
extern crate text_processing;
+pub mod datetime;
+pub use datetime::UnixTimestamp;
+
#[macro_use]
mod logging;
pub use self::logging::LoggingLevel::*;
@@ -129,7 +132,6 @@ extern crate serde_derive;
/* parser */
#[macro_use]
extern crate nom;
-extern crate chrono;
extern crate data_encoding;
extern crate encoding;
diff --git a/melib/src/logging.rs b/melib/src/logging.rs
index 37985516..cef2fdb9 100644
--- a/melib/src/logging.rs
+++ b/melib/src/logging.rs
@@ -20,7 +20,6 @@
*/
use crate::shellexpand::ShellExpandTrait;
-use chrono::offset::Local;
use std::fs::OpenOptions;
use std::io::{BufWriter, Write};
use std::path::PathBuf;
@@ -79,7 +78,9 @@ pub fn log(val: String, level: LoggingLevel) {
let mut b = f.lock().unwrap();
if level <= b.level {
b.dest
- .write_all(Local::now().to_string().as_bytes())
+ .write_all(
+ crate::datetime::timestamp_to_string(crate::datetime::now(), None).as_bytes(),
+ )
.unwrap();
b.dest.write_all(b" [").unwrap();
b.dest.write_all(level.to_string().as_bytes()).unwrap();
diff --git a/melib/src/thread.rs b/melib/src/thread.rs
index a1f2445c..9c8fdbfe 100644
--- a/melib/src/thread.rs
+++ b/melib/src/thread.rs
@@ -32,6 +32,7 @@
* ownership.
*/
+use crate::datetime::UnixTimestamp;
use crate::email::parser::BytesExt;
use crate::email::*;
use crate::structs::StackVec;
@@ -432,13 +433,6 @@ impl ThreadNode {
self.date
}
- pub fn datetime(&self) -> chrono::DateTime<chrono::Utc> {
- use chrono::{TimeZone, Utc};
- use std::convert::TryInto;
-
- Utc.timestamp(self.date.try_into().unwrap_or(0), 0)
- }
-
pub fn is_empty(&self) -> bool {
self.parent.is_none() && self.message.is_none() && self.children.is_empty()
}