Giter Club home page Giter Club logo

ical-rs's Introduction

license Build Status Latest version Documentation

ical-rs

This library parses the iCalendar format defined in RFC5545, as well as similar formats like vCard.

There are probably some issues to be taken care of, but the library should work for most cases. If you like to help out and would like to discuss any API changes, please contact me or create an issue.

Initially, the goal was to port the JavaScript ical.js library. Many code/algorithms were taken from it at first; but in order to but more “Rusty”, a complete rewrite was made.

Installing

Put this in your Cargo.toml:

[dependencies]
ical = "0.10"

Overview

There are several ways to use the ical crate, depending on the level of parsing you want. Some new wrappers/formatters could appear in future releases.

By default all the features are included, but you can include only the features you need in your project.

Warning

The parsers (PropertyParser and IcalParser) only parse the content and uppercase the case-insensitive fields. No checks are made on the fields’ validity.

IcalParser / VcardParser

Wraps the result of the PropertyParser into components.

Each component can contains properties (ie: Property) or sub-components.

  • The IcalParser returns IcalCalendar
  • The VcardParser returns VcardContact

Cargo.toml:

[dependencies.ical]
version = "0.10"
default-features = false
features = ["ical", "vcard"]

Code:

extern crate ical;

use std::io::BufReader;
use std::fs::File;

fn main() {
    let buf = BufReader::new(File::open("/tmp/component.ics")
        .unwrap());

    let reader = ical::IcalParser::new(buf);

    for line in reader {
        println!("{:?}", line);
    }
}

Output:

IcalCalendar {
  properties: [],
  events: [
    IcalEvent {
      properties: [ Property { ... }, ... ],
      alarms: [
        IcalAlarm {
          properties: [ Property { ... } ]
        }
      ]
    }
  ],
  alarms: [],
  todos: [],
  journals: [],
  free_busys: [],
  timezones: []
}

PropertyParser

Parse the result of LineReader into three parts:

  • The name of the line attribute formatted in uppercase.
  • A vector of (key, value) tuples for the parameters:
    • The param key is formatted in uppercase.
    • The param value is untouched.
  • The property value is untouched.

It work for both the vCard and iCal formats.

Example:

Cargo.toml:

[dependencies.ical]
version = "0.10"
default-features = false
features = ["property"]

Code:

extern crate ical;

use std::io::BufReader;
use std::fs::File;

fn main() {
    let buf = BufReader::new(File::open("/tmp/component.ics")
        .unwrap());

    let reader = ical::PropertyParser::from_reader(buf);

    for line in reader {
        println!("{:?}", line);
    }
}

Input -> Output:

begin:VCALENDAR                           Ok(Property { name: "BEGIN", params: None, value: Some("VCALENDAR") })
ATTENDEE;cn=FooBar:mailto:foo3@bar    ->  Ok(Property { name: "ATTENDEE", params: Some([("CN", "FooBar")]), value: Some("mailto:foo3@bar") })
DESCRIPTION:                              Ok(Property { name: "DESCRIPTION": params: None, value: None })
END:VCALENDAR                             Ok(Property { name: "END", params: None, value: Some("VCALENDAR") })

LineReader

This is a very low-level parser. It cleans empty lines and unfolds them.

It work for both the vCard and iCal formats.

Example:

Cargo.toml:

[dependencies.ical]
version = "0.10"
default-features = false
features = ["line"]

Code:

extern crate ical;

use std::io::BufReader;
use std::fs::File;

fn main() {
    let buf = BufReader::new(File::open("/tmp/component.ics")
        .unwrap());

    let reader = ical::LineReader::new(buf);

    for line in reader {
        println!("{}", line);
    }
}

Input -> Output:

BEGIN:VCALENDAR        Line 0: BEGIN:VCALENDAR
BEGIN:VEVENT           Line 1: BEGIN:VEVENT
SUMMARY:foo and   ->   Line 3: SUMMARY:foo andbar
 bar
END:VEVENT             Line 4: END:VEVENT
END:VCALENDAR          Line 5: END:VCALENDAR

Generator

The other way to use ical is to generate ical/ics files. Builder for Events, Calendar and VCards ensure filling of mandatory fields.

A fair knowledge of the iCal-standards is necessary to create usable ics-files, even so the IcalEventBuilder helps to stick to the formalities.

Cargo.toml:

[dependencies.ical]
version = "0.10"
default-features = false
features = ["ical", "vcard", "generator"]

Code:

extern crate ical;

use crate::ical::{generator::*, *};

fn main() {
  let mut cal = IcalCalendarBuilder::version("2.0")
          .gregorian()
          .prodid("-//ical-rs//github.com//")
          .build();

  let event = IcalEventBuilder::tzid("Europe/Berlin")
          .uid("UID for identifying this event.")
          .changed("20210115")
          .one_day("20220101")
          .set(ical_property!("SUMMARY", "New Year"))
          .build();
  cal.events.push(event);

  print!("{}", cal.generate());
}

ical-rs's People

Contributors

daladim avatar ddnomad avatar fliegendewurst avatar jbg avatar klardotsh avatar link2xt avatar migmedia avatar peltoche avatar reedts avatar ronnybremer avatar westy92 avatar zearin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

ical-rs's Issues

Generator are not showing on doc.rs

I open this issue to signal that the whole generator module is not visible in doc.rs. It took me a while to figure out that this library can also do calendar generation besides of parsing, so I think it could be useful to show it on the docs.

IcalParser can't parse entries with missing values


**UPDATE**: Turns out, right after I posted this, I found the answer to parsing my file in particular, however, this should probably be handled sanely library-side. For Google Calendar events with no `DESCRIPTION` field, the entire IcalParser bugs out. Adding a value to `DESCRIPTION` of my example code below solved the problem and parsed my example. Talk about blind luck...

Perhaps `value` should be an `Option<...>` type, and allow `None` values?

The relevant source:

```rust
extern crate ical;

use self::ical::parser::ical::IcalParser;
use std::io::BufReader;
use std::fs::File;

pub fn entry() -> i32 {
	let file: File = match File::open("test_file.ics") {
		Ok(f) => f,
		Err(f) => {
			println!("{}", f);
			return 1;
		}
	};

	let input = IcalParser::new(BufReader::new(file));

	for line in input {
		println!("{:?}", line);
	}

	return 0;
}
```

and my ICS file (anonymized slightly):

```ical
BEGIN:VCALENDAR
PRODID:-//Google Inc//Google Calendar 70.9054//EN
VERSION:2.0
CALSCALE:GREGORIAN
METHOD:PUBLISH
BEGIN:VEVENT
DTSTART:20151017T110000Z
DTEND:20151017T210000Z
DTSTAMP:20170226T174202Z
UID:BC6D7B1B-499D-4F67-B356-4B75CB6BBA56
CREATED:20151009T204308Z
DESCRIPTION:
LAST-MODIFIED:20151013T185140Z
LOCATION:Github
SEQUENCE:0
STATUS:CONFIRMED
SUMMARY:[Some] Event
TRANSP:OPAQUE
END:VEVENT
END:VCALENDAR
```

Output:

```
Err(Parse(MissingValue))
Err(MissingHeader)
Err(MissingHeader)
Err(MissingHeader)
Err(MissingHeader)
Err(MissingHeader)
Err(MissingHeader)
Err(MissingHeader)
Err(MissingHeader)
```

Create wiki

Create a github wiki with Rust documentation

Parsing from a `String`?

I think this a relatively common use-case (e.g. when retrieving data from a remote server), where one has a String – is it possible to parse these directly?

Consider adding serde support ?

Thanks for this crate.

I wished it had a serde cargo feature, so that I could include e.g. parsed Propertys into my own structs that #[derive(Serialize)].

I can work around this by writing my own serializer (which is not terribly difficult), but it would be better if it was already included in your crate (I haven't really tried yet, but reading quickly into the serde documentation, it looks like the latter is more difficult than the former, so I'm not even sure I'll be able to do this myself and make a MR for this :-/ )

Add auto-detection for the Type and version used

The first two lines of a Vcard/Ical file must specify the protocole and its versions as:

BEGIN:VCARD
VERSION:4.0

Goal

Read this first two lines and load automatically the corresponding design set

vCard property group support

Hi @Peltoche

It looks like property groups are not supported.

From the spec https://www.rfc-editor.org/rfc/rfc6350#section-3.3 on page 6:

...
   contentline = [group "."] name *(";" param) ":" value CRLF
...
   group = 1*(ALPHA / DIGIT / "-")
...

And then page 7:

The group construct is used to group related properties together.
The group name is a syntactic convention used to indicate that all
property names prefaced with the same group name SHOULD be grouped
together when displayed by an application. It has no other
significance. Implementations that do not understand or support
grouping MAY simply strip off any text before a "." to the left of
the type name and present the types and values as normal.

So having vCard property line:

gr1.FN:Bob

The expectation would be something like:

let p = vcard.get_property("FN").unwrap();
assert_eq!(p.name, "FN");
assert_eq!(p.group, Some("gr1"));

IMHO, the key point here is that the property name should be "FN" and not "gr1.FN".

Is this functionality being considered? I could submit a PR.

Cheers

IcalEvent and others are private

I can't pass single events to other functions, because I can't reference the type IcalEvent by name, since it's in the private module “component”.

The same is true for everything else in ical::parser::ical::component except IcalParser, which is reexported from the top level module.

Handle dquote parameters values

The current parameter parser in LineParser handle only the PARAM_DELIMITER (';') without escaping dquotes.

This input is not handled correctly:

NOTE;CN="Foo;Bar":This is a note

The input is valid but the current parser will try to split the parameter at the PARAM_DELIMITER, producing and error or invalid (key/param).
Possible output:

Params: Vec<("CN", "\"Foo"), ("Bar\", "")>

Create a VcardParser

Should be acting like IcalParser and return a list of components. It should be easier as Vcard doesn't have recursive components.

Release a 0.8 version?

Hi,

(I'm not sure whether you received notifications about my previous messages in closed issues, so I'm creating a new issue, sorry for the duplication).
Now you've merged #44 , could you release a 0.8 version?

That's because I'd like to use ical in my own crate, and I cannot publish my own crate with dependencies that are not published in crates.io (and I'd like to avoid publishing a "temporary" fork of your crate that I'll have to deprecate once you publish 0.8...)

Thanks

Panics when fed invalid UTF-8 as input

To reproduce, feed the parser any invalid UTF-8.

My test was

fuzz_target!(|data: &[u8]| {
    let c = std::io::Cursor::new(data);
    for _ in ical::IcalParser::new(c) {}
});

The iterator is already over Result's to indicate errors, so I would expect invalid UTF-8 to be just an Err yielded.

failure is deprecated

Crate:  failure
Title:  failure is officially deprecated/unmaintained
Date:   2020-05-02
URL:    https://rustsec.org/advisories/RUSTSEC-2020-0036
Dependency tree: 
failure 0.1.8
└── ical 0.6.0

warning: 1 warning found

split_line is not multibyte aware

I recently encountered a panic when generating an iCal event, after a bit of debugging I found the function split_line to fail when the line break should be inserted at a multibyte character.

Here is a test code to demonstrate the issue:

fn main() {
   let s = "DESCRIPTION:ABCDEFGHIJ\\n\\nKLMNOPQRSTUVWXYZ123456789üABCDEFGHIJKLMNOPQRS\\n\\nTUVWXYZ123456ä7890ABCDEFGHIJKLM\\n\\nNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXöYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWX\\n\\nYZ1234567890abcdefghiÜjklm\\nnopqrstuvwx".to_string();
   let r1 = split_line2(s.clone());
   println!("{}", r1);
}

It fails with:

thread 'main' panicked at /rustc/82e1608dfa6e0b5569232559e3d385fea5a93112/library/alloc/src/string.rs:1688:9:
assertion failed: self.is_char_boundary(idx)
note: run with RUST_BACKTRACE=1 environment variable to display a backtrace

I will create a pull request with a different implementation, which is multibyte aware. Could you please check it out?

Thank you,

Ronny

Even more highlevel than PropertyParser

I need a crate to parse ical more high level than just to properties.

I was basically thinking of something like:

struct VEvent {
start: Option<TimeStamp>,
end: Option<TimeStamp>,
summary: ...
// Unsuported Properties
properties: Vec<Property>,
}

Is this something that can be implemented in the scope of this crate, as a PR? Or should I create a high-level crate depending on ical-rs?

[Question] State of the library

Hey @Peltoche

Is this library abandoned or feature-complete/stable?
Are there any known limitations, bugs? I stumbled upon this repo while looking for rust ical implementations.

Could not find `IcalReader` in `ical`

With:

[dependencies]
ical = "0.2.0"

I get "Could not find IcalReader in ical" error using the example from the README:

extern crate ical;

use std::io::BufReader;
use std::fs::File;

fn main() {
    let buf = BufReader::new(File::open("/england-and-wales.ics")
        .unwrap());

    let reader = ical::IcalReader::new(buf);

    for line in reader {
        println!("{:?}", line);
    }
}

Which newbie mistake am I making?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.