#vcard #rfc-6350 #parser #contact

vcard4

Fast and correct vCard parser for RFC6350

17 releases

0.5.2 Jun 28, 2024
0.5.0 Feb 9, 2024
0.4.4 Apr 18, 2023
0.4.3 Mar 20, 2023
0.1.4 Nov 9, 2022

#500 in Date and time

Download history 99/week @ 2024-07-03 59/week @ 2024-07-10 52/week @ 2024-07-17 147/week @ 2024-07-24 69/week @ 2024-07-31 100/week @ 2024-08-07 99/week @ 2024-08-14 47/week @ 2024-08-21 37/week @ 2024-08-28 16/week @ 2024-09-04 26/week @ 2024-09-11 28/week @ 2024-09-18 55/week @ 2024-09-25 51/week @ 2024-10-02 12/week @ 2024-10-09 71/week @ 2024-10-16

202 downloads per month
Used in 7 crates (2 directly)

MIT/Apache

155KB
4K SLoC

vCard

Fast and correct vCard parser based on RFC6350; see the API documentation for more information.

For interoperability with older software the parser will accept input with a CHARSET parameter that has a value of UTF-8, any other encoding value for CHARSET will generate an error. However, this parameter is not part of RFC6350 and is therefore not included in the string output for a vCard.

License is MIT or Apache-2.0.


lib.rs:

Fast and correct vCard parser based on RFC6350.

vCards inherently contain private information so this library implements a zeroize feature (which is enabled by default) to securely zero the memory for all the data in a vCard when it is dropped.

Certain external types cannot be zeroize'd due to the restrictions on implementing external traits on external types and are therefore exempt:

  • Uri
  • Time / UtcOffset / OffsetDateTime
  • LanguageTag (feature: language-tags)
  • Mime (feature: mime)

If the mime feature is enabled the MEDIATYPE parameter is parsed to a Mime struct otherwise it is a String.

If the language-tags feature is enabled the LANG property and the LANGUAGE parameter are parsed using the language-tags crate.

Serde support can be enabled with the serde feature.

Examples

Create a new vCard:

use vcard4::VcardBuilder;
let card = VcardBuilder::new("John Doe".to_owned())
    .nickname("Johnny".to_owned())
    .finish();
print!("{}", card);

Decoding and encoding:

use anyhow::Result;
use vcard4::parse;
pub fn main() -> Result<()> {
    let input = r#"BEGIN:VCARD
VERSION:4.0
FN:John Doe
NICKNAME:Johnny
END:VCARD"#;
    let cards = parse(input)?;
    let card = cards.first().unwrap();
    let encoded = card.to_string();
    let decoded = parse(&encoded)?.remove(0);
    assert_eq!(card, &decoded);
    Ok(())
}

Iterative parsing is useful if you only need the first vCard or wish to ignore vCards that have errors (possibly during an import operation):

use anyhow::Result;
use vcard4::iter;

pub fn main() -> Result<()> {
    let input = r#"BEGIN:VCARD
VERSION:4.0
FN:John Doe
END:VCARD

BEGIN:VCARD
VERSION:4.0
FN:Jane Doe
END:VCARD"#;
    let mut it = iter(input, true);
    print!("{}", it.next().unwrap()?);
    print!("{}", it.next().unwrap()?);
    assert!(matches!(it.next(), None));
    Ok(())
}

Implementation

  • The XML property is parsed and propagated but it is not validated as it is optional in the RFC.
  • IANA Tokens are not implemented.
  • The RFC requires a CRLF sequence for line breaks but for easier interoperability between platforms we treat the carriage return as optional.

Dependencies

~5MB
~65K SLoC