Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

initial import from http://icalendar.rubyforge.org/

  • Loading branch information...
commit d47e7ad1ae741eb5d85aa2505ebee15de11a8e53 0 parents
Mark Yoon authored
Showing with 4,050 additions and 0 deletions.
  1. +105 −0 .specification
  2. +56 −0 COPYING
  3. +340 −0 GPL
  4. +141 −0 README
  5. +110 −0 Rakefile
  6. +69 −0 docs/rfcs/itip_notes.txt
  7. BIN  docs/rfcs/rfc2425.pdf
  8. BIN  docs/rfcs/rfc2426.pdf
  9. BIN  docs/rfcs/rfc2445.pdf
  10. BIN  docs/rfcs/rfc2446.pdf
  11. BIN  docs/rfcs/rfc2447.pdf
  12. +738 −0 docs/rfcs/rfc3283.txt
  13. +45 −0 examples/create_cal.rb
  14. +20 −0 examples/parse_cal.rb
  15. +18 −0 examples/single_event.ics
  16. +34 −0 lib/hash_attrs.rb
  17. +36 −0 lib/icalendar.rb
  18. +43 −0 lib/icalendar/base.rb
  19. +104 −0 lib/icalendar/calendar.rb
  20. +438 −0 lib/icalendar/component.rb
  21. +44 −0 lib/icalendar/component/alarm.rb
  22. +123 −0 lib/icalendar/component/event.rb
  23. +37 −0 lib/icalendar/component/freebusy.rb
  24. +61 −0 lib/icalendar/component/journal.rb
  25. +87 −0 lib/icalendar/component/timezone.rb
  26. +64 −0 lib/icalendar/component/todo.rb
  27. +133 −0 lib/icalendar/conversions.rb
  28. +109 −0 lib/icalendar/helpers.rb
  29. +33 −0 lib/icalendar/parameter.rb
  30. +375 −0 lib/icalendar/parser.rb
  31. +32 −0 lib/meta.rb
  32. +71 −0 test/calendar_test.rb
  33. +44 −0 test/component/event_test.rb
  34. +13 −0 test/component/todo_test.rb
  35. +66 −0 test/component_test.rb
  36. +97 −0 test/conversions_test.rb
  37. +23 −0 test/fixtures/folding.ics
  38. +46 −0 test/fixtures/life.ics
  39. +119 −0 test/fixtures/simplecal.ics
  40. +23 −0 test/fixtures/single_event.ics
  41. +17 −0 test/interactive.rb
  42. +29 −0 test/parameter_test.rb
  43. +84 −0 test/parser_test.rb
  44. +23 −0 test/read_write.rb
105 .specification
@@ -0,0 +1,105 @@
+--- !ruby/object:Gem::Specification
+name: icalendar
+version: !ruby/object:Gem::Version
+ version: 1.0.2
+platform: ""
+authors:
+- Jeff Rose
+autorequire: icalendar
+bindir: bin
+cert_chain:
+date: 2007-11-24 00:00:00 -06:00
+default_executable:
+dependencies: []
+
+description: Implements the iCalendar specification (RFC-2445) in Ruby. This allows for the generation and parsing of .ics files, which are used by a variety of calendaring applications.
+email: rosejn@gmail.com
+executables: []
+
+extensions: []
+
+extra_rdoc_files:
+- README
+- COPYING
+- GPL
+files:
+- test/component
+- test/component/event_test.rb
+- test/component/todo_test.rb
+- test/parameter_test.rb
+- test/interactive.rb
+- test/coverage
+- test/component_test.rb
+- test/fixtures
+- test/fixtures/simplecal.ics
+- test/fixtures/folding.ics
+- test/fixtures/single_event.ics
+- test/fixtures/life.ics
+- test/read_write.rb
+- test/calendar_test.rb
+- test/parser_test.rb
+- test/conversions_test.rb
+- lib/icalendar
+- lib/icalendar/component
+- lib/icalendar/component/alarm.rb
+- lib/icalendar/component/event.rb
+- lib/icalendar/component/freebusy.rb
+- lib/icalendar/component/journal.rb
+- lib/icalendar/component/timezone.rb
+- lib/icalendar/component/todo.rb
+- lib/icalendar/conversions.rb
+- lib/icalendar/parameter.rb
+- lib/icalendar/component.rb
+- lib/icalendar/helpers.rb
+- lib/icalendar/parser.rb
+- lib/icalendar/calendar.rb
+- lib/icalendar/base.rb
+- lib/hash_attrs.rb
+- lib/icalendar.rb
+- lib/meta.rb
+- docs/api
+- docs/rfcs
+- docs/rfcs/itip_notes.txt
+- docs/rfcs/rfc2425.pdf
+- docs/rfcs/rfc2426.pdf
+- docs/rfcs/rfc2445.pdf
+- docs/rfcs/rfc2446.pdf
+- docs/rfcs/rfc2447.pdf
+- docs/rfcs/rfc3283.txt
+- examples/single_event.ics
+- examples/create_cal.rb
+- examples/parse_cal.rb
+- Rakefile
+- README
+- COPYING
+- GPL
+has_rdoc: true
+homepage: http://icalendar.rubyforge.org/
+post_install_message:
+rdoc_options:
+- --main
+- README
+require_paths:
+- bin
+- lib
+required_ruby_version: !ruby/object:Gem::Requirement
+ requirements:
+ - - ">"
+ - !ruby/object:Gem::Version
+ version: 0.0.0
+ version:
+required_rubygems_version: !ruby/object:Gem::Requirement
+ requirements:
+ - - ">="
+ - !ruby/object:Gem::Version
+ version: "0"
+ version:
+requirements: []
+
+rubyforge_project:
+rubygems_version: 0.9.5
+signing_key:
+specification_version: 1
+summary: A ruby implementation of the iCalendar specification (RFC-2445).
+test_files: []
+
56 COPYING
@@ -0,0 +1,56 @@
+Ruby is copyrighted free software by Yukihiro Matsumoto <matz@netlab.jp>.
+You can redistribute it and/or modify it under either the terms of the GPL
+(see the file GPL), or the conditions below:
+
+ 1. You may make and give away verbatim copies of the source form of the
+ software without restriction, provided that you duplicate all of the
+ original copyright notices and associated disclaimers.
+
+ 2. You may modify your copy of the software in any way, provided that
+ you do at least ONE of the following:
+
+ a) place your modifications in the Public Domain or otherwise
+ make them Freely Available, such as by posting said
+ modifications to Usenet or an equivalent medium, or by allowing
+ the author to include your modifications in the software.
+
+ b) use the modified software only within your corporation or
+ organization.
+
+ c) give non-standard binaries non-standard names, with
+ instructions on where to get the original software distribution.
+
+ d) make other distribution arrangements with the author.
+
+ 3. You may distribute the software in object code or binary form,
+ provided that you do at least ONE of the following:
+
+ a) distribute the binaries and library files of the software,
+ together with instructions (in the manual page or equivalent)
+ on where to get the original distribution.
+
+ b) accompany the distribution with the machine-readable source of
+ the software.
+
+ c) give non-standard binaries non-standard names, with
+ instructions on where to get the original software distribution.
+
+ d) make other distribution arrangements with the author.
+
+ 4. You may modify and include the part of the software into any other
+ software (possibly commercial). But some files in the distribution
+ are not written by the author, so that they are not under these terms.
+
+ For the list of those files and their copying conditions, see the
+ file LEGAL.
+
+ 5. The scripts and library files supplied as input to or produced as
+ output from the software do not automatically fall under the
+ copyright of the software, but belong to whomever generated them,
+ and may be sold commercially, and may be aggregated with this
+ software.
+
+ 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE.
340 GPL
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program 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 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
141 README
@@ -0,0 +1,141 @@
+= iCalendar -- Internet calendaring, Ruby style
+
+This is a Ruby library for dealing with iCalendar files. Rather than
+explaining myself, here is the introduction from RFC-2445, which
+defines the format:
+
+The use of calendaring and scheduling has grown considerably in the
+last decade. Enterprise and inter-enterprise business has become
+dependent on rapid scheduling of events and actions using this
+information technology. However, the longer term growth of calendaring
+and scheduling, is currently limited by the lack of Internet standards
+for the message content types that are central to these knowledgeware
+applications. This memo is intended to progress the level of
+interoperability possible between dissimilar calendaring and
+scheduling applications. This memo defines a MIME content type for
+exchanging electronic calendaring and scheduling information. The
+Internet Calendaring and Scheduling Core Object Specification, or
+iCalendar, allows for the capture and exchange of information normally
+stored within a calendaring and scheduling application; such as a
+Personal Information Manager (PIM) or a Group Scheduling product.
+
+The iCalendar format is suitable as an exchange format between
+applications or systems. The format is defined in terms of a MIME
+content type. This will enable the object to be exchanged using
+several transports, including but not limited to SMTP, HTTP, a file
+system, desktop interactive protocols such as the use of a memory-
+based clipboard or drag/drop interactions, point-to-point asynchronous
+communication, wired-network transport, or some form of unwired
+transport such as infrared might also be used.
+
+Now for some examples:
+
+## Probably want to start with this
+
+ require 'rubygems' # Unless you install from the tarball or zip.
+ require 'icalendar'
+ require 'date'
+
+ include Icalendar # Probably do this in your class to limit namespace overlap
+
+## Creating calendars and events is easy.
+
+ # Create a calendar with an event (standard method)
+ cal = Calendar.new
+ cal.event do
+ dtstart Date.new(2005, 04, 29)
+ dtend Date.new(2005, 04, 28)
+ summary "Meeting with the man."
+ description "Have a long lunch meeting and decide nothing..."
+ klass "PRIVATE"
+ end
+
+ cal.publish
+
+## Or you can make events like this
+ event = Event.new
+ event.start = DateTime.civil(2006, 6, 23, 8, 30)
+ event.summary = "A great event!"
+ cal.add_event(event)
+
+ event2 = cal.event # This automatically adds the event to the calendar
+ event2.start = DateTime.civil(2006, 6, 24, 8, 30)
+ event2.summary = "Another great event!"
+
+ # Now with support for property parameters
+ params = {"ALTREP" =>['"http://my.language.net"'], "LANGUAGE" => ["SPANISH"]}
+
+ cal.event do
+ dtstart Date.new(2005, 04, 29)
+ dtend Date.new(2005, 04, 28)
+ summary "This is a summary with params.", params
+ end
+
+ # We can output the calendar as a string to write to a file,
+ # network port, database etc.
+ cal_string = cal.to_ical
+ puts cal_string
+
+== Parsing iCalendars:
+
+ # Open a file or pass a string to the parser
+ cal_file = File.open("single_event.ics")
+
+ # Parser returns an array of calendars because a single file
+ # can have multiple calendars.
+ cals = Icalendar.parse(cal_file)
+ cal = cals.first
+
+ # Now you can access the cal object in just the same way I created it
+ event = cal.events.first
+
+ puts "start date-time: " + event.dtstart
+ puts "summary: " + event.summary
+
+== Finders:
+
+Often times in web apps and other interactive applications you'll need to
+lookup items in a calendar to make changes or get details. Now you can find
+everything by the unique id automatically associated with all components.
+
+ cal = Calendar.new
+ 10.times { cal.event } # Create 10 events with only default data.
+ some_event = cal.events[5] # Grab it from the array of events
+
+ # Use the uid as the key in your app
+ key = some_event.uid
+
+ # so later you can find it.
+ same_event = cal.find_event(key)
+
+== Examples:
+
+Check the unit tests for examples of most things you'll want to do, but please
+send me example code or let me know what's missing.
+
+== Download
+
+The latest release version of this library can be found at
+
+* http://rubyforge.org/projects/icalendar/
+
+Documentation can be found at
+
+* http://icalendar.rubyforge.org/
+
+== Installation
+
+It's all about rubygems:
+
+$ sudo gem install icalendar
+
+== License
+
+This library is released under the same license as Ruby itself.
+
+== Support & Contributions
+
+The iCalendar library homepage is http://icalendar.rubyforge.org/
+
+There is an icalendar-devel@rubyforge.org mailing list that can be
+used for asking questions, making comments or submitting patches.
110 Rakefile
@@ -0,0 +1,110 @@
+require 'rubygems'
+require 'rake'
+require 'rake/testtask'
+require 'rake/rdoctask'
+require 'rake/clean'
+require 'rake/contrib/sshpublisher'
+
+PKG_VERSION = "1.0.2"
+
+$VERBOSE = nil
+TEST_CHANGES_SINCE = Time.now - 600 # Recent tests = changed in last 10 minutes
+
+desc "Run all the unit tests"
+task :default => [ :test, :lines ]
+
+desc "Run the unit tests in test"
+Rake::TestTask.new(:test) { |t|
+ t.libs << "test"
+ t.test_files = FileList['test/*_test.rb', 'test/component/*_test.rb']
+ t.verbose = true
+}
+
+# rcov code coverage
+rcov_path = '/usr/local/bin/rcov'
+rcov_test_output = "./test/coverage"
+rcov_exclude = "interactive.rb,read_write.rb,fixtures"
+
+# Add our created paths to the 'rake clobber' list
+CLOBBER.include(rcov_test_output)
+
+desc 'Removes all previous unit test coverage information'
+task (:reset_unit_test_coverage) do |t|
+ rm_rf rcov_unit_test_output
+ mkdir rcov_unit_test_output
+end
+
+desc 'Run all unit tests with Rcov to measure coverage'
+Rake::TestTask.new(:rcov) do |t|
+ t.libs << "test"
+ t.pattern = 'test/**/*_test.rb'
+ t.ruby_opts << rcov_path
+ t.ruby_opts << "-o #{rcov_test_output}"
+ t.ruby_opts << "-x #{rcov_exclude}"
+ t.verbose = true
+end
+
+# Generate the RDoc documentation
+Rake::RDocTask.new(:doc) { |rdoc|
+ rdoc.main = 'README'
+ rdoc.rdoc_files.include('lib/**/*.rb', 'README')
+ rdoc.rdoc_files.include('GPL', 'COPYING')
+ rdoc.rdoc_dir = 'docs/api'
+ rdoc.title = "iCalendar -- Internet Calendaring for Ruby"
+ rdoc.options << "--include=examples --line-numbers --inline-source"
+ rdoc.options << "--accessor=ical_component,ical_property,ical_multi_property"
+}
+
+Gem::manage_gems
+require 'rake/gempackagetask'
+
+spec = Gem::Specification.new do |s|
+ s.name = "icalendar"
+ s.version = PKG_VERSION
+ s.homepage = "http://icalendar.rubyforge.org/"
+ s.platform = Gem::Platform::RUBY
+ s.summary = "A ruby implementation of the iCalendar specification (RFC-2445)."
+ s.description = "Implements the iCalendar specification (RFC-2445) in Ruby. This allows for the generation and parsing of .ics files, which are used by a variety of calendaring applications."
+
+ s.files = FileList["{test,lib,docs,examples}/**/*"].to_a
+ s.files += ["Rakefile", "README", "COPYING", "GPL" ]
+ s.require_path = "lib"
+ s.autorequire = "icalendar"
+ s.has_rdoc = true
+ s.extra_rdoc_files = ["README", "COPYING", "GPL"]
+ s.rdoc_options.concat ['--main', 'README']
+
+ s.author = "Jeff Rose"
+ s.email = "rosejn@gmail.com"
+end
+
+Rake::GemPackageTask.new(spec) do |pkg|
+ pkg.gem_spec = spec
+ pkg.need_tar = true
+ pkg.need_zip = true
+end
+
+desc 'Install the gem globally (requires sudo)'
+task :install => :package do |t|
+ `sudo gem install pkg/icalendar-#{PKG_VERSION}.gem`
+end
+
+task :lines do
+ lines = 0
+ codelines = 0
+ Dir.foreach("lib/icalendar") { |file_name|
+ next unless file_name =~ /.*rb/
+
+ f = File.open("lib/icalendar/" + file_name)
+
+ while line = f.gets
+ lines += 1
+ next if line =~ /^\s*$/
+ next if line =~ /^\s*#/
+ codelines += 1
+ end
+ }
+ puts "\n------------------------------\n"
+ puts "Total Lines: #{lines}"
+ puts "Lines of Code: #{codelines}"
+end
69 docs/rfcs/itip_notes.txt
@@ -0,0 +1,69 @@
+Set of methods used for transactions:
+
+PUBLISH:
+- Publish a calendar entry to one or more users.
+
+REQUEST:
+- Used to schedule a calendar entry with other users.
+- Require REPLY messages from others.
+- Used by Organizers to update status of entries.
+
+REPLY:
+- Attendees use this to send information back to Organizers who have sent a
+ REQUEST message.
+
+ADD:
+- Add one or more instances to an existing entry.
+
+CANCEL:
+- Cancel a calendar item.
+
+REFRESH:
+- Attendee's use this to get the latest version of an item.
+
+COUNTER:
+- Used by an attendee to negotiate a change in a calendar entry.
+
+DECLINE-COUNTER:
+- Used by an organizer to decline a COUNTER message.
+
+
+Transports:
+
+Real-time vs. Store-and-forward?
+
+Entry Status:
+- Only the organizer can set the STATUS property
+- Attendee's use the "partstat" parameter of the ATTENDEE property to convey
+ their personal status.
+- Initial value of "partstat" is set to "NEEDS-ACTION" by organizer
+- Modifying this state is part of an attendee's REPLY message.
+
+Sequence Property:
+- Used to tell manage different versions of an entry
+- Has specific rules so look at these
+
+Handling messages should be done in this manner:
+
+1. The primary key for referencing a particular iCalendar component
+ is the "UID" property value. To reference an instance of a
+ recurring component, the primary key is composed of the "UID" and
+ the "RECURRENCE-ID" properties.
+2. The secondary key for referencing a component is the "SEQUENCE"
+ property value. For components where the "UID" is the same, the
+ component with the highest numeric value for the "SEQUENCE"
+ property obsoletes all other revisions of the component with
+ lower values.
+3. "Attendees" send "REPLY" messages to the "Organizer". For
+ replies where the "UID" property value is the same, the value of
+ the "SEQUENCE" property indicates the revision of the component
+ to which the "Attendee" is replying. The reply with the highest
+ numeric value for the "SEQUENCE" property obsoletes all other
+ replies with lower values.
+4. In situations where the "UID" and "SEQUENCE" properties match,
+ the "DTSTAMP" property is used as the tie-breaker. The component
+ with the latest "DTSTAMP" overrides all others. Similarly, for
+ "Attendee" responses where the "UID" property values match and
+ the "SEQUENCE" property values match, the response with the
+ latest "DTSTAMP" overrides all others.
+
BIN  docs/rfcs/rfc2425.pdf
Binary file not shown
BIN  docs/rfcs/rfc2426.pdf
Binary file not shown
BIN  docs/rfcs/rfc2445.pdf
Binary file not shown
BIN  docs/rfcs/rfc2446.pdf
Binary file not shown
BIN  docs/rfcs/rfc2447.pdf
Binary file not shown
738 docs/rfcs/rfc3283.txt
@@ -0,0 +1,738 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<HTML>
+<HEAD>
+<TITLE>RFC 3283 (rfc3283) - Guide to Internet Calendaring</TITLE>
+<META name="description" content="RFC 3283 - Guide to Internet Calendaring">
+<script language="JavaScript1.2">
+function erfc(s)
+{document.write("<A href=\"/rfccomment.php?rfcnum="+s+"\" target=\"_blank\" onclick=\"window.open('/rfccomment.php?rfcnum="+s+"','Popup','toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=yes,width=680,height=530,left=30,top=43'); return false;\")>Comment on RFC "+s+"</A>\n");}
+//-->
+</script>
+</HEAD>
+<BODY BGCOLOR="#ffffff" TEXT="#000000">
+<P ALIGN=CENTER><IMG SRC="/images/library.jpg" HEIGHT=62 WIDTH=150 BORDER="0" ALIGN="MIDDLE" ALT=""></P>
+<H1 ALIGN=CENTER>RFC 3283 (RFC3283)</H1>
+<P ALIGN=CENTER>Internet RFC/STD/FYI/BCP Archives</P>
+
+<DIV ALIGN=CENTER>[ <a href="/rfcs/">RFC Index</a> | <A HREF="/rfcs/rfcsearch.html">RFC Search</A> | <a href="/faqs/">Usenet FAQs</a> | <a href="/contrib/">Web FAQs</a> | <a href="/docs/">Documents</a> | <a href="http://www.city-data.com/">Cities</a> ]
+<P>
+<STRONG>Alternate Formats:</STRONG>
+ <A HREF="/ftp/rfc/rfc3283.txt">rfc3283.txt</A></DIV>
+<p align=center><script language="JavaScript"><!--
+erfc("3283");
+// --></script></p>
+<h3 align=center>RFC 3283 - Guide to Internet Calendaring</h3>
+<HR SIZE=2 NOSHADE>
+<PRE>
+
+Network Working Group B. Mahoney
+Request for Comments: 3283 MIT
+Category: Informational G. Babics
+ Steltor
+ A. Taler
+ June 2002
+
+ Guide to Internet Calendaring
+
+Status of this Memo
+
+ This memo provides information for the Internet community. It does
+ not specify an Internet standard of any kind. Distribution of this
+ memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2002). All Rights Reserved.
+
+Abstract
+
+ This document describes the various Internet calendaring and
+ scheduling standards and works in progress, and the relationships
+ between them. Its intent is to provide a context for these
+ documents, assist in their understanding, and potentially aid in the
+ design of standards-based calendaring and scheduling systems. The
+ standards addressed are <A HREF="/rfcs/rfc2445.html">RFC 2445</A> (iCalendar), <A HREF="/rfcs/rfc2446.html">RFC 2446</A> (iTIP), and
+ <A HREF="/rfcs/rfc2447.html">RFC 2447</A> (iMIP). The work in progress addressed is "Calendar Access
+ Protocol" (CAP). This document also describes issues and problems
+ that are not solved by these protocols, and that could be targets for
+ future work.
+
+Table of Contents
+
+ 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 2
+ 1.1 Terminology . . . . . . . . . . . . . . . . . . . . . . . . 2
+ 1.2 Concepts and Relationships . . . . . . . . . . . . . . . . . 4
+ 2. Requirements . . . . . . . . . . . . . . . . . . . . . . . . 4
+ 2.1 Fundamental Needs . . . . . . . . . . . . . . . . . . . . . 4
+ 2.2 Protocol Requirements . . . . . . . . . . . . . . . . . . . 5
+ 3. Solutions . . . . . . . . . . . . . . . . . . . . . . . . . 7
+ 3.1 Examples . . . . . . . . . . . . . . . . . . . . . . . . . . 7
+ 3.2 Systems . . . . . . . . . . . . . . . . . . . . . . . . . . 8
+ 3.2.1 Standalone Single-user System . . . . . . . . . . . . . . . 8
+ 3.2.2 Single-user Systems Communicating . . . . . . . . . . . . . 8
+ 3.2.3 Single-user with Multiple CUAs . . . . . . . . . . . . . . . 9
+ 3.2.4 Single-user with Multiple Calendars . . . . . . . . . . . . 9
+
+ 3.2.5 Users Communicating on a Multi-user System . . . . . . . . . 10
+ 3.2.6 Users Communicating through Different Multi-user Systems . . 10
+ 4. Important Aspects . . . . . . . . . . . . . . . . . . . . . 10
+ 4.1 Timezones . . . . . . . . . . . . . . . . . . . . . . . . . 10
+ 4.2 Choice of Transport . . . . . . . . . . . . . . . . . . . . 11
+ 4.3 Security . . . . . . . . . . . . . . . . . . . . . . . . . . 11
+ 4.4 Amount of data . . . . . . . . . . . . . . . . . . . . . . . 11
+ 4.5 Recurring Components . . . . . . . . . . . . . . . . . . . . 11
+ 5. Open Issues . . . . . . . . . . . . . . . . . . . . . . . . 11
+ 5.1 Scheduling People, not Calendars . . . . . . . . . . . . . . 12
+ 5.2 Administration . . . . . . . . . . . . . . . . . . . . . . . 12
+ 5.3 Notification . . . . . . . . . . . . . . . . . . . . . . . . 12
+ 6. Security Considerations . . . . . . . . . . . . . . . . . . 12
+ 6.1 Access Control . . . . . . . . . . . . . . . . . . . . . . . 12
+ 6.2 Authentication . . . . . . . . . . . . . . . . . . . . . . . 12
+ 6.3 Using E-mail . . . . . . . . . . . . . . . . . . . . . . . . 13
+ 6.4 Other Issues . . . . . . . . . . . . . . . . . . . . . . . . 13
+ Acknowledgments . . . . . . . . . . . . . . . . . . . . . . 13
+ References . . . . . . . . . . . . . . . . . . . . . . . . . 14
+ Authors' Addresses . . . . . . . . . . . . . . . . . . . . . 15
+ Full Copyright Statement . . . . . . . . . . . . . . . . . . 16
+
+1. Introduction
+
+ Calendaring and scheduling protocols are intended to aid individuals
+ in obtaining calendaring information and scheduling meetings across
+ the Internet, to aid organizations in providing calendaring
+ information on the Internet, and to provide for organizations looking
+ for a calendaring and scheduling solution to deploy internally.
+
+ It is the intent of this document to provide a context for these
+ documents, assist in their understanding, and potentially help in the
+ design of standards-based calendaring and scheduling systems.
+
+ Problems not solved by these protocols, as well as security issues to
+ be kept in mind, are discussed at the end of the document.
+
+1.1 Terminology
+
+ This memo uses much of the same terminology as iCalendar [<A HREF="/rfcs/rfc2445.html">RFC-2445</A>],
+ iTIP [<A HREF="/rfcs/rfc2446.html">RFC-2446</A>], iMIP [<A HREF="/rfcs/rfc2447.html">RFC-2447</A>], and [CAP]. The following
+ definitions are provided as an introduction; the definitions in the
+ protocol specifications themselves should be considered canonical.
+
+ Calendar
+
+ A collection of events, to-dos, journal entries, etc. A calendar
+ could be the content of a person or resource's agenda; it could
+ also be a collection of data serving a more specialized need.
+ Calendars are the basic storage containers for calendaring
+ information.
+
+ Calendar Access Rights
+
+ A set of rules defining who may perform what operations, such as
+ reading or writing information, on a given calendar.
+
+ Calendar Service
+
+ A running server application that provides access to a number of
+ calendar stores.
+
+ Calendar Store (CS)
+
+ A data store of a calendar service. A calendar service may have
+ several calendar stores, and each store may contain several
+ calendars, as well as properties and components outside of those
+ calendars.
+
+ Calendar User (CU)
+
+ An entity (often a human) that accesses calendar information.
+
+ Calendar User Agent (CUA)
+
+ Software with which the calendar user communicates with a calendar
+ service or local calendar store to access calendar information.
+
+ Component
+
+ A piece of calendar data such as an event, a to-do or an alarm.
+ Information about components is stored as properties of those
+ components.
+
+ Delegator
+
+ A calendar user who has assigned his or her participation in a
+ scheduled calendar component (e.g. a VEVENT) to another calendar
+ user (sometimes called the delegate or delegatee). An example of
+ a delegator is a busy executive sending an employee to a meeting
+ in his or her place.
+
+ Delegate
+
+ A calendar user (sometimes called the delegatee) who has been
+ assigned to participate in a scheduled calendar component (e.g. a
+ VEVENT) in place of one of the attendees in that component
+ (sometimes called the delegator). An example of a delegate is a
+ team member sent to a particular meeting.
+
+ Designate
+
+ A calendar user authorized to act on behalf of another calendar
+ user. An example of a designate is an assistant scheduling
+ meetings for his or her superior.
+
+ Local Store
+
+ A CS that is on the same device as the CUA.
+
+ Property
+
+ A description of some element of a component, such as a start
+ time, title or location.
+
+ Remote Store
+
+ A CS that is not on the same device as the CUA.
+
+1.2 Concepts and Relationships
+
+ iCalendar is the language used to describe calendar objects. iTIP
+ describes a way to use the iCalendar language to do scheduling. iMIP
+ describes how to do iTIP scheduling via e-mail. CAP describes a way
+ to use the iCalendar language to access a calendar store in real-
+ time.
+
+ The relationship between calendaring protocols is similar to that
+ between e-mail protocols. In those terms, iCalendar is analogous to
+ <A HREF="/rfcs/rfc2822.html">RFC 2822</A>, iTIP and iMIP are analogous to the Simple Mail Transfer
+ Protocol (SMTP), and CAP is analogous to the Post Office Protocol
+ (POP) or Internet Message Access Protocol (IMAP).
+
+2. Requirements
+
+2.1 Fundamental Needs
+
+ The following scenarios illustrate people and organizations' basic
+ calendaring and scheduling needs:
+
+ a] A doctor wishes to keep track of all her appointments.
+
+ Need: To read and manipulate one's own calendar with only one CUA.
+
+ b] A busy musician wants to maintain her schedule with multiple
+ devices, such as through an Internet-based agenda and with a PDA.
+
+ Need: To read and manipulate one's own calendar, possibly with
+ solutions from different vendors.
+
+ c] A software development team wishes to more effectively schedule
+ their time through viewing each other's calendar information.
+
+ Need: To share calendar information between users of the same
+ calendar service.
+
+ d] A teacher wants his students to schedule appointments during
+ his office hours.
+
+ Need: To schedule calendar events, to-dos and journals with other
+ users of the same calendar service.
+
+ e] A movie theater wants to publish its schedule for prospective
+ customers.
+
+ Need: To share calendar information with users of other calendar
+ services, possibly from a number of different vendors.
+
+ f] A social club wants to schedule calendar entries effectively
+ with its members.
+
+ Need: To schedule calendar events and to-dos with users of other
+ calendar services, possibly from a number of different vendors.
+
+2.2 Protocol Requirements
+
+ Some of these needs can be met by proprietary solutions (a, c, d),
+ but others can not (b, e, f). These latter scenarios show that
+ standard protocols are required for accessing information in a
+ calendar store and scheduling calendar entries. In addition, these
+ protocols require a common data format for representing calendar
+ information.
+
+ These requirements are met by the following protocol specifications.
+
+ - Data format: iCalendar [<A HREF="/rfcs/rfc2445.html">RFC-2445</A>]
+
+ iCalendar [<A HREF="/rfcs/rfc2445.html">RFC-2445</A>] provides a data format for representing
+ calendar information, to be used and exchanged by other protocols.
+ iCalendar [<A HREF="/rfcs/rfc2445.html">RFC-2445</A>] can also be used in other contexts, such as a
+ drag-and-drop interface, or an export/import feature. All the
+ other calendaring protocols depend on iCalendar [<A HREF="/rfcs/rfc2445.html">RFC-2445</A>], so all
+ elements of a standards-based calendaring and scheduling systems
+ will have to be able to interpret iCalendar [<A HREF="/rfcs/rfc2445.html">RFC-2445</A>].
+
+ - Scheduling protocol: iTIP [<A HREF="/rfcs/rfc2446.html">RFC-2446</A>]
+
+ iTIP [<A HREF="/rfcs/rfc2446.html">RFC-2446</A>] describes the messages used to schedule calendar
+ events. Within iTIP messages, events are represented in iCalendar
+ [<A HREF="/rfcs/rfc2445.html">RFC-2445</A>] format, and have semantics that identify the message as
+ being an invitation to a meeting, an acceptance of an invitation,
+ or the assignment of a task.
+
+ iTIP [<A HREF="/rfcs/rfc2446.html">RFC-2446</A>] messages are used in the scheduling workflow,
+ where users exchange messages in order to organize things such as
+ events and to-dos. CUAs generate and interpret iTIP [<A HREF="/rfcs/rfc2446.html">RFC-2446</A>]
+ messages at the direction of the calendar user. With iTIP [RFC-
+ 2446] users can create, modify, delete, reply to, counter, and
+ decline counters to the various iCalendar [<A HREF="/rfcs/rfc2445.html">RFC-2445</A>] components.
+ Furthermore, users can also request the free/busy time of other
+ people.
+
+ iTIP [<A HREF="/rfcs/rfc2446.html">RFC-2446</A>] is transport-independent, and has one specified
+ transport binding: iMIP [<A HREF="/rfcs/rfc2447.html">RFC-2447</A>] binds iTIP to e-mail. In
+ addition [CAP] will provide a real-time binding of iTIP [RFC-
+ 2446], allowing CUAs to perform calendar management and scheduling
+ over a single connection.
+
+ - Calendar management protocol: [CAP]
+
+ [CAP] describes the messages used to manage calendars on a
+ calendar store. These messages use iCalendar [<A HREF="/rfcs/rfc2445.html">RFC-2445</A>] to
+ describe various components such as events and to-dos. These
+ messages make it possible to perform iTIP [<A HREF="/rfcs/rfc2446.html">RFC-2446</A>] operations,
+ as well as other operations relating to a calendar store such as
+ searching, creating calendars, specifying calendar properties, and
+ specifying calendar access rights.
+
+3. Solutions
+
+3.1 Examples
+
+ Returning to the scenarios presented in section 2.1, the calendaring
+ protocols can be used in the following ways:
+
+ a] The doctor can use a proprietary CUA with a local store, and
+ perhaps use iCalendar [<A HREF="/rfcs/rfc2445.html">RFC-2445</A>] as a storage mechanism. This
+ would allow her to easily import her data store into another
+ application that supports iCalendar [<A HREF="/rfcs/rfc2445.html">RFC-2445</A>].
+
+ b] The musician who wishes to access her agenda from anywhere can
+ use a [CAP]-enabled calendar service accessible over the Internet.
+ She can then use any available [CAP] clients to access the data.
+
+ A proprietary system that provides access through a Web-based
+ interface could also be employed, but the use of [CAP] would be
+ superior in that it would allow the use of third party
+ applications, such as PDA synchronization tools.
+
+ c] The development team can use a calendar service which supports
+ [CAP], and each member can use a [CAP]-enabled CUA of their
+ choice.
+
+ Alternatively, each member could use an iMIP [<A HREF="/rfcs/rfc2447.html">RFC-2447</A>]-enabled
+ CUA, and they could book meetings over e-mail. This solution has
+ the drawback that it is difficult to examine other users' agendas,
+ making the organization of meetings more difficult.
+
+ Proprietary solutions are also available, but they require that
+ all members use clients by the same vendor, and disallow the use
+ of third party applications.
+
+ d] The teacher can set up a calendar service, and have students
+ book time through any of the iTIP [<A HREF="/rfcs/rfc2446.html">RFC-2446</A>] bindings. [CAP]
+ provides real-time access, but could require additional
+ configuration. iMIP [<A HREF="/rfcs/rfc2447.html">RFC-2447</A>] would be the easiest to configure,
+ but may require more e-mail processing.
+
+ If [CAP] access is provided then determining the state of the
+ teacher's schedule is straightforward. If not, this can be
+ determined through iTIP [<A HREF="/rfcs/rfc2446.html">RFC-2446</A>] free/busy requests. Non-
+ standard methods could also be employed, such as serving up
+ iCalendar [<A HREF="/rfcs/rfc2445.html">RFC-2445</A>], HTML, or XML over HTTP.
+
+ A proprietary system could also be used, but would require that
+ all students be able to use software from a specific vendor.
+
+ e] [CAP] would be preferred for publishing a movie theater's
+ schedule, since it provides advanced access and search
+ capabilities. It also allows easy integration with customers'
+ calendar systems.
+
+ Non-standard methods such as serving data over HTTP could also be
+ employed, but would be harder to integrate with customers'
+ systems.
+
+ Using a completely proprietary solution would be very difficult,
+ if not impossible, since it would require every user to install
+ and use the proprietary software.
+
+ f] The social club could distribute meeting information in the
+ form of iTIP [<A HREF="/rfcs/rfc2446.html">RFC-2446</A>] messages, sent via e-mail using iMIP
+ [<A HREF="/rfcs/rfc2447.html">RFC-2447</A>]. The club could distribute meeting invitations, as
+ well as a full published agenda.
+
+ Alternatively, the club could provide access to a [CAP]-enabled
+ calendar service. However, this solution would be more expensive
+ since it requires the maintenance of a server.
+
+3.2 Systems
+
+ The following diagrams illustrate possible systems and their usage of
+ the various protocols.
+
+3.2.1 Standalone Single-user System
+
+ A single user system that does not communicate with other systems
+ need not employ any of the protocols. However, it may use iCalendar
+ [<A HREF="/rfcs/rfc2445.html">RFC-2445</A>] as a data format in some places.
+
+ ----------- O
+ | CUA w/ | -+- user
+ |local store| A
+ ----------- / \
+
+3.2.2 Single-user Systems Communicating
+
+ Users with single-user systems may schedule meetings with each others
+ using iTIP [<A HREF="/rfcs/rfc2446.html">RFC-2446</A>]. The easiest binding of iTIP [<A HREF="/rfcs/rfc2446.html">RFC-2446</A>] to use
+ would be iMIP [<A HREF="/rfcs/rfc2447.html">RFC-2447</A>], since messages can be held in the users'
+ mail queues, which we assume to already exist. [CAP] could also be
+ used.
+
+ O ----------- ----------- O
+ -+- | CUA w/ | -----[iMIP]----- | CUA w/ | -+- user
+ A |local store| Internet |local store| A
+ / \ ----------- ----------- / \
+
+3.2.3 Single-user with Multiple CUAs
+
+ A single user may use more than one CUA to access his or her
+ calendar. The user may use a PDA, a Web client, a PC, or some other
+ device, depending on accessibility. Some of these clients may have
+ local stores and others may not. Those with local stores need to
+ synchronize the data on the CUA with the data on the CS.
+
+ -----------
+ | CUA w | -----[CAP]----------+
+ |local store| |
+ O ----------- ----------
+ -+- | CS |
+ A | |
+ / \ ----------
+ ----------- |
+ | CUA w/o | -----[CAP]----------+
+ |local store|
+ -----------
+
+3.2.4 Single-user with Multiple Calendars
+
+ A single user may have many independent calendars; for example, one
+ may contain work-related information and another personal
+ information. The CUA may or may not have a local store. If it does,
+ then it needs to synchronize the data of the CUA with the data on
+ both of the CS.
+
+ ----------
+ +------------[CAP]------ | CS |
+ | | |
+ O ----------- ----------
+ -+- | CUA |
+ A | |
+ / \ -----------
+ | ----------
+ +------------[CAP]------ | CS |
+ | |
+ ----------
+
+3.2.5 Users Communicating on a Multi-user System
+
+ Users on a multi-user system may schedule meetings with each other
+ using [CAP]-enabled CUAs and services. The CUAs may or may not have
+ local stores. Those with local stores need to synchronize the data
+ on the CUAs with the data on the CS.
+
+ O -----------
+ -+- | CUA w | -----[CAP]----------+
+ A |local store| |
+ / \ ----------- ----------
+ | CS |
+ | |
+ ----------
+ O ----------- |
+ -+- | CUA w/o | -----[CAP]----------+
+ A |local store|
+ / \ -----------
+
+3.2.6 Users Communicating through Different Multi-user Systems
+
+ Users on a multi-user system may need to schedule meetings with users
+ on a different multi-user system. The services can communicate using
+ [CAP] or iMIP [<A HREF="/rfcs/rfc2447.html">RFC-2447</A>].
+
+ O ----------- ----------
+ -+- | CUA w | -----[CAP]-------| CS |
+ A |local store| | |
+ / \ ----------- ----------
+ |
+ [CAP] or [iMIP]
+ |
+ O ----------- ----------
+ -+- | CUA w/o | -----[CAP]-------| CS |
+ A |local store| | |
+ / \ ----------- ----------
+
+4. Important Aspects
+
+ There are a number of important aspects of these calendaring
+ standards of which people, especially implementers, should be aware.
+
+4.1 Timezones
+
+ The dates and times in components can refer to a specific time zone.
+ Time zones can be defined in a central store, or they may be defined
+ by a user to fit his or her needs. All users and applications should
+ be aware of time zones and time zone differences. New time zones may
+
+ need to be added, and others removed. Two different vendors may
+ describe the same time zone differently (such as by using a different
+ name).
+
+4.2 Choice of Transport
+
+ There are issues to be aware of in choosing between a network
+ protocol such as [CAP], or a store and forward protocol, such as iMIP
+ [<A HREF="/rfcs/rfc2447.html">RFC-2447</A>].
+
+ The use of a network ("on-the-wire") mechanism may require some
+ organizations to make provisions to allow calendaring traffic to
+ traverse a corporate firewall on the required ports. Depending on
+ the organizational culture, this may be a challenging social
+ exercise.
+
+ The use of an email-based mechanism exposes time-sensitive data to
+ unbounded latency. Large or heavily utilized mail systems may
+ experience an unacceptable delay in message receipt.
+
+4.3 Security
+
+ See the "Security Considerations" (Section 6) section below.
+
+4.4 Amount of data
+
+ In some cases, a component may be very large, for instance, a
+ component with a very large attachment. Some applications may be
+ low-bandwidth or may be limited in the amount of data they can store.
+ Maximum component size may be set in [CAP]. It can also be
+ controlled in iMIP [<A HREF="/rfcs/rfc2447.html">RFC-2447</A>] by restricting the maximum size of the
+ e-mail that the application can download.
+
+4.5 Recurring Components
+
+ In iCAL [<A HREF="/rfcs/rfc2445.html">RFC-2445</A>], one can specify complex recurrence rules for
+ VEVENTs, VTODOs, and VJOURNALs. One must be careful to correctly
+ interpret these recurrence rules and pay extra attention to being
+ able to interoperate using them.
+
+5. Open Issues
+
+ Many issues are not currently resolved by these protocols, and many
+ desirable features are not yet provided. Some of the more prominent
+ ones are outlined below.
+
+5.1 Scheduling People, not Calendars
+
+ Meetings are scheduled with people; however, people may have many
+ calendars, and may store these calendars in many places. There may
+ also be many routes to contact them. The calendaring protocols do
+ not attempt to provide unique access for contacting a given person.
+ Instead, 'calendar addresses' are booked, which may be e-mail
+ addresses or individual calendars. It is up to the users themselves
+ to orchestrate mechanisms to ensure that the bookings go to the right
+ place.
+
+5.2 Administration
+
+ The calendaring protocols do not address the issues of administering
+ users and calendars on a calendar service. This must be handled by
+ proprietary mechanisms for each implementation.
+
+5.3 Notification
+
+ People often wish to be notified of upcoming events, new events, or
+ changes to existing events. The calendaring protocols do not attempt
+ to address these needs in a real-time system. Instead, the ability
+ to store alarm information on events is provided, which can be used
+ to provide client-side notification of upcoming events. To organize
+ notification of new or changed events, clients have to poll the data
+ store.
+
+6. Security Considerations
+
+6.1 Access Control
+
+ There has to be reasonable granularity in the configuration options
+ for access to data through [CAP], so that what should be released to
+ requesters is released, and what shouldn't is not. Details of
+ handling this are described in [CAP].
+
+6.2 Authentication
+
+ Access control must be coupled with a good authentication system, so
+ that the right people get the right information. For [CAP], this
+ means requiring authentication before any database access can be
+ performed, and checking access rights and authentication credentials
+ before releasing information. [CAP] uses the Simple Authentication
+ Security Layer (SASL) for this authentication. In iMIP [<A HREF="/rfcs/rfc2447.html">RFC-2447</A>],
+ this may present some challenges, as authentication is often not a
+ consideration in store-and-forward protocols.
+
+ Authentication is also important for scheduling, in that receivers of
+ scheduling messages should be able to validate the apparent sender.
+ Since scheduling messages are wrapped in MIME [<A HREF="/rfcs/rfc2045.html">RFC-2045</A>], signing and
+ encryption are freely available. For messages transmitted over mail,
+ this is the only available alternative. It is suggested that
+ developers take care in implementing the security features in iMIP
+ [<A HREF="/rfcs/rfc2447.html">RFC-2447</A>], bearing in mind that the concept and need may be foreign
+ or non-obvious to users, yet essential for the system to function as
+ they might expect.
+
+ The real-time protocols provide for the authentication of users, and
+ the preservation of that authentication information, allowing for
+ validation by the receiving end-user or server.
+
+6.3 Using E-mail
+
+ Because scheduling information can be transmitted over mail without
+ any authentication information, e-mail spoofing is extremely easy if
+ the receiver is not checking for authentication. It is suggested
+ that implementers consider requiring authentication as a default,
+ using mechanisms such as are described in Section 3 of iMIP [RFC-
+ 2447]. The use of e-mail, and the potential for anonymous
+ connections, means that 'calendar spam' is possible. Developers
+ should consider this threat when designing systems, particularly
+ those that allow for automated request processing.
+
+6.4 Other Issues
+
+ The current security context should be obvious to users. Because the
+ underlying mechanisms may not be clear to users, efforts to make
+ clear the current state in the UI should be made. One example of
+ this is the 'lock' icon used in some Web browsers during secure
+ connections.
+
+ With both iMIP [<A HREF="/rfcs/rfc2447.html">RFC-2447</A>] and [CAP], the possibilities of Denial of
+ Service attacks must be considered. The ability to flood a calendar
+ system with bogus requests is likely to be exploited once these
+ systems become widely deployed, and detection and recovery methods
+ will need to be considered.
+
+Acknowledgments
+
+ Thanks to the following, who have participated in the development of
+ this document:
+
+ Eric Busboom, Pat Egen, David Madeo, Shawn Packwood, Bruce Kahn,
+ Alan Davies, Robb Surridge.
+
+References
+
+ [<A HREF="/rfcs/rfc2445.html">RFC-2445</A>] Dawson, F. and D. Stenerson, "Internet Calendaring and
+ Scheduling Core Object Specification - iCalendar", RFC
+ 2445, November 1998.
+
+ [<A HREF="/rfcs/rfc2446.html">RFC-2446</A>] Silverberg, S., Mansour, S., Dawson, F. and R. Hopson,
+ "iCalendar Transport-Independent Interoperability Protocol
+ (iTIP): Scheduling Events, Busy Time, To-dos and Journal
+ Entries", <A HREF="/rfcs/rfc2446.html">RFC 2446</A>, November 1998.
+
+ [<A HREF="/rfcs/rfc2447.html">RFC-2447</A>] Dawson, F., Mansour, S. and S. Silverberg, "iCalendar
+ Message-Based Interoperability Protocol - iMIP", <A HREF="/rfcs/rfc2447.html">RFC 2447</A>,
+ November 1998.
+
+ [<A HREF="/rfcs/rfc2045.html">RFC-2045</A>] Freed, N. and N. Borenstein, "Multipurpose Internet Mail
+ Extensions (MIME) - Part One: Format of Internet Message
+ Bodies", <A HREF="/rfcs/rfc2045.html">RFC 2045</A>, November 1996.
+
+ [CAP] Mansour, S., Royer, D., Babics, G., and Hill, P.,
+ "Calendar Access Protocol (CAP)", Work in Progress.
+
+Authors' Addresses
+
+ Bob Mahoney
+ MIT
+ E40-327
+ 77 Massachusetts Avenue
+ Cambridge, MA 02139
+ US
+
+ Phone: (617) 253-0774
+ EMail: <A HREF="mailto:bobmah@mit.edu">bobmah@mit.edu</A>
+
+ George Babics
+ Steltor
+ 2000 Peel Street
+ Montreal, Quebec H3A 2W5
+ CA
+
+ Phone: (514) 733-8500 x4201
+ EMail: <A HREF="mailto:georgeb@steltor.com">georgeb@steltor.com</A>
+
+ Alexander Taler
+
+ EMail: <A HREF="mailto:alex@0--0.org">alex@0--0.org</A>
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (2002). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+</PRE>
+<p align=center><script language="JavaScript"><!--
+erfc("3283");
+// --></script></p>
+&nbsp;<br>
+<div align="center">
+<table border="0" cellpadding="3" width="100%" cellspacing="3">
+<tr><td width="45%">
+<p align="left">Previous: <a href="/rfcs/rfc3282.html">RFC 3282 - Content Language Headers</a>
+</p></td><td width="10%">&nbsp;</td><td width="45%">
+<p align="right">Next: <a href="/rfcs/rfc3284.html">RFC 3284 - The VCDIFF Generic Differencing and Compression Data Format</a>
+</p></td></tr></table></div><p align="right">&nbsp;</p>
+<HR SIZE=2 NOSHADE>
+<DIV ALIGN=CENTER>[ <a href="/rfcs/">RFC Index</a> | <A HREF="/rfcs/rfcsearch.html">RFC Search</A> | <a href="/faqs/">Usenet FAQs</a> | <a href="/contrib/">Web FAQs</a> | <a href="/docs/">Documents</a> | <a href="http://www.city-data.com/">Cities</a> ]
+<P>
+</DIV>
+<ADDRESS>
+<P ALIGN=CENTER>
+
+</P>
+</ADDRESS>
+</SMALL>
+</BODY>
+</HTML>
+
45 examples/create_cal.rb
@@ -0,0 +1,45 @@
+#!/usr/bin/env ruby
+## Need this so we can require the library from the samples directory
+$:.unshift(File.dirname(__FILE__) + '/../lib')
+
+require 'rubygems' # Unless you install from the tarball or zip.
+require 'icalendar'
+require 'date'
+
+include Icalendar # Probably do this in your class to limit namespace overlap
+
+## Creating calendars and events is easy.
+
+# Create a calendar with an event (standard method)
+cal = Calendar.new
+cal.event do
+ dtstart Date.new(2005, 04, 29)
+ dtend Date.new(2005, 04, 28)
+ summary "Meeting with the man."
+ description "Have a long lunch meeting and decide nothing..."
+ klass "PRIVATE"
+end
+
+## Or you can make events like this
+event = Event.new
+event.start = DateTime.civil(2006, 6, 23, 8, 30)
+event.summary = "A great event!"
+cal.add_event(event)
+
+event2 = cal.event # This automatically adds the event to the calendar
+event2.start = DateTime.civil(2006, 6, 24, 8, 30)
+event2.summary = "Another great event!"
+
+# Now with support for property parameters
+params = {"ALTREP" =>['"http://my.language.net"'], "LANGUAGE" => ["SPANISH"]}
+
+cal.event do
+ dtstart Date.new(2005, 04, 29)
+ dtend Date.new(2005, 04, 28)
+ summary "This is a summary with params.", params
+end
+
+# We can output the calendar as a string to write to a file,
+# network port, database etc.
+cal_string = cal.to_ical
+puts cal_string
20 examples/parse_cal.rb
@@ -0,0 +1,20 @@
+#!/usr/bin/env ruby
+## Need this so we can require the library from the samples directory
+$:.unshift(File.dirname(__FILE__) + '/../lib')
+
+require 'icalendar'
+require 'date'
+
+# Open a file or string to parse
+cal_file = File.open("../test/life.ics")
+
+# Parser returns an array of calendars because a single file
+# can have multiple calendar objects.
+cals = Icalendar::parse(cal_file)
+cal = cals.first
+
+# Now you can access the cal object in just the same way I created it
+event = cal.events.first
+
+puts "start date-time: " + event.dtstart.to_s
+puts "summary: " + event.summary
18 examples/single_event.ics
@@ -0,0 +1,18 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:bsprodidfortestabc123
+BEGIN:VEVENT
+UID:bsuidfortestabc123
+SUMMARY:This is a really long summary
+ to test the method of unfolding lines
+ so I'm just going to ma
+ ke it
+ a whol
+ e
+ bunch of lines.
+CLASS:PRIVATE
+DTSTART;TZID=US-Mountain:20050120T170000
+DTEND:20050120T184500
+DTSTAMP:20050118T211523Z
+END:VEVENT
+END:VCALENDAR
34 lib/hash_attrs.rb
@@ -0,0 +1,34 @@
+# A module which adds some generators for hash based accessors.
+module HashAttrs
+
+ def hash_reader(hash_sym, syms)
+ syms.each do |id|
+ id = id.to_s.downcase
+ func = Proc.new do
+ hash = instance_variable_get(hash_sym)
+ hash[id.to_sym]
+ end
+
+ self.send(:define_method, id, func)
+ end
+ end
+
+ def hash_writer(hash_sym, syms)
+ syms.each do |id|
+ id = id.to_s.downcase
+
+ func = Proc.new do |val|
+ hash = instance_variable_get(hash_sym)
+ hash[id.to_sym] = val
+ end
+
+ self.send(:define_method, id+'=', func)
+ end
+ end
+
+ def hash_accessor(hash, *syms)
+ hash_reader(hash, syms)
+ hash_writer(hash, syms)
+ end
+end
+
36 lib/icalendar.rb
@@ -0,0 +1,36 @@
+=begin
+ Copyright (C) 2005 Jeff Rose
+
+ This library is free software; you can redistribute it and/or modify it
+ under the same terms as the ruby language itself, see the file COPYING for
+ details.
+=end
+
+$:.unshift(File.dirname(__FILE__))
+
+### Base classes and mixin modules
+
+# to_ical methods for built-in classes
+require 'icalendar/conversions'
+
+# Meta-programming helper methods
+require 'meta'
+
+# Hash attributes mixin module
+require 'hash_attrs'
+
+require 'icalendar/base'
+require 'icalendar/component'
+
+# Calendar and components
+require 'icalendar/calendar'
+require 'icalendar/component/event'
+require 'icalendar/component/journal'
+require 'icalendar/component/todo'
+require 'icalendar/component/freebusy'
+require 'icalendar/component/timezone'
+require 'icalendar/component/alarm'
+
+# Calendar parser
+require 'icalendar/parser'
+
43 lib/icalendar/base.rb
@@ -0,0 +1,43 @@
+=begin
+ Copyright (C) 2005 Jeff Rose
+
+ This library is free software; you can redistribute it and/or modify it
+ under the same terms as the ruby language itself, see the file COPYING for
+ details.
+=end
+require 'logger'
+
+module Icalendar #:nodoc:
+
+ # A simple error class to differentiate iCalendar library exceptions
+ # from ruby language exceptions or others.
+ class IcalendarError < StandardError #:nodoc:
+ end
+
+ # Exception used when the library encounters a bogus calendar component.
+ class UnknownComponentClass < IcalendarError
+ end
+
+ # Exception used when the library encounters a bogus property type.
+ class UnknownPropertyMethod< IcalendarError
+ end
+
+ # Exception used when the library encounters a bogus property value.
+ class InvalidPropertyValue < IcalendarError
+ end
+
+ # This class serves as the base class for just about everything in
+ # the library so that the logging system can be configured in one place.
+ class Base
+ @@logger = Logger.new(STDERR)
+ @@logger.level = Logger::FATAL
+
+ def self.debug
+ @@logger.level = Logger::DEBUG
+ end
+
+ def self.quiet
+ @@logger.level = Logger::FATAL
+ end
+ end
+end
104 lib/icalendar/calendar.rb
@@ -0,0 +1,104 @@
+=begin
+ Copyright (C) 2005 Jeff Rose
+
+ This library is free software; you can redistribute it and/or modify it
+ under the same terms as the ruby language itself, see the file COPYING for
+ details.
+=end
+
+module Icalendar
+
+ class Calendar < Component
+ ical_component :events, :todos, :journals, :freebusys, :timezones
+
+ ical_property :calscale, :calendar_scale
+ ical_property :prodid, :product_id
+ ical_property :version
+ ical_property :ip_method
+
+ def initialize()
+ super("VCALENDAR")
+
+ # Set some defaults
+ self.calscale = "GREGORIAN" # Who knows, but this is the only one in the spec.
+ self.prodid = "iCalendar-Ruby" # Current product... Should be overwritten by apps that use the library
+ self.version = "2.0" # Version of the specification
+ end
+
+ def event(&block)
+ e = Event.new
+ self.add_component e
+
+ e.instance_eval &block if block
+
+ e
+ end
+
+ def find_event(uid)
+ self.events.find {|e| e.uid == uid}
+ end
+
+ def todo(&block)
+ e = Todo.new
+ self.add_component e
+
+ e.instance_eval &block if block
+
+ e
+ end
+
+ def find_todo(uid)
+ self.todos.find {|t| t.uid == uid}
+ end
+
+ def journal(&block)
+ e = Journal.new
+ self.add_component e
+
+ e.instance_eval &block if block
+
+ e
+ end
+
+ def find_journal(uid)
+ self.journals.find {|j| j.uid == uid}
+ end
+
+ def freebusy(&block)
+ e = Freebusy.new
+ self.add_component e
+
+ e.instance_eval &block if block
+
+ e
+ end
+
+ def find_freebusy(uid)
+ self.freebusys.find {|f| f.uid == uid}
+ end
+
+ def timezone(&block)
+ e = Timezone.new
+ self.add_component e
+
+ e.instance_eval &block if block
+
+ e
+ end
+
+ # The "PUBLISH" method in a "VEVENT" calendar component is an
+ # unsolicited posting of an iCalendar object. Any CU may add published
+ # components to their calendar. The "Organizer" MUST be present in a
+ # published iCalendar component. "Attendees" MUST NOT be present. Its
+ # expected usage is for encapsulating an arbitrary event as an
+ # iCalendar object. The "Organizer" may subsequently update (with
+ # another "PUBLISH" method), add instances to (with an "ADD" method),
+ # or cancel (with a "CANCEL" method) a previously published "VEVENT"
+ # calendar component.
+ def publish
+ self.ip_method = "PUBLISH"
+ end
+
+ end # class Calendar
+
+end # module Icalendar
438 lib/icalendar/component.rb
@@ -0,0 +1,438 @@
+=begin
+ Copyright (C) 2005 Jeff Rose
+
+ This library is free software; you can redistribute it and/or modify it
+ under the same terms as the ruby language itself, see the file COPYING for
+ details.
+=end
+
+module Icalendar
+ require 'socket'
+
+ MAX_LINE_LENGTH = 75
+
+ class Geo < Icalendar::Base
+ attr_accessor :latitude, :longitude
+ alias :lat :latitude
+ alias :long :longitude
+
+ def initialize(lat, long)
+ @lat = lat
+ @long = long
+ end
+
+ def to_ical
+ "#{@lat.to_ical};#{@long.to_ical}"
+ end
+ end
+
+ # The body of the iCalendar object consists of a sequence of calendar
+ # properties and one or more calendar components. The calendar
+ # properties are attributes that apply to the calendar as a whole. The
+ # calendar components are collections of properties that express a
+ # particular calendar semantic. For example, the calendar component can
+ # specify an Event, a Todo, a Journal entry, Timezone information, or
+ # Freebusy time information, or an Alarm.
+ class Component < Icalendar::Base
+
+ meta_include HashAttrs
+
+ attr_reader :name
+ attr_accessor :properties
+
+ @@multi_properties = {}
+ @@multiline_properties = {}
+
+ def initialize(name)
+ @name = name
+ @components = Hash.new([])
+ @properties = {}
+
+ @@logger.info("New #{@name[1,@name.size].capitalize}...")
+ end
+
+ # Add a sub-component to the current component object.
+ def add_component(component)
+ key = (component.class.to_s.downcase + 's').gsub('icalendar::', '').to_sym
+
+ unless @components.has_key? key
+ @components[key] = []
+ end
+
+ @components[key] << component
+ end
+
+ # Add a component to the calendar.
+ alias add add_component
+
+ # Add an event to the calendar.
+ alias add_event add_component
+
+ # Add a todo item to the calendar.
+ alias add_todo add_component
+
+ # Add a journal item to the calendar.
+ alias add_journal add_component
+
+ def remove_component(component)
+ key = (component.class.to_s.downcase + 's').gsub('icalendar::', '').to_sym
+
+ if @components.has_key? key
+ @components[key].delete(component)
+ end
+ end
+
+ # Remove a component from the calendar.
+ alias remove remove_component
+
+ # Remove an event from the calendar.
+ alias remove_event remove_component
+
+ # Remove a todo item from the calendar.
+ alias remove_todo remove_component
+
+ # Remove a journal item from the calendar.
+ alias remove_journal remove_component
+
+ # Used to generate unique component ids
+ def new_uid
+ "#{DateTime.now}_#{rand(999999999)}@#{Socket.gethostname}"
+ end
+
+ # Output in the icalendar format
+ def to_ical
+ print_component do
+ s = ""
+ @components.each_value do |comps|
+ comps.each { |component| s << component.to_ical }
+ end
+ s
+ end
+ end
+
+ # Print this icalendar component
+ def print_component
+ # Begin a new component
+ "BEGIN:#{@name.upcase}\r\n" +
+
+ # Then the properties
+ print_properties +
+
+ # sub components
+ yield +
+
+ # End of this component
+ "END:#{@name.upcase}\r\n"
+ end
+
+ # Print this components properties
+ def print_properties
+ s = ""
+
+ @properties.each do |key,val|
+ # Take out underscore for property names that conflicted
+ # with built-in words.
+ if key =~ /ip_.*/
+ key = key[3..-1]
+ end
+
+ # Property name
+ unless multiline_property?(key)
+ prelude = "#{key.gsub(/_/, '-').upcase}" +
+
+ # Possible parameters
+ print_parameters(val)
+
+ # Property value
+ value = ":#{val.to_ical}"
+ escaped = prelude + value.gsub("\\", "\\\\").gsub("\n", "\\n").gsub(",", "\\,").gsub(";", "\\;")
+ s << escaped.slice!(0, MAX_LINE_LENGTH) << "\r\n " while escaped.size > MAX_LINE_LENGTH
+ s << escaped << "\r\n"
+ s.gsub!(/ *$/, '')
+ else
+ prelude = "#{key.gsub(/_/, '-').upcase}"
+ val.each do |v|
+ params = print_parameters(v)
+ value = ":#{v.to_ical}"
+ escaped = prelude + params + value.gsub("\\", "\\\\").gsub("\n", "\\n").gsub(",", "\\,").gsub(";", "\\;")
+ s << escaped.slice!(0, MAX_LINE_LENGTH) << "\r\n " while escaped.size > MAX_LINE_LENGTH
+ s << escaped << "\r\n"
+ s.gsub!(/ *$/, '')
+ end
+ end
+ end
+ s
+ end
+
+ # Print the parameters for a specific property
+ def print_parameters(val)
+ s = ""
+ return s unless val.respond_to?(:ical_params) and not val.ical_params.nil?
+
+ val.ical_params.each do |key,val|
+ s << ";#{key}"
+ val = [ val ] unless val.is_a?(Array)
+
+ # Possible parameter values
+ unless val.empty?
+ s << "="
+ sep = "" # First entry comes after = sign, but then we need commas
+ val.each do |pval|
+ if pval.respond_to? :to_ical
+ s << sep << pval.to_ical
+ sep = ","
+ end
+ end
+ end
+ end
+ s
+ end
+
+ # TODO: Look into the x-property, x-param stuff...
+ # This would really only be needed for subclassing to add additional
+ # properties to an application using the API.
+ def custom_property(name, value)
+ @properties[name] = value
+ end
+
+ def multi_property?(name)
+ @@multi_properties.has_key?(name.downcase)
+ end
+
+ def multiline_property?(name)
+ @@multiline_properties.has_key?(name.downcase)
+ end
+
+ # Make it protected so we can monitor usage...
+ protected
+
+ def Component.ical_component(*syms)
+ hash_accessor :@components, *syms
+ end
+
+ # Define a set of methods supporting a new property
+ def Component.ical_property(property, alias_name = nil, prop_name = nil)
+ property = "#{property}".strip.downcase
+ alias_name = "#{alias_name}".strip.downcase unless alias_name.nil?
+ # If a prop_name was given then we use that for the actual storage
+ property = "#{prop_name}".strip.downcase unless prop_name.nil?
+
+ generate_getter(property, alias_name)
+ generate_setter(property, alias_name)
+ generate_query(property, alias_name)
+ end
+
+ # Define a set of methods defining a new property, which
+ # supports multiple values for the same property name.
+ def Component.ical_multi_property(property, singular, plural)
+ property = "#{property}".strip.downcase.gsub(/-/, '_')
+ plural = "#{plural}".strip.downcase
+
+ # Set this key so the parser knows to use an array for
+ # storing this property type.
+ @@multi_properties["#{property}"] = true
+
+ generate_multi_getter(property, plural)
+ generate_multi_setter(property, plural)
+ generate_multi_query(property, plural)
+ generate_multi_adder(property, singular)
+ generate_multi_remover(property, singular)
+ end
+
+ # Define a set of methods defining a new property, which
+ # supports multiple values in multiple lines with same property name
+ def Component.ical_multiline_property(property, singular, plural)
+ @@multiline_properties["#{property}"] = true
+ ical_multi_property(property, singular, plural)
+ end
+
+
+ private
+
+ def Component.generate_getter(property, alias_name)
+ unless instance_methods.include? property
+ code = <<-code
+ def #{property}(val = nil, params = nil)
+ return @properties["#{property}"] if val.nil?
+
+ unless val.respond_to?(:to_ical)
+ raise(NotImplementedError, "Value of type (" + val.class.to_s + ") does not support to_ical method!")
+ end
+
+ unless params.nil?
+ # Extend with the parameter methods only if we have to...
+ unless val.respond_to?(:ical_params)
+ val.class.class_eval { attr_accessor :ical_params }
+ end
+ val.ical_params = params
+ end
+
+ @properties["#{property}"] = val
+ end
+ code
+
+ class_eval code, "component.rb", 219
+ alias_method("#{alias_name}", "#{property}") unless alias_name.nil?
+ end
+ end
+
+ def Component.generate_setter(property, alias_name)
+ setter = property + '='
+ unless instance_methods.include? setter
+ code = <<-code
+ def #{setter}(val)
+ #{property}(val)
+ end
+ code
+
+ class_eval code, "component.rb", 233
+ alias_method("#{alias_name}=", "#{property+'='}") unless alias_name.nil?
+ end
+ end
+
+ def Component.generate_query(property, alias_name)
+ query = "#{property}?"
+ unless instance_methods.include? query
+ code = <<-code
+ def #{query}
+ @properties.has_key?("#{property.downcase}")
+ end
+ code
+
+ class_eval code, "component.rb", 226
+
+ alias_method("#{alias_name}\?", "#{query}") unless alias_name.nil?
+ end
+ end
+
+ def Component.generate_multi_getter(property, plural)
+ # Getter for whole array
+ unless instance_methods.include? plural
+ code = <<-code
+ def #{plural}(a = nil)
+ if a.nil?
+ @properties["#{property}"] || []
+ else
+ self.#{plural}=(a)
+ end
+ end
+ code
+
+ class_eval code, "component.rb", 186
+ end
+ end
+
+ def Component.generate_multi_setter(property, plural)
+ # Setter for whole array
+ unless instance_methods.include? plural+'+'
+ code = <<-code
+ def #{plural}=(a)
+ if a.respond_to?(:to_ary)
+ a.to_ary.each do |val|
+ unless val.respond_to?(:to_ical)
+ raise(NotImplementedError, "Property values do not support to_ical method!")
+ end
+ end
+
+ @properties["#{property}"] = a.to_ary
+ else
+ raise ArgumentError, "#{plural} is a multi-property that must be an array! Use the add_[property] method to add single entries."
+ end
+ end
+ code
+
+ class_eval code, "component.rb", 198
+ end
+ end
+
+ def Component.generate_multi_query(property, plural)
+ # Query for any of these properties
+ unless instance_methods.include? plural+'?'
+ code = <<-code
+ def #{plural}?
+ @properties.has_key?("#{property}")
+ end
+ code
+
+ class_eval code, "component.rb", 210
+ end
+ end
+
+ def Component.generate_multi_adder(property, singular)
+ adder = "add_"+singular.to_s
+ # Add another item to this properties array
+ unless instance_methods.include? adder
+ code = <<-code
+ def #{adder}(val, params = {})
+ unless val.respond_to?(:to_ical)
+ raise(NotImplementedError, "Property value object does not support to_ical method!")
+ end
+
+ unless params.nil?
+ # Extend with the parameter methods only if we have to...
+ unless val.respond_to?(:ical_params)
+ val.class.class_eval { attr_accessor :ical_params }
+ end
+ val.ical_params = params
+ end
+
+ if @properties.has_key?("#{property}")
+ @properties["#{property}"] << val
+ else
+ @properties["#{property}"] = [val]
+ end
+ end
+ code
+
+ class_eval code, "component.rb", 289
+ alias_method("add_#{property.downcase}", "#{adder}")
+ end
+ end
+
+ def Component.generate_multi_remover(property, singular)
+ # Remove an item from this properties array
+ unless instance_methods.include? "remove_#{singular}"
+ code = <<-code
+ def remove_#{singular}(a)
+ if @properties.has_key?("#{property}")
+ @properties["#{property}"].delete(a)
+ end
+ end
+ code
+
+ class_eval code, "component.rb", 303
+ alias_method("remove_#{property.downcase}", "remove_#{singular}")
+ end
+ end
+
+ def method_missing(method_name, *args)
+ @@logger.debug("Inside method_missing...")
+ method_name = method_name.to_s.downcase
+
+ unless method_name =~ /x_.*/
+ raise NoMethodError, "Method Name: #{method_name}"
+ end
+
+ # x-properties are accessed with underscore but stored with a dash so
+ # they output correctly and we don't have to special case the
+ # output code, which would require checking every property.
+ if args.size > 0 # Its a setter
+ # Pull off the possible equals
+ @properties[method_name[/x_[^=]*/].gsub('x_', 'x-')] = args.first
+ else # Or its a getter
+ return @properties[method_name.gsub('x_', 'x-')]
+ end
+ end
+
+ public
+
+ def respond_to?(method_name)
+ unless method_name.to_s.downcase =~ /x_.*/
+ super
+ end
+
+ true
+ end
+
+ end # class Component
+end
44 lib/icalendar/component/alarm.rb
@@ -0,0 +1,44 @@
+=begin
+ Copyright (C) 2005 Jeff Rose
+
+ This library is free software; you can redistribute it and/or modify it
+ under the same terms as the ruby language itself, see the file COPYING for
+ details.
+=end
+module Icalendar
+ # An Alarm calendar component is a grouping of component
+ # properties that is a reminder or alarm for an event or a
+ # to-do. For example, it may be used to define a reminder for a
+ # pending Event or an overdue Todo.
+ class Alarm < Component
+
+ # Single properties
+ ical_property :action
+ ical_property :description
+ ical_property :trigger
+ ical_property :summary
+
+ # Single but must appear together
+ ical_property :duration
+ ical_property :repeat
+
+ # Single and only occurring once
+
+ ical_property :created
+ ical_property :last_modified
+ ical_property :timestamp
+ ical_property :sequence
+
+ # Multi properties
+ ical_multiline_property :attendee, :attendee, :attendees
+ ical_multi_property :attach, :attachment, :attachments
+
+ def initialize()
+ super("VALARM")
+
+ # Almost everyone just wants to display so I make it the
+ # default so it works for most people right away...
+ action "DISPLAY"
+ end
+ end
+end
123 lib/icalendar/component/event.rb
@@ -0,0 +1,123 @@
+=begin
+ Copyright (C) 2005 Jeff Rose
+
+ This library is free software; you can redistribute it and/or modify it
+ under the same terms as the ruby language itself, see the file COPYING for
+ details.
+=end
+
+module Icalendar
+ # A Event calendar component is a grouping of component
+ # properties, and possibly including Alarm calendar components, that
+ # represents a scheduled amount of time on a calendar. For example, it
+ # can be an activity; such as a one-hour long, department meeting from
+ # 8:00 AM to 9:00 AM, tomorrow. Generally, an event will take up time
+ # on an individual calendar.
+ class Event < Component
+ ical_component :alarms
+
+ ## Single instance properties
+
+ # Access classification (PUBLIC, PRIVATE, CONFIDENTIAL...)
+ ical_property :ip_class, :klass
+
+ # Date & time of creation
+ ical_property :created
+
+ # Complete description of the calendar component
+ ical_property :description
+
+ # Specifies date-time when calendar component begins
+ ical_property :dtstart, :start
+
+ # Latitude & longitude for specified activity
+ ical_property :geo, :geo_location
+
+ # Date & time this item was last modified
+ ical_property :last_modified
+
+ # Specifies the intended venue for this activity
+ ical_property :location
+
+ # Defines organizer of this item
+ ical_property :organizer
+
+ # Defines relative priority for this item (1-9... 1 = best)
+ ical_property :priority
+
+ # Indicate date & time when this item was created
+ ical_property :dtstamp, :timestamp
+
+ # Revision sequence number for this item
+ ical_property :sequence, :seq
+
+ # Defines overall status or confirmation of this item
+ ical_property :status
+ ical_property :summary
+ ical_property :transp, :transparency
+
+ # Defines a persistent, globally unique id for this item
+ ical_property :uid, :unique_id
+
+ # Defines a URL associated with this item
+ ical_property :url
+ ical_property :recurid, :recurrence_id
+
+ ## Single but mutually exclusive properties (Not testing though)
+
+ # Specifies a date and time that this item ends
+ ical_property :dtend, :end
+
+ # Specifies a positive duration time
+ ical_property :duration
+
+ ## Multi-instance properties
+
+ # Associates a URI or binary blob with this item
+ ical_multi_property :attach, :attachment, :attachments
+
+ # Defines an attendee for this calendar item
+ ical_multiline_property :attendee, :attendee, :attendees
+
+ # Defines the categories for a calendar component (school, work...)
+ ical_multi_property :categories, :category, :categories
+
+ # Simple comment for the calendar user.
+ ical_multi_property :comment, :comment, :comments
+
+ # Contact information associated with this item.
+ ical_multi_property :contact, :contact, :contacts
+ ical_multi_property :exdate, :exception_date, :exception_dates
+ ical_multi_property :exrule, :exception_rule, :exception_rules
+ ical_multi_property :rstatus, :request_status, :request_statuses
+
+ # Used to represent a relationship between two calendar items
+ ical_multi_property :related_to, :related_to, :related_tos
+ ical_multi_property :resources, :resource, :resources
+
+ # Used with the UID & SEQUENCE to identify a specific instance of a
+ # recurring calendar item.
+ ical_multi_property :rdate, :recurrence_date, :recurrence_dates
+ ical_multi_property :rrule, :recurrence_rule, :recurrence_rules
+
+ def initialize()
+ super("VEVENT")
+
+ # Now doing some basic initialization
+ sequence 0
+ timestamp DateTime.now
+ uid new_uid
+ end
+
+ def alarm(&block)
+ a = Alarm.new
+ self.add a
+
+ a.instance_eval &block if block
+
+ a
+ end
+
+
+ end
+end
37 lib/icalendar/component/freebusy.rb
@@ -0,0 +1,37 @@
+=begin
+ Copyright (C) 2005 Jeff Rose
+
+ This library is free software; you can redistribute it and/or modify it
+ under the same terms as the ruby language itself, see the file COPYING for
+ details.
+=end
+module Icalendar
+ # A Freebusy calendar component is a grouping of
+ # component properties that represents either a request for, a reply to
+ # a request for free or busy time information or a published set of
+ # busy time information.
+ class Freebusy < Component
+ # Single properties
+ ical_property :contact
+ ical_property :dtstart, :start
+ ical_property :dtend, :end
+ ical_property :dtstamp, :timestamp
+ ical_property :duration
+ ical_property :organizer
+ ical_property :uid, :user_id
+ ical_property :url
+
+ # Multi-properties
+ ical_multiline_property :attendee, :attendee, :attendees
+ ical_multi_property :comment, :comment, :comments
+ ical_multiline_property :freebusy, :freebusy, :freebusys
+ ical_multi_property :rstatus, :request_status, :request_statuses
+
+ def initialize()
+ super("VFREEBUSY")
+
+ timestamp DateTime.now
+ uid new_uid
+ end
+ end
+end
61 lib/icalendar/component/journal.rb
@@ -0,0 +1,61 @@
+=begin
+ Copyright (C) 2005 Jeff Rose
+
+ This library is free software; you can redistribute it and/or modify it
+ under the same terms as the ruby language itself, see the file COPYING for
+ details.
+=end
+module Icalendar
+ # A Journal calendar component is a grouping of
+ # component properties that represent one or more descriptive text
+ # notes associated with a particular calendar date. The "DTSTART"
+ # property is used to specify the calendar date that the journal entry
+ # is associated with. Generally, it will have a DATE value data type,
+ # but it can also be used to specify a DATE-TIME value data type.
+ # Examples of a journal entry include a daily record of a legislative
+ # body or a journal entry of individual telephone contacts for the day
+ # or an ordered list of accomplishments for the day. The Journal
+ # calendar component can also be used to associate a document with a
+ # calendar date.
+ class Journal < Component
+
+ # Single properties
+ ical_property :ip_class
+ ical_property :created
+ ical_property :description
+ ical_property :dtstart, :start
+ ical_property :last_modified
+ ical_property :organizer
+ ical_property :dtstamp, :timestamp
+ ical_property :sequence, :seq
+ ical_property :status
+ ical_property :summary
+ ical_property :uid, :user_id
+ ical_property :url
+ ical_property :recurid, :recurrence_id
+
+ # Multi-properties
+ ical_multi_property :attach, :attachment, :attachments
+ ical_multiline_property :attendee, :attendee, :attendees
+ ical_multi_property :categories, :category, :categories
+ ical_multi_property :comment, :comment, :comments
+ ical_multi_property :contact, :contact, :contacts
+ ical_multi_property :exdate, :exception_date, :exception_dates
+ ical_multi_property :exrule, :exception_rule, :exception_rules
+ ical_multi_property :rstatus, :request_status, :request_statuses
+ ical_multi_property :related_to, :related_to, :related_tos
+ ical_multi_property :resources, :resource, :resources
+ ical_multi_property :rdate, :recurrence_date, :recurrence_dates
+ ical_multi_property :rrule, :recurrence_rule, :recurrence_rules
+
+ def initialize()
+ super("VJOURNAL")
+
+ sequence 0
+ timestamp DateTime.now
+ uid new_uid
+ end
+
+ end
+end
+
87 lib/icalendar/component/timezone.rb
@@ -0,0 +1,87 @@
+=begin
+ Copyright (C) 2005 Jeff Rose
+
+ This library is free software; you can redistribute it and/or modify it
+ under the same terms as the ruby language itself, see the file COPYING for
+ details.
+=end
+module Icalendar
+ # A Timezone is unambiguously defined by the set of time
+ # measurement rules determined by the governing body for a given
+ # geographic area. These rules describe at a minimum the base offset
+ # from UTC for the time zone, often referred to as the Standard Time
+ # offset. Many locations adjust their Standard Time forward or backward
+ # by one hour, in order to accommodate seasonal changes in number of
+ # daylight hours, often referred to as Daylight Saving Time. Some
+ # locations adjust their time by a fraction of an hour. Standard Time
+ # is also known as Winter Time. Daylight Saving Time is also known as
+ # Advanced Time, Summer Time, or Legal Time in certain countries. The
+ # following table shows the changes in time zone rules in effect for
+ # New York City starting from 1967. Each line represents a description
+ # or rule for a particular observance.
+ class Timezone < Component
+ ical_component :standard, :daylight
+
+ # Single properties
+ ical_property :dtstart, :start
+ ical_property :tzoffsetto, :timezone_offset_to
+ ical_property :tzoffsetfrom, :timezone_offset_from
+ ical_property :tzid, :timezone_id
+ ical_property :tzname, :timezone_name
+
+ ical_property :created
+ ical_property :last_modified
+ ical_property :timestamp
+ ical_property :sequence
+
+ # Multi-properties
+ ical_multi_property :comment, :comment, :comments
+ ical_multi_property :rdate, :recurrence_date, :recurrence_dates
+ ical_multi_property :rrule, :recurrence_rule, :recurrence_rules
+
+ # Define a custom add component method because standard and daylight
+ # are the only components that can occur just once with their parent.
+ def add_component(component)
+ key = component.class.to_s.downcase.gsub('icalendar::','').to_sym
+ @components[key] = component
+ end
+
+ # Also need a custom to_ical because typically it iterates over an array
+ # of components.
+ def to_ical
+ print_component do
+ s = ""
+ @components.each_value do |comp|
+ s << comp.to_ical
+ end
+ s
+ end
+ end
+
+
+ def initialize(name = "VTIMEZONE")
+ super(name)
+ end
+
+ end
+
+ # A Standard component is a sub-component of the Timezone component which
+ # is used to describe the standard time offset.
+ class Standard < Timezone
+
+ def initialize()
+ super("STANDARD")
+ end
+ end
+
+ # A Daylight component is a sub-component of the Timezone component which
+ # is used to describe the time offset for what is commonly known as
+ # daylight savings time.
+ class Daylight < Timezone
+
+ def initialize()
+ super("DAYLIGHT")
+ end
+ end
+
+end
64 lib/icalendar/component/todo.rb
@@ -0,0 +1,64 @@