--- /dev/null
+# $Id$
+# Doxyfile 1.5.9
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = webcal
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER = 0.7.4
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = doc
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH = /Users/dimitri/doxygen/mail/1.5.7/doxywizard/
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it parses.
+# With this tag you can assign which parser to use for a given extension.
+# Doxygen has a built-in mapping, but you can override or extend it using this tag.
+# The format is ext=language, where ext is a file extension, and language is one of
+# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP,
+# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat
+# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran),
+# use: inc=Fortran f=C. Note that for custom extensions you also need to set
+# FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen to replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penality.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will rougly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols
+
+SYMBOL_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = YES
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page. This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by
+# doxygen. The layout file controls the global structure of the generated output files
+# in an output format independent way. The create the layout file that represents
+# doxygen's defaults, run doxygen with the -l option. You can optionally specify a
+# file name after the option, if omitted DoxygenLayout.xml will be used as the name
+# of the layout file.
+
+LAYOUT_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = ./doc_source
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.d \
+ *.java \
+ *.ii \
+ *.ixx \
+ *.ipp \
+ *.i++ \
+ *.inl \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++ \
+ *.idl \
+ *.odl \
+ *.cs \
+ *.php \
+ *.php3 \
+ *.inc \
+ *.m \
+ *.mm \
+ *.dox \
+ *.py \
+ *.f90 \
+ *.f \
+ *.vhd \
+ *.vhdl
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output. If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code. Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information.
+
+GENERATE_DOCSET = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER
+# are set, an additional index file will be generated that can be used as input for
+# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated
+# HTML documentation.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE =
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add.
+# For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION =
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to FRAME, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature. Other possible values
+# for this tag are: HIERARCHIES, which will generate the Groups, Directories,
+# and Class Hierarchy pages using a tree view instead of an ordered list;
+# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which
+# disables this behavior completely. For backwards compatibility with previous
+# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE
+# respectively.
+
+GENERATE_TREEVIEW = ALL
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE = 10
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include
+# source code with syntax highlighting in the LaTeX output.
+# Note that which sources are shown also depends on other settings
+# such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS = NO
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = YES
+
+# By default doxygen will write a font called FreeSans.ttf to the output
+# directory and reference it in all dot files that doxygen generates. This
+# font does not include all possible unicode characters however, so when you need
+# these (or just want a differently looking font) you can specify the font name
+# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
+# which can be done by putting it in a standard location or by setting the
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
+# containing the font.
+
+DOT_FONTNAME = FreeSans
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
+# can find it using this tag.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = YES
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH = YES
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH = YES
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT = YES
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = YES
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Options related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = NO
--- /dev/null
+/* $Id$ */
+
+There are two ways to install webcal. Outside web scope and inside web
+scope.
+
+Inside web scope:
+Untar the package in a web enabled directory and point your browser to
+this directory. To install webcal simply follow the automatically
+started wizard.
+
+Outside web scope:
+Untar the package to any directory outside web scope and go to the
+directory install and run the script setup as root or by using sudo.
+Answer the question and follow the directions given. The script requires
+Perl.
--- /dev/null
+<?php
+/**
+* Utility functions of a general nature which are used by
+* most AWL library classes.
+*
+* @package awl
+* @subpackage Utilities
+* @author Andrew McMillan <andrew@catalyst.net.nz>
+* @copyright Catalyst IT Ltd
+* @license http://gnu.org/copyleft/gpl.html GNU GPL v2
+*/
+
+if ( !function_exists('dbg_error_log') ) {
+ /**
+ * Writes a debug message into the error log using printf syntax. If the first
+ * parameter is "ERROR" then the message will _always_ be logged.
+ * Otherwise, the first parameter is a "component" name, and will only be logged
+ * if $c->dbg["component"] is set to some non-null value.
+ *
+ * If you want to see every log message then $c->dbg["ALL"] can be set, to
+ * override the debugging status of the individual components.
+ *
+ * @var string $component The component to identify itself, or "ERROR", or "LOG:component"
+ * @var string $format A format string for the log message
+ * @var [string $parameter ...] Parameters for the format string.
+ */
+ function dbg_error_log() {
+ global $c;
+ $argc = func_num_args();
+ $args = func_get_args();
+ $type = "DBG";
+ $component = array_shift($args);
+ if ( substr( $component, 0, 3) == "LOG" ) {
+ // Special escape case for stuff that always gets logged.
+ $type = 'LOG';
+ $component = substr($component,4);
+ }
+ else if ( $component == "ERROR" ) {
+ $type = "***";
+ }
+ else if ( isset($c->dbg["ALL"]) ) {
+ $type = "ALL";
+ }
+ else if ( !isset($c->dbg[strtolower($component)]) ) return;
+
+ if ( 2 <= $argc ) {
+ $format = array_shift($args);
+ }
+ else {
+ $format = "%s";
+ }
+ @error_log( $c->sysabbr.": $type: $component:". vsprintf( $format, $args ) );
+ }
+}
+
+
+
+if ( !function_exists('apache_request_headers') ) {
+ /**
+ * Forward compatibility so we can use the non-deprecated name in PHP4
+ * @package awl
+ */
+ function apache_request_headers() {
+ return getallheaders();
+ }
+}
+
+
+
+if ( !function_exists('dbg_log_array') ) {
+ /**
+ * Function to dump an array to the error log, possibly recursively
+ *
+ * @var string $component Which component should this log message identify itself from
+ * @var string $name What name should this array dump identify itself as
+ * @var array $arr The array to be dumped.
+ * @var boolean $recursive Should the dump recurse into arrays/objects in the array
+ */
+ function dbg_log_array( $component, $name, $arr, $recursive = false ) {
+ if ( !isset($arr) || (gettype($arr) != 'array' && gettype($arr) != 'object') ) {
+ dbg_error_log( $component, "%s: array is not set, or is not an array!", $name);
+ return;
+ }
+ foreach ($arr as $key => $value) {
+ dbg_error_log( $component, "%s: >>%s<< = >>%s<<", $name, $key,
+ (gettype($value) == 'array' || gettype($value) == 'object' ? gettype($value) : $value) );
+ if ( $recursive && (gettype($value) == 'array' || (gettype($value) == 'object' && "$key" != 'self' && "$key" != 'parent') ) ) {
+ dbg_log_array( $component, "$name"."[$key]", $value, $recursive );
+ }
+ }
+ }
+}
+
+
+
+if ( !function_exists("session_salted_md5") ) {
+ /**
+ * Make a salted MD5 string, given a string and (possibly) a salt.
+ *
+ * If no salt is supplied we will generate a random one.
+ *
+ * @param string $instr The string to be salted and MD5'd
+ * @param string $salt Some salt to sprinkle into the string to be MD5'd so we don't get the same PW always hashing to the same value.
+ * @return string The salt, a * and the MD5 of the salted string, as in SALT*SALTEDHASH
+ */
+ function session_salted_md5( $instr, $salt = "" ) {
+ if ( $salt == "" ) $salt = substr( md5(rand(100000,999999)), 2, 8);
+ dbg_error_log( "Login", "Making salted MD5: salt=$salt, instr=$instr, md5($salt$instr)=".md5($salt . $instr) );
+ return ( sprintf("*%s*%s", $salt, md5($salt . $instr) ) );
+ }
+}
+
+
+
+if ( !function_exists("session_salted_sha1") && version_compare(phpversion(), "4.9.9") > 0 ) {
+ /**
+ * Make a salted SHA1 string, given a string and (possibly) a salt. PHP5 only (although it
+ * could be made to work on PHP4 (@see http://www.openldap.org/faq/data/cache/347.html). The
+ * algorithm used here is compatible with OpenLDAP so passwords generated through this function
+ * should be able to be migrated to OpenLDAP by using the part following the second '*', i.e.
+ * the '{SSHA}....' part.
+ *
+ * If no salt is supplied we will generate a random one.
+ *
+ * @param string $instr The string to be salted and SHA1'd
+ * @param string $salt Some salt to sprinkle into the string to be SHA1'd so we don't get the same PW always hashing to the same value.
+ * @return string A *, the salt, a * and the SHA1 of the salted string, as in *SALT*SALTEDHASH
+ */
+ function session_salted_sha1( $instr, $salt = "" ) {
+ if ( $salt == "" ) $salt = substr( str_replace('*','',base64_encode(sha1(rand(100000,9999999),true))), 2, 9);
+ dbg_error_log( "Login", "Making salted SHA1: salt=$salt, instr=$instr, encoded($instr$salt)=".base64_encode(sha1($instr . $salt, true).$salt) );
+ return ( sprintf("*%s*{SSHA}%s", $salt, base64_encode(sha1($instr.$salt, true) . $salt ) ) );
+ }
+}
+
+
+if ( !function_exists("session_validate_password") ) {
+ /**
+ * Checks what a user entered against the actual password on their account.
+ * @param string $they_sent What the user entered.
+ * @param string $we_have What we have in the database as their password. Which may (or may not) be a salted MD5.
+ * @return boolean Whether or not the users attempt matches what is already on file.
+ */
+ function session_validate_password( $they_sent, $we_have ) {
+ if ( preg_match('/^\*\*.+$/', $we_have ) ) {
+ // The "forced" style of "**plaintext" to allow easier admin setting
+ return ( "**$they_sent" == $we_have );
+ }
+
+ if ( preg_match('/^\*(.+)\*{[A-Z]+}.+$/', $we_have, $regs ) ) {
+ if ( function_exists("session_salted_sha1") ) {
+ // A nicely salted sha1sum like "*<salt>*{SSHA}<salted_sha1>"
+ $salt = $regs[1];
+ $sha1_sent = session_salted_sha1( $they_sent, $salt ) ;
+ return ( $sha1_sent == $we_have );
+ }
+ else {
+ dbg_error_log( "ERROR", "Password is salted SHA-1 but you are using PHP4!" );
+ echo <<<EOERRMSG
+<html>
+<head>
+<title>Salted SHA1 Password format not supported with PHP4</title>
+</head>
+<body>
+<h1>Salted SHA1 Password format not supported with PHP4</h1>
+<p>At some point you have used PHP5 to set the password for this user and now you are
+ using PHP4. You will need to assign a new password to this user using PHP4, or ensure
+ you use PHP5 everywhere (recommended).</p>
+<p>AWL has now switched to using salted SHA-1 passwords by preference in a format
+ compatible with OpenLDAP.</p>
+</body>
+</html>
+EOERRMSG;
+ exit;
+ }
+ }
+
+ if ( preg_match('/^\*(.+)\*.+$/', $we_have, $regs ) ) {
+ // A nicely salted md5sum like "*<salt>*<salted_md5>"
+ $salt = $regs[1];
+ $md5_sent = session_salted_md5( $they_sent, $salt ) ;
+ return ( $md5_sent == $we_have );
+ }
+
+ // Anything else is bad
+ return false;
+
+ }
+}
+
+
+
+if ( !function_exists("replace_uri_params") ) {
+ /**
+ * Given a URL (presumably the current one) and a parameter, replace the value of parameter,
+ * extending the URL as necessary if the parameter is not already there.
+ * @param string $uri The URI we will be replacing parameters in.
+ * @param array $replacements An array of replacement pairs array( "replace_this" => "with this" )
+ * @return string The URI with the replacements done.
+ */
+ function replace_uri_params( $uri, $replacements ) {
+ $replaced = $uri;
+ foreach( $replacements AS $param => $new_value ) {
+ $rxp = preg_replace( '/([\[\]])/', '\\\\$1', $param ); // Some parameters may be arrays.
+ $regex = "/([&?])($rxp)=([^&]+)/";
+ dbg_error_log("core", "Looking for [%s] to replace with [%s] regex is %s and searching [%s]", $param, $new_value, $regex, $replaced );
+ if ( preg_match( $regex, $replaced ) )
+ $replaced = preg_replace( $regex, "\$1$param=$new_value", $replaced);
+ else
+ $replaced .= "&$param=$new_value";
+ }
+ if ( ! preg_match( '/\?/', $replaced ) ) {
+ $replaced = preg_replace("/&(.+)$/", "?\$1", $replaced);
+ }
+ $replaced = str_replace("&", "--AmPeRsAnD--", $replaced);
+ $replaced = str_replace("&", "&", $replaced);
+ $replaced = str_replace("--AmPeRsAnD--", "&", $replaced);
+ dbg_error_log("core", "URI <<$uri>> morphed to <<$replaced>>");
+ return $replaced;
+ }
+}
+
+
+if ( !function_exists("uuid") ) {
+/**
+ * Generates a Universally Unique IDentifier, version 4.
+ *
+ * RFC 4122 (http://www.ietf.org/rfc/rfc4122.txt) defines a special type of Globally
+ * Unique IDentifiers (GUID), as well as several methods for producing them. One
+ * such method, described in section 4.4, is based on truly random or pseudo-random
+ * number generators, and is therefore implementable in a language like PHP.
+ *
+ * We choose to produce pseudo-random numbers with the Mersenne Twister, and to always
+ * limit single generated numbers to 16 bits (ie. the decimal value 65535). That is
+ * because, even on 32-bit systems, PHP's RAND_MAX will often be the maximum *signed*
+ * value, with only the equivalent of 31 significant bits. Producing two 16-bit random
+ * numbers to make up a 32-bit one is less efficient, but guarantees that all 32 bits
+ * are random.
+ *
+ * The algorithm for version 4 UUIDs (ie. those based on random number generators)
+ * states that all 128 bits separated into the various fields (32 bits, 16 bits, 16 bits,
+ * 8 bits and 8 bits, 48 bits) should be random, except : (a) the version number should
+ * be the last 4 bits in the 3rd field, and (b) bits 6 and 7 of the 4th field should
+ * be 01. We try to conform to that definition as efficiently as possible, generating
+ * smaller values where possible, and minimizing the number of base conversions.
+ *
+ * @copyright Copyright (c) CFD Labs, 2006. This function may be used freely for
+ * any purpose ; it is distributed without any form of warranty whatsoever.
+ * @author David Holmes <dholmes@cfdsoftware.net>
+ *
+ * @return string A UUID, made up of 32 hex digits and 4 hyphens.
+ */
+
+ function uuid() {
+
+ // The field names refer to RFC 4122 section 4.1.2
+
+ return sprintf('%04x%04x-%04x-%03x4-%04x-%04x%04x%04x',
+ mt_rand(0, 65535), mt_rand(0, 65535), // 32 bits for "time_low"
+ mt_rand(0, 65535), // 16 bits for "time_mid"
+ mt_rand(0, 4095), // 12 bits before the 0100 of (version) 4 for "time_hi_and_version"
+ bindec(substr_replace(sprintf('%016b', mt_rand(0, 65535)), '01', 6, 2)),
+ // 8 bits, the last two of which (positions 6 and 7) are 01, for "clk_seq_hi_res"
+ // (hence, the 2nd hex digit after the 3rd hyphen can only be 1, 5, 9 or d)
+ // 8 bits for "clk_seq_low"
+ mt_rand(0, 65535), mt_rand(0, 65535), mt_rand(0, 65535) // 48 bits for "node"
+ );
+ }
+}
+
+if ( !function_exists("translate") ) {
+ require_once("Translation.php");
+}
+
+ if ( !function_exists("clone") && version_compare(phpversion(), '5.0') < 0) {
+ /**
+ * PHP5 screws with the assignment operator changing so that $a = $b means that
+ * $a becomes a reference to $b. There is a clone() that we can use in PHP5, so
+ * we have to emulate that for PHP4. Bleargh.
+ */
+ eval( 'function clone($object) { return $object; }' );
+}
+
+if ( !function_exists("quoted_printable_encode") ) {
+ /**
+ * Process a string to fit the requirements of RFC2045 section 6.7. Note that
+ * this works, but replaces more characters than the minimum set. For readability
+ * the spaces aren't encoded as =20 though.
+ */
+ function quoted_printable_encode($string) {
+ return preg_replace('/[^\r\n]{73}[^=\r\n]{2}/', "$0=\r\n", str_replace("%","=",str_replace("%20"," ",rawurlencode($string))));
+ }
+}
+
+
+if ( !function_exists("clean_by_regex") ) {
+ /**
+ * Clean a value by applying a regex to it. If it is an array apply it to
+ * each element in the array recursively. If it is an object we don't mess
+ * with it.
+ */
+ function clean_by_regex( $val, $regex ) {
+ if ( is_null($val) ) return null;
+ switch( $regex ) {
+ case 'int': $regex = '#^\d+$#'; break;
+ }
+ if ( is_array($val) ) {
+ foreach( $val AS $k => $v ) {
+ $val[$k] = clean_by_regex($v,$regex);
+ }
+ }
+ else if ( ! is_object($val) ) {
+ if ( preg_match( $regex, $val, $matches) ) {
+ $val = $matches[0];
+ }
+ else {
+ $val = '';
+ }
+ }
+ return $val;
+ }
+}
+
+
+if ( !function_exists("param_to_global") ) {
+ /**
+ * Convert a parameter to a global. We first look in _POST and then in _GET,
+ * and if they passed in a bunch of valid characters, we will make sure the
+ * incoming is cleaned to only match that set.
+ *
+ * @param string $varname The name of the global variable to put the answer in
+ * @param string $match_regex The part of the parameter matching this regex will be returned
+ * @param string $alias1 An alias for the name that we should look for first.
+ * @param " ... More aliases, in the order which they should be examined. $varname will be appended to the end.
+ */
+ function param_to_global( ) {
+ $args = func_get_args();
+
+ $varname = array_shift($args);
+ $GLOBALS[$varname] = null;
+
+ $match_regex = null;
+ $argc = func_num_args();
+ if ( $argc > 1 ) {
+ $match_regex = array_shift($args);
+ }
+
+ $args[] = $varname;
+ foreach( $args AS $k => $name ) {
+ if ( isset($_POST[$name]) ) {
+ $result = $_POST[$name];
+ break;
+ }
+ else if ( isset($_GET[$name]) ) {
+ $result = $_GET[$name];
+ break;
+ }
+ }
+ if ( !isset($result) ) return null;
+
+ if ( isset($match_regex) ) {
+ $result = clean_by_regex( $result, $match_regex );
+ }
+
+ $GLOBALS[$varname] = $result;
+ return $result;
+ }
+}
+
+
+if ( !function_exists("get_fields") ) {
+ /**
+ * @var array $_AWL_field_cache is a cache of the field names for a table
+ */
+ $_AWL_field_cache = array();
+
+
+ /**
+ * Get the names of the fields for a particular table
+ * @param string $tablename The name of the table.
+ * @return array of string The public fields in the table.
+ */
+ function get_fields( $tablename ) {
+ global $_AWL_field_cache;
+
+ if ( !isset($_AWL_field_cache[$tablename]) ) {
+ dbg_error_log( "DataUpdate", ":get_fields: Loaded fields for table '$tablename'" );
+ $sql = "SELECT f.attname, t.typname FROM pg_attribute f ";
+ $sql .= "JOIN pg_class c ON ( f.attrelid = c.oid ) ";
+ $sql .= "JOIN pg_type t ON ( f.atttypid = t.oid ) ";
+ $sql .= "WHERE relname = ? AND attnum >= 0 order by f.attnum;";
+ $qry = new PgQuery( $sql, $tablename );
+ $qry->Exec("DataUpdate");
+ $fields = array();
+ while( $row = $qry->Fetch() ) {
+ $fields["$row->attname"] = $row->typname;
+ }
+ $_AWL_field_cache[$tablename] = $fields;
+ }
+ return $_AWL_field_cache[$tablename];
+ }
+}
+
--- /dev/null
+<?php
+/**
+* Functions involved in translating with gettext
+* @package awl
+* @subpackage Translation
+* @author Andrew McMillan <andrew@catalyst.net.nz>
+* @copyright Catalyst IT Ltd
+* @license http://gnu.org/copyleft/gpl.html GNU GPL v2
+*/
+if ( !function_exists("i18n") ) {
+ /**
+ * Mark a string as being internationalized. This is a semaphore method; it
+ * does nothing but it allows us to easily identify strings that require
+ * translation. Generally this is used to mark strings that will be stored
+ * in the database (like descriptions of permissions).
+ *
+ * AWL uses GNU gettext for internationalization (i18n) and localization (l10n) of
+ * text presented to the user. Gettext needs to know about all places involving strings,
+ * that must be translated. Mark any place, where localization at runtime shall take place
+ * by using the function translate().
+ *
+ * In the help I have used 'xlate' rather than 'translate' and 'x18n' rather than 'i18n'
+ * so that the tools skip this particular file for translation :-)
+ *
+ * E.g. instead of:
+ * print 'TEST to be displayed in different languages';
+ * use:
+ * print xlate('TEST to be displayed in different languages');
+ * and you are all set for pure literals. The translation teams will receive that literal
+ * string as a job to translate and will translate it (when the message is clear enough).
+ * At runtime the message is then localized when printed.
+ * The input string can contain a hint to assist translators:
+ * print xlate('TT <!-- abbreviation for Translation Test -->');
+ * The hint portion of the string will not be printed.
+ *
+ * But consider this case:
+ * $message_to_be_localized = 'TEST to be displayed in different languages';
+ * print xlate($message_to_be_localized);
+ *
+ * The translate() function is called in the right place for runtime handling, but there
+ * is no message at gettext preprocessing time to be given to the translation teams,
+ * just a variable name. Translation of the variable name would break the code! So all
+ * places potentially feeding this variable have to be marked to be given to translation
+ * teams, but not translated at runtime!
+ *
+ * This method resolves all such cases. Simply mark the candidates:
+ * $message_to_be_localized = x18n('TEST to be displayed in different languages');
+ * print xlate($message_to_be_localized);
+ *
+ * @param string the value
+ * @return string the same value
+ */
+ function i18n($value) {
+ return $value; /* Just pass the value through */
+ }
+}
+
+
+if ( !function_exists("translate") ) {
+ /**
+ * Convert a string in English to whatever this user's locale is
+ */
+ function translate( $en ) {
+ $xl = gettext($en);
+ dbg_error_log("I18N","Translated =%s= into =%s=", $en, $xl );
+ return $xl;
+ }
+}
+
+
+if ( !function_exists("init_gettext") ) {
+ /**
+ * Initialise our use of Gettext
+ */
+ function init_gettext( $domain, $location ) {
+ bindtextdomain( $domain, $location );
+ $codeset = bind_textdomain_codeset( $domain, "UTF-8" );
+ textdomain( $domain );
+ dbg_error_log("I18N","Bound domain =%s= to location =%s= using character set =%s=", $domain, $location, $codeset );
+ }
+}
+
+
+if ( !function_exists("awl_set_locale") ) {
+ /**
+ * Set the translation to the user's locale. At this stage all we do is
+ * call the gettext function.
+ */
+ function awl_set_locale( $locale ) {
+ global $c;
+
+ if ( !is_array($locale) && ! preg_match('/^[a-z]{2}(_[A-Z]{2})?\./', $locale ) ) {
+ $locale = array( $locale, $locale.".UTF-8");
+ }
+ if ( $newlocale = setlocale( LC_ALL, $locale) ) {
+ dbg_error_log("I18N","Set locale to =%s=", $newlocale );
+ $c->current_locale = $newlocale;
+ }
+ else {
+ dbg_log_array("I18N","Unsupported locale: ", $locale, false );
+ }
+ }
+}
+
+?>
\ No newline at end of file
--- /dev/null
+<?php
+/**
+* A class to assist with construction of XML documents
+*
+* @package awl
+* @subpackage XMLElement
+* @author Andrew McMillan <andrew@mcmillan.net.nz>
+* @copyright Catalyst .Net Ltd, Morphoss Ltd <http://www.morphoss.com/>
+* @license http://gnu.org/copyleft/gpl.html GNU GPL v2
+*/
+require_once("AWLUtilities.php");
+
+/**
+* A class for XML elements which may have attributes, or contain
+* other XML sub-elements
+*
+* @package awl
+*/
+class XMLElement {
+ var $tagname;
+ var $xmlns;
+ var $attributes;
+ var $content;
+ var $_parent;
+
+ /**
+ * Constructor - nothing fancy as yet.
+ *
+ * @param string $tagname The tag name of the new element
+ * @param mixed $content Either a string of content, or an array of sub-elements
+ * @param array $attributes An array of attribute name/value pairs
+ * @param array $xmlns An XML namespace specifier
+ */
+ function XMLElement( $tagname, $content=false, $attributes=false, $xmlns=null ) {
+ $this->tagname=$tagname;
+ if ( gettype($content) == "object" ) {
+ // Subtree to be parented here
+ $this->content = array(&$content);
+ }
+ else {
+ // Array or text
+ $this->content = $content;
+ }
+ $this->attributes = $attributes;
+ if ( isset($this->attributes['xmlns']) ) { // Oversimplification to be removed
+ $this->xmlns = $this->attributes['xmlns'];
+ }
+ if ( isset($xmlns) ) {
+ $this->xmlns = $xmlns;
+ }
+ }
+
+
+ /**
+ * Count the number of elements
+ * @return int The number of elements
+ */
+ function CountElements( ) {
+ if ( $this->content === false ) return 0;
+ if ( is_array($this->content) ) return count($this->content);
+ if ( $this->content == '' ) return 0;
+ return 1;
+ }
+
+ /**
+ * Set an element attribute to a value
+ *
+ * @param string The attribute name
+ * @param string The attribute value
+ */
+ function SetAttribute($k,$v) {
+ if ( gettype($this->attributes) != "array" ) $this->attributes = array();
+ $this->attributes[$k] = $v;
+ if ( strtolower($k) == 'xmlns' ) {
+ $this->xmlns = $v;
+ }
+ }
+
+ /**
+ * Set the whole content to a value
+ *
+ * @param mixed The element content, which may be text, or an array of sub-elements
+ */
+ function SetContent($v) {
+ $this->content = $v;
+ }
+
+ /**
+ * Accessor for the tag name
+ *
+ * @return string The tag name of the element
+ */
+ function GetTag() {
+ return $this->tagname;
+ }
+
+ /**
+ * Accessor for the full-namespaced tag name
+ *
+ * @return string The tag name of the element, prefixed by the namespace
+ */
+ function GetNSTag() {
+ return $this->xmlns . ':' . $this->tagname;
+ }
+
+ /**
+ * Accessor for a single attribute
+ * @param string $attr The name of the attribute.
+ * @return string The value of that attribute of the element
+ */
+ function GetAttribute( $attr ) {
+ if ( isset($this->attributes[$attr]) ) return $this->attributes[$attr];
+ }
+
+ /**
+ * Accessor for the attributes
+ *
+ * @return array The attributes of this element
+ */
+ function GetAttributes() {
+ return $this->attributes;
+ }
+
+ /**
+ * Accessor for the content
+ *
+ * @return array The content of this element
+ */
+ function GetContent() {
+ return $this->content;
+ }
+
+ /**
+ * Return an array of elements matching the specified tag
+ *
+ * @return array The XMLElements within the tree which match this tag
+ */
+ function GetElements( $tag, $recursive=false ) {
+ $elements = array();
+ if ( gettype($this->content) == "array" ) {
+ foreach( $this->content AS $k => $v ) {
+ if ( $v->tagname == $tag ) {
+ $elements[] = $v;
+ }
+ if ( $recursive ) {
+ $elements = $elements + $v->GetElements($tag,true);
+ }
+ }
+ }
+ return $elements;
+ }
+
+
+ /**
+ * Return an array of elements matching the specified path
+ *
+ * @return array The XMLElements within the tree which match this tag
+ */
+ function GetPath( $path ) {
+ $elements = array();
+ // printf( "Querying within '%s' for path '%s'\n", $this->tagname, $path );
+ if ( !preg_match( '#(/)?([^/]+)(/?.*)$#', $path, $matches ) ) return $elements;
+ // printf( "Matches: %s -- %s -- %s\n", $matches[1], $matches[2], $matches[3] );
+ if ( $matches[2] == '*' || strtolower($matches[2]) == strtolower($this->tagname) ) {
+ if ( $matches[3] == '' ) {
+ /**
+ * That is the full path
+ */
+ $elements[] = $this;
+ }
+ else if ( gettype($this->content) == "array" ) {
+ /**
+ * There is more to the path, so we recurse into that sub-part
+ */
+ foreach( $this->content AS $k => $v ) {
+ $elements = array_merge( $elements, $v->GetPath($matches[3]) );
+ }
+ }
+ }
+
+ if ( $matches[1] != '/' && gettype($this->content) == "array" ) {
+ /**
+ * If our input $path was not rooted, we recurse further
+ */
+ foreach( $this->content AS $k => $v ) {
+ $elements = array_merge( $elements, $v->GetPath($path) );
+ }
+ }
+ // printf( "Found %d within '%s' for path '%s'\n", count($elements), $this->tagname, $path );
+ return $elements;
+ }
+
+
+ /**
+ * Add a sub-element
+ *
+ * @param object An XMLElement to be appended to the array of sub-elements
+ */
+ function AddSubTag(&$v) {
+ if ( gettype($this->content) != "array" ) $this->content = array();
+ $this->content[] =& $v;
+ return count($this->content);
+ }
+
+ /**
+ * Add a new sub-element
+ *
+ * @param string The tag name of the new element
+ * @param mixed Either a string of content, or an array of sub-elements
+ * @param array An array of attribute name/value pairs
+ *
+ * @return objectref A reference to the new XMLElement
+ */
+ function &NewElement( $tagname, $content=false, $attributes=false, $xmlns=null ) {
+ if ( gettype($this->content) != "array" ) $this->content = array();
+ $element =/*&*/ new XMLElement($tagname,$content,$attributes,$xmlns);
+ $this->content[] =/*&*/ $element;
+ return $element;
+ }
+
+
+ /**
+ * Render just the internal content
+ *
+ * @return string The content of this element, as a string without this element wrapping it.
+ */
+ function RenderContent($indent=0, $nslist=null ) {
+ $r = "";
+ if ( is_array($this->content) ) {
+ /**
+ * Render the sub-elements with a deeper indent level
+ */
+ $r .= "\n";
+ foreach( $this->content AS $k => $v ) {
+ if ( is_object($v) ) {
+ $r .= $v->Render($indent+1, "", $nslist);
+ }
+ }
+ $r .= substr(" ",0,$indent);
+ }
+ else {
+ /**
+ * Render the content, with special characters escaped
+ *
+ */
+ $r .= htmlspecialchars($this->content, ENT_NOQUOTES );
+ }
+ return $r;
+ }
+
+
+ /**
+ * Render the document tree into (nicely formatted) XML
+ *
+ * @param int The indenting level for the pretty formatting of the element
+ */
+ function Render($indent=0, $xmldef="", $nslist=null) {
+ $r = ( $xmldef == "" ? "" : $xmldef."\n");
+
+ $attr = "";
+ $tagname = $this->tagname;
+ if ( gettype($this->attributes) == "array" ) {
+ /**
+ * Render the element attribute values
+ */
+ foreach( $this->attributes AS $k => $v ) {
+ if ( preg_match('#^xmlns(:?(.+))?$#', $k, $matches ) ) {
+ if ( !isset($nslist) ) $nslist = array();
+ $prefix = (isset($matches[2]) ? $matches[2] : '');
+ if ( isset($nslist[$v]) && $nslist[$v] == $prefix ) continue; // No need to include in list as it's in a wrapping element
+ $nslist[$v] = $prefix;
+ if ( !isset($this->xmlns) ) $this->xmlns = $v;
+ }
+ $attr .= sprintf( ' %s="%s"', $k, htmlspecialchars($v) );
+ }
+ }
+ if ( isset($this->xmlns) && isset($nslist[$this->xmlns]) && $nslist[$this->xmlns] != '' ) {
+ $tagname = $nslist[$this->xmlns] . ':' . $tagname;
+ }
+
+ $r .= substr(" ",0,$indent) . '<' . $tagname . $attr;
+
+ if ( (is_array($this->content) && count($this->content) > 0) || (!is_array($this->content) && strlen($this->content) > 0) ) {
+ $r .= ">";
+ $r .= $this->RenderContent($indent,$nslist);
+ $r .= '</' . $tagname.">\n";
+ }
+ else {
+ $r .= "/>\n";
+ }
+ return $r;
+ }
+}
+
+
+/**
+* Rebuild an XML tree in our own style from the parsed XML tags using
+* a tail-recursive approach.
+*
+* @param array $xmltags An array of XML tags we get from using the PHP XML parser
+* @param intref &$start_from A pointer to our current integer offset into $xmltags
+* @return mixed Either a single XMLElement, or an array of XMLElement objects.
+*/
+function BuildXMLTree( $xmltags, &$start_from ) {
+ $content = array();
+
+ if ( !isset($start_from) ) $start_from = 0;
+
+ for( $i=0; $i < 50000 && isset($xmltags[$start_from]); $i++) {
+ $tagdata = $xmltags[$start_from++];
+ if ( !isset($tagdata) || !isset($tagdata['tag']) || !isset($tagdata['type']) ) break;
+ if ( $tagdata['type'] == "close" ) break;
+ $attributes = ( isset($tagdata['attributes']) ? $tagdata['attributes'] : false );
+ if ( $tagdata['type'] == "open" ) {
+ $subtree = BuildXMLTree( $xmltags, $start_from );
+ $content[] = new XMLElement($tagdata['tag'], $subtree, $attributes );
+ }
+ else if ( $tagdata['type'] == "complete" ) {
+ $value = ( isset($tagdata['value']) ? $tagdata['value'] : false );
+ $content[] = new XMLElement($tagdata['tag'], $value, $attributes );
+ }
+ }
+
+ /**
+ * If there is only one element, return it directly, otherwise return the
+ * array of them
+ */
+ if ( count($content) == 1 ) {
+ return $content[0];
+ }
+ return $content;
+}
+
--- /dev/null
+<?php
+/**
+* A Class for handling iCalendar data.
+*
+* When parsed the underlying structure is roughly as follows:
+*
+* iCalendar( array(iCalComponent), array(iCalProp) )
+*
+* each iCalComponent is similarly structured:
+*
+* iCalComponent( array(iCalComponent), array(iCalProp) )
+*
+* Once parsed, $ical->component will point to the wrapping VCALENDAR component of
+* the iCalendar. This will be fine for simple iCalendar usage as sampled below,
+* but more complex iCalendar such as a VEVENT with RRULE which has repeat overrides
+* will need quite a bit more thought to process correctly.
+*
+* @example
+* To create a new iCalendar from several data values:
+* $ical = new iCalendar( array('DTSTART' => $dtstart, 'SUMMARY' => $summary, 'DURATION' => $duration ) );
+*
+* @example
+* To render it as an iCalendar string:
+* echo $ical->Render();
+*
+* @example
+* To render just the VEVENTs in the iCalendar with a restricted list of properties:
+* echo $ical->Render( false, 'VEVENT', array( 'DTSTART', 'DURATION', 'DTEND', 'RRULE', 'SUMMARY') );
+*
+* @example
+* To parse an existing iCalendar string for manipulation:
+* $ical = new iCalendar( array('icalendar' => $icalendar_text ) );
+*
+* @example
+* To clear any 'VALARM' components in an iCalendar object
+* $ical->component->ClearComponents('VALARM');
+*
+* @example
+* To replace any 'RRULE' property in an iCalendar object
+* $ical->component->SetProperties( 'RRULE', $rrule_definition );
+*
+* @package awl
+* @subpackage iCalendar
+* @author Andrew McMillan <andrew@mcmillan.net.nz>
+* @copyright Catalyst IT Ltd, Morphoss Ltd <http://www.morphoss.com/>
+* @license http://gnu.org/copyleft/gpl.html GNU GPL v2 or later
+*
+*/
+require_once("XMLElement.php");
+
+/**
+* A Class for representing properties within an iCalendar
+*
+* @package awl
+*/
+class iCalProp {
+ /**#@+
+ * @access private
+ */
+
+ /**
+ * The name of this property
+ *
+ * @var string
+ */
+ var $name;
+
+ /**
+ * An array of parameters to this property, represented as key/value pairs.
+ *
+ * @var array
+ */
+ var $parameters;
+
+ /**
+ * The value of this property.
+ *
+ * @var string
+ */
+ var $content;
+
+ /**
+ * The original value that this was parsed from, if that's the way it happened.
+ *
+ * @var string
+ */
+ var $rendered;
+
+ /**#@-*/
+
+ /**
+ * The constructor parses the incoming string, which is formatted as per RFC2445 as a
+ * propname[;param1=pval1[; ... ]]:propvalue
+ * however we allow ourselves to assume that the RFC2445 content unescaping has already
+ * happened when iCalComponent::ParseFrom() called iCalComponent::UnwrapComponent().
+ *
+ * @param string $propstring The string from the iCalendar which contains this property.
+ */
+ function iCalProp( $propstring = null ) {
+ $this->name = "";
+ $this->content = "";
+ $this->parameters = array();
+ unset($this->rendered);
+ if ( $propstring != null && gettype($propstring) == 'string' ) {
+ $this->ParseFrom($propstring);
+ }
+ }
+
+
+ /**
+ * The constructor parses the incoming string, which is formatted as per RFC2445 as a
+ * propname[;param1=pval1[; ... ]]:propvalue
+ * however we allow ourselves to assume that the RFC2445 content unescaping has already
+ * happened when iCalComponent::ParseFrom() called iCalComponent::UnwrapComponent().
+ *
+ * @param string $propstring The string from the iCalendar which contains this property.
+ */
+ function ParseFrom( $propstring ) {
+ $this->rendered = (strlen($propstring) < 72 ? $propstring : null); // Only pre-rendered if we didn't unescape it
+ $pos = strpos( $propstring, ':');
+ $start = substr( $propstring, 0, $pos);
+
+ $unescaped = str_replace( '\\n', "\n", substr( $propstring, $pos + 1));
+ $unescaped = str_replace( '\\N', "\n", $unescaped);
+ $this->content = preg_replace( "/\\\\([,;:\"\\\\])/", '$1', $unescaped);
+
+ $parameters = explode(';',$start);
+ $this->name = array_shift( $parameters );
+ $this->parameters = array();
+ foreach( $parameters AS $k => $v ) {
+ $pos = strpos($v,'=');
+ $name = substr( $v, 0, $pos);
+ $value = substr( $v, $pos + 1);
+ $this->parameters[$name] = $value;
+ }
+ dbg_error_log("iCalendar", " iCalProp::ParseFrom found '%s' = '%s' with %d parameters", $this->name, $this->content, count($this->parameters) );
+ }
+
+
+ /**
+ * Get/Set name property
+ *
+ * @param string $newname [optional] A new name for the property
+ *
+ * @return string The name for the property.
+ */
+ function Name( $newname = null ) {
+ if ( $newname != null ) {
+ $this->name = $newname;
+ if ( isset($this->rendered) ) unset($this->rendered);
+ dbg_error_log("iCalendar", " iCalProp::Name(%s)", $this->name );
+ }
+ return $this->name;
+ }
+
+
+ /**
+ * Get/Set the content of the property
+ *
+ * @param string $newvalue [optional] A new value for the property
+ *
+ * @return string The value of the property.
+ */
+ function Value( $newvalue = null ) {
+ if ( $newvalue != null ) {
+ $this->content = $newvalue;
+ if ( isset($this->rendered) ) unset($this->rendered);
+ }
+ return $this->content;
+ }
+
+
+ /**
+ * Get/Set parameters in their entirety
+ *
+ * @param array $newparams An array of new parameter key/value pairs
+ *
+ * @return array The current array of parameters for the property.
+ */
+ function Parameters( $newparams = null ) {
+ if ( $newparams != null ) {
+ $this->parameters = $newparams;
+ if ( isset($this->rendered) ) unset($this->rendered);
+ }
+ return $this->parameters;
+ }
+
+
+ /**
+ * Test if our value contains a string
+ *
+ * @param string $search The needle which we shall search the haystack for.
+ *
+ * @return string The name for the property.
+ */
+ function TextMatch( $search ) {
+ if ( isset($this->content) ) return strstr( $this->content, $search );
+ return false;
+ }
+
+
+ /**
+ * Get the value of a parameter
+ *
+ * @param string $name The name of the parameter to retrieve the value for
+ *
+ * @return string The value of the parameter
+ */
+ function GetParameterValue( $name ) {
+ if ( isset($this->parameters[$name]) ) return $this->parameters[$name];
+ }
+
+ /**
+ * Set the value of a parameter
+ *
+ * @param string $name The name of the parameter to set the value for
+ *
+ * @param string $value The value of the parameter
+ */
+ function SetParameterValue( $name, $value ) {
+ if ( isset($this->rendered) ) unset($this->rendered);
+ $this->parameters[$name] = $value;
+ }
+
+ /**
+ * Render the set of parameters as key1=value1[;key2=value2[; ...]] with
+ * any colons or semicolons escaped.
+ */
+ function RenderParameters() {
+ $rendered = "";
+ foreach( $this->parameters AS $k => $v ) {
+ $escaped = preg_replace( "/([;:\"])/", '\\\\$1', $v);
+ $rendered .= sprintf( ";%s=%s", $k, $escaped );
+ }
+ return $rendered;
+ }
+
+
+ /**
+ * Render a suitably escaped RFC2445 content string.
+ */
+ function Render() {
+ // If we still have the string it was parsed in from, it hasn't been screwed with
+ // and we can just return that without modification.
+ if ( isset($this->rendered) ) return $this->rendered;
+
+ $property = preg_replace( '/[;].*$/', '', $this->name );
+ $escaped = $this->content;
+ switch( $property ) {
+ /** Content escaping does not apply to these properties culled from RFC2445 */
+ case 'ATTACH': case 'GEO': case 'PERCENT-COMPLETE': case 'PRIORITY':
+ case 'DURATION': case 'FREEBUSY': case 'TZOFFSETFROM': case 'TZOFFSETTO':
+ case 'TZURL': case 'ATTENDEE': case 'ORGANIZER': case 'RECURRENCE-ID':
+ case 'URL': case 'EXRULE': case 'SEQUENCE': case 'CREATED':
+ case 'RRULE': case 'REPEAT': case 'TRIGGER':
+ break;
+
+ case 'COMPLETED': case 'DTEND':
+ case 'DUE': case 'DTSTART':
+ case 'DTSTAMP': case 'LAST-MODIFIED':
+ case 'CREATED': case 'EXDATE':
+ case 'RDATE':
+ if ( isset($this->parameters['VALUE']) && $this->parameters['VALUE'] == 'DATE' ) {
+ $escaped = substr( $escaped, 0, 8);
+ }
+ break;
+
+ /** Content escaping applies by default to other properties */
+ default:
+ $escaped = str_replace( '\\', '\\\\', $escaped);
+ $escaped = preg_replace( '/\r?\n/', '\\n', $escaped);
+ $escaped = preg_replace( "/([,;\"])/", '\\\\$1', $escaped);
+ }
+ $property = sprintf( "%s%s:", $this->name, $this->RenderParameters() );
+ if ( (strlen($property) + strlen($escaped)) <= 72 ) {
+ $this->rendered = $property . $escaped;
+ }
+ else if ( (strlen($property) + strlen($escaped)) > 72 && (strlen($property) < 72) && (strlen($escaped) < 72) ) {
+ $this->rendered = $property . " \r\n " . $escaped;
+ }
+ else {
+ $this->rendered = wordwrap( $property . $escaped, 72, " \r\n ", true );
+ }
+ return $this->rendered;
+ }
+
+}
+
+
+/**
+* A Class for representing components within an iCalendar
+*
+* @package awl
+*/
+class iCalComponent {
+ /**#@+
+ * @access private
+ */
+
+ /**
+ * The type of this component, such as 'VEVENT', 'VTODO', 'VTIMEZONE', etc.
+ *
+ * @var string
+ */
+ var $type;
+
+ /**
+ * An array of properties, which are iCalProp objects
+ *
+ * @var array
+ */
+ var $properties;
+
+ /**
+ * An array of (sub-)components, which are iCalComponent objects
+ *
+ * @var array
+ */
+ var $components;
+
+ /**
+ * The rendered result (or what was originally parsed, if there have been no changes)
+ *
+ * @var array
+ */
+ var $rendered;
+
+ /**#@-*/
+
+ /**
+ * A basic constructor
+ */
+ function iCalComponent( $content = null ) {
+ $this->type = "";
+ $this->properties = array();
+ $this->components = array();
+ $this->rendered = "";
+ if ( $content != null && gettype($content) == 'string' ) {
+ $this->ParseFrom($content);
+ }
+ }
+
+
+ /**
+ * Apply standard properties for a VCalendar
+ * @param array $extra_properties Key/value pairs of additional properties
+ */
+ function VCalendar( $extra_properties = null ) {
+ $this->SetType('VCALENDAR');
+ $this->AddProperty('PRODID', '-//davical.org//NONSGML AWL Calendar//EN');
+ $this->AddProperty('VERSION', '2.0');
+ $this->AddProperty('CALSCALE', 'GREGORIAN');
+ if ( is_array($extra_properties) ) {
+ foreach( $extra_properties AS $k => $v ) {
+ $this->AddProperty($k,$v);
+ }
+ }
+ }
+
+ /**
+ * Collect an array of all parameters of our properties which are the specified type
+ * Mainly used for collecting the full variety of references TZIDs
+ */
+ function CollectParameterValues( $parameter_name ) {
+ $values = array();
+ foreach( $this->components AS $k => $v ) {
+ $also = $v->CollectParameterValues($parameter_name);
+ $values = array_merge( $values, $also );
+ }
+ foreach( $this->properties AS $k => $v ) {
+ $also = $v->GetParameterValue($parameter_name);
+ if ( isset($also) && $also != "" ) {
+ dbg_error_log( "iCalendar", "::CollectParameterValues(%s) : Found '%s'", $parameter_name, $also);
+ $values[$also] = 1;
+ }
+ }
+ return $values;
+ }
+
+
+ /**
+ * Parse the text $content into sets of iCalProp & iCalComponent within this iCalComponent
+ * @param string $content The raw RFC2445-compliant iCalendar component, including BEGIN:TYPE & END:TYPE
+ */
+ function ParseFrom( $content ) {
+ $this->rendered = $content;
+ $content = $this->UnwrapComponent($content);
+
+ $lines = preg_split('/\r?\n/', $content );
+
+ $type = false;
+ $subtype = false;
+ $finish = null;
+ $subfinish = null;
+ foreach( $lines AS $k => $v ) {
+ if ( preg_match('/^\s*$/', $v ) ) continue;
+ dbg_error_log( "iCalendar", "::ParseFrom: Parsing line: $v");
+ if ( $type === false ) {
+ if ( preg_match( '/^BEGIN:(.+)$/', $v, $matches ) ) {
+ // We have found the start of the main component
+ $type = $matches[1];
+ $finish = "END:$type";
+ $this->type = $type;
+ dbg_error_log( "iCalendar", "::ParseFrom: Start component of type '%s'", $type);
+ }
+ else {
+ dbg_error_log( "iCalendar", "::ParseFrom: Ignoring crap before start of component");
+ unset($lines[$k]); // The content has crap before the start
+ if ( $v != "" ) $this->rendered = null;
+ }
+ }
+ else if ( $type == null ) {
+ dbg_error_log( "iCalendar", "::ParseFrom: Ignoring crap after end of component");
+ unset($lines[$k]); // The content has crap after the end
+ if ( $v != "" ) $this->rendered = null;
+ }
+ else if ( $v == $finish ) {
+ dbg_error_log( "iCalendar", "::ParseFrom: End of component");
+ $type = null; // We have reached the end of our component
+ }
+ else {
+ if ( $subtype === false && preg_match( '/^BEGIN:(.+)$/', $v, $matches ) ) {
+ // We have found the start of a sub-component
+ $subtype = $matches[1];
+ $subfinish = "END:$subtype";
+ $subcomponent = "$v\r\n";
+ dbg_error_log( "iCalendar", "::ParseFrom: Found a subcomponent '%s'", $subtype);
+ }
+ else if ( $subtype ) {
+ // We are inside a sub-component
+ $subcomponent .= $this->WrapComponent($v);
+ if ( $v == $subfinish ) {
+ dbg_error_log( "iCalendar", "::ParseFrom: End of subcomponent '%s'", $subtype);
+ // We have found the end of a sub-component
+ $this->components[] = new iCalComponent($subcomponent);
+ $subtype = false;
+ }
+ else
+ dbg_error_log( "iCalendar", "::ParseFrom: Inside a subcomponent '%s'", $subtype );
+ }
+ else {
+ dbg_error_log( "iCalendar", "::ParseFrom: Parse property of component");
+ // It must be a normal property line within a component.
+ $this->properties[] = new iCalProp($v);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * This unescapes the (CRLF + linear space) wrapping specified in RFC2445. According
+ * to RFC2445 we should always end with CRLF but the CalDAV spec says that normalising
+ * XML parsers often muck with it and may remove the CR. We accept either case.
+ */
+ function UnwrapComponent( $content ) {
+ return preg_replace('/\r?\n[ \t]/', '', $content );
+ }
+
+ /**
+ * This imposes the (CRLF + linear space) wrapping specified in RFC2445. According
+ * to RFC2445 we should always end with CRLF but the CalDAV spec says that normalising
+ * XML parsers often muck with it and may remove the CR. We output RFC2445 compliance.
+ *
+ * In order to preserve pre-existing wrapping in the component, we split the incoming
+ * string on line breaks before running wordwrap over each component of that.
+ */
+ function WrapComponent( $content ) {
+ $strs = preg_split( "/\r?\n/", $content );
+ $wrapped = "";
+ foreach ($strs as $str) {
+ $wrapped .= wordwrap($str, 73, " \r\n ") . "\r\n";
+ }
+ return $wrapped;
+ }
+
+ /**
+ * Return the type of component which this is
+ */
+ function GetType() {
+ return $this->type;
+ }
+
+
+ /**
+ * Set the type of component which this is
+ */
+ function SetType( $type ) {
+ if ( isset($this->rendered) ) unset($this->rendered);
+ $this->type = $type;
+ return $this->type;
+ }
+
+
+ /**
+ * Get all properties, or the properties matching a particular type
+ */
+ function GetProperties( $type = null ) {
+ $properties = array();
+ foreach( $this->properties AS $k => $v ) {
+ if ( $type == null || $v->Name() == $type ) {
+ $properties[$k] = $v;
+ }
+ }
+ return $properties;
+ }
+
+
+ /**
+ * Get the value of the first property matching the name. Obviously this isn't
+ * so useful for properties which may occur multiply, but most don't.
+ *
+ * @param string $type The type of property we are after.
+ * @return string The value of the property, or null if there was no such property.
+ */
+ function GetPValue( $type ) {
+ foreach( $this->properties AS $k => $v ) {
+ if ( $v->Name() == $type ) return $v->Value();
+ }
+ return null;
+ }
+
+
+ /**
+ * Get the value of the specified parameter for the first property matching the
+ * name. Obviously this isn't so useful for properties which may occur multiply, but most don't.
+ *
+ * @param string $type The type of property we are after.
+ * @param string $type The name of the parameter we are after.
+ * @return string The value of the parameter for the property, or null in the case that there was no such property, or no such parameter.
+ */
+ function GetPParamValue( $type, $parameter_name ) {
+ foreach( $this->properties AS $k => $v ) {
+ if ( $v->Name() == $type ) return $v->GetParameterValue($parameter_name);
+ }
+ return null;
+ }
+
+
+ /**
+ * Clear all properties, or the properties matching a particular type
+ * @param string $type The type of property - omit for all properties
+ */
+ function ClearProperties( $type = null ) {
+ if ( $type != null ) {
+ // First remove all the existing ones of that type
+ foreach( $this->properties AS $k => $v ) {
+ if ( $v->Name() == $type ) {
+ unset($this->properties[$k]);
+ if ( isset($this->rendered) ) unset($this->rendered);
+ }
+ }
+ $this->properties = array_values($this->properties);
+ }
+ else {
+ if ( isset($this->rendered) ) unset($this->rendered);
+ $this->properties = array();
+ }
+ }
+
+
+ /**
+ * Set all properties, or the ones matching a particular type
+ */
+ function SetProperties( $new_properties, $type = null ) {
+ if ( isset($this->rendered) && count($new_properties) > 0 ) unset($this->rendered);
+ $this->ClearProperties($type);
+ foreach( $new_properties AS $k => $v ) {
+ $this->AddProperty($v);
+ }
+ }
+
+
+ /**
+ * Adds a new property
+ *
+ * @param iCalProp $new_property The new property to append to the set, or a string with the name
+ * @param string $value The value of the new property (default: param 1 is an iCalProp with everything
+ * @param array $parameters The key/value parameter pairs (default: none, or param 1 is an iCalProp with everything)
+ */
+ function AddProperty( $new_property, $value = null, $parameters = null ) {
+ if ( isset($this->rendered) ) unset($this->rendered);
+ if ( isset($value) && gettype($new_property) == 'string' ) {
+ $new_prop = new iCalProp();
+ $new_prop->Name($new_property);
+ $new_prop->Value($value);
+ if ( $parameters != null ) $new_prop->Parameters($parameters);
+ dbg_error_log("iCalendar"," Adding new property '%s'", $new_prop->Render() );
+ $this->properties[] = $new_prop;
+ }
+ else if ( gettype($new_property) ) {
+ $this->properties[] = $new_property;
+ }
+ }
+
+
+ /**
+ * Get all sub-components, or at least get those matching a type
+ * @return array an array of the sub-components
+ */
+ function &FirstNonTimezone( $type = null ) {
+ foreach( $this->components AS $k => $v ) {
+ if ( $v->GetType() != 'VTIMEZONE' ) return $this->components[$k];
+ }
+ $result = false;
+ return $result;
+ }
+
+
+ /**
+ * Return true if the person identified by the email address is down as an
+ * organizer for this meeting.
+ * @param string $email The e-mail address of the person we're seeking.
+ * @return boolean true if we found 'em, false if we didn't.
+ */
+ function IsOrganizer( $email ) {
+ if ( !preg_match( '#^mailto:#', $email ) ) $email = 'mailto:$email';
+ $props = $this->GetPropertiesByPath('!VTIMEZONE/ORGANIZER');
+ foreach( $props AS $k => $prop ) {
+ if ( $prop->Value() == $email ) return true;
+ }
+ return false;
+ }
+
+
+ /**
+ * Return true if the person identified by the email address is down as an
+ * attendee or organizer for this meeting.
+ * @param string $email The e-mail address of the person we're seeking.
+ * @return boolean true if we found 'em, false if we didn't.
+ */
+ function IsAttendee( $email ) {
+ if ( !preg_match( '#^mailto:#', $email ) ) $email = 'mailto:$email';
+ if ( $this->IsOrganizer($email) ) return true; /** an organizer is an attendee, as far as we're concerned */
+ $props = $this->GetPropertiesByPath('!VTIMEZONE/ATTENDEE');
+ foreach( $props AS $k => $prop ) {
+ if ( $prop->Value() == $email ) return true;
+ }
+ return false;
+ }
+
+
+ /**
+ * Get all sub-components, or at least get those matching a type, or failling to match,
+ * should the second parameter be set to false.
+ *
+ * @param string $type The type to match (default: All)
+ * @param boolean $normal_match Set to false to invert the match (default: true)
+ * @return array an array of the sub-components
+ */
+ function GetComponents( $type = null, $normal_match = true ) {
+ $components = $this->components;
+ if ( $type != null ) {
+ foreach( $components AS $k => $v ) {
+ if ( ($v->GetType() != $type) === $normal_match ) {
+ unset($components[$k]);
+ }
+ }
+ $components = array_values($components);
+ }
+ return $components;
+ }
+
+
+ /**
+ * Clear all components, or the components matching a particular type
+ * @param string $type The type of component - omit for all components
+ */
+ function ClearComponents( $type = null ) {
+ if ( $type != null ) {
+ // First remove all the existing ones of that type
+ foreach( $this->components AS $k => $v ) {
+ if ( $v->GetType() == $type ) {
+ unset($this->components[$k]);
+ if ( isset($this->rendered) ) unset($this->rendered);
+ }
+ else {
+ if ( ! $this->components[$k]->ClearComponents($type) ) {
+ if ( isset($this->rendered) ) unset($this->rendered);
+ }
+ }
+ }
+ return isset($this->rendered);
+ }
+ else {
+ if ( isset($this->rendered) ) unset($this->rendered);
+ $this->components = array();
+ }
+ }
+
+
+ /**
+ * Sets some or all sub-components of the component to the supplied new components
+ *
+ * @param array of iCalComponent $new_components The new components to replace the existing ones
+ * @param string $type The type of components to be replaced. Defaults to null, which means all components will be replaced.
+ */
+ function SetComponents( $new_component, $type = null ) {
+ if ( isset($this->rendered) ) unset($this->rendered);
+ if ( count($new_component) > 0 ) $this->ClearComponents($type);
+ foreach( $new_component AS $k => $v ) {
+ $this->components[] = $v;
+ }
+ }
+
+
+ /**
+ * Adds a new subcomponent
+ *
+ * @param iCalComponent $new_component The new component to append to the set
+ */
+ function AddComponent( $new_component ) {
+ if ( is_array($new_component) && count($new_component) == 0 ) return;
+ if ( isset($this->rendered) ) unset($this->rendered);
+ if ( is_array($new_component) ) {
+ foreach( $new_component AS $k => $v ) {
+ $this->components[] = $v;
+ }
+ }
+ else {
+ $this->components[] = $new_component;
+ }
+ }
+
+
+ /**
+ * Mask components, removing any that are not of the types in the list
+ * @param array $keep An array of component types to be kept
+ */
+ function MaskComponents( $keep ) {
+ foreach( $this->components AS $k => $v ) {
+ if ( ! in_array( $v->GetType(), $keep ) ) {
+ unset($this->components[$k]);
+ if ( isset($this->rendered) ) unset($this->rendered);
+ }
+ else {
+ $v->MaskComponents($keep);
+ }
+ }
+ }
+
+
+ /**
+ * Mask properties, removing any that are not in the list
+ * @param array $keep An array of property names to be kept
+ * @param array $component_list An array of component types to check within
+ */
+ function MaskProperties( $keep, $component_list=null ) {
+ foreach( $this->components AS $k => $v ) {
+ $v->MaskProperties($keep, $component_list);
+ }
+
+ if ( !isset($component_list) || in_array($this->GetType(),$component_list) ) {
+ foreach( $this->components AS $k => $v ) {
+ if ( ! in_array( $v->GetType(), $keep ) ) {
+ unset($this->components[$k]);
+ if ( isset($this->rendered) ) unset($this->rendered);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Clone this component (and subcomponents) into a confidential version of it. A confidential
+ * event will be scrubbed of any identifying characteristics other than time/date, repeat, uid
+ * and a summary which is just a translated 'Busy'.
+ */
+ function CloneConfidential() {
+ $confidential = clone($this);
+ $keep_properties = array( 'DTSTAMP', 'DTSTART', 'RRULE', 'DURATION', 'DTEND', 'UID', 'CLASS', 'TRANSP' );
+ $resource_components = array( 'VEVENT', 'VTODO', 'VJOURNAL' );
+ $confidential->MaskComponents(array( 'VTIMEZONE', 'VEVENT', 'VTODO', 'VJOURNAL' ));
+ $confidential->MaskProperties($keep_properties, $resource_components );
+ if ( in_array( $confidential->GetType(), $resource_components ) ) {
+ $confidential->AddProperty( 'SUMMARY', translate('Busy') );
+ }
+ foreach( $confidential->components AS $k => $v ) {
+ if ( in_array( $v->GetType(), $resource_components ) ) {
+ $v->AddProperty( 'SUMMARY', translate('Busy') );
+ }
+ }
+
+ return $confidential;
+ }
+
+
+ /**
+ * Renders the component, possibly restricted to only the listed properties
+ */
+ function Render( $restricted_properties = null) {
+
+ $unrestricted = (!isset($restricted_properties) || count($restricted_properties) == 0);
+
+ if ( isset($this->rendered) && $unrestricted )
+ return $this->rendered;
+
+ $rendered = "BEGIN:$this->type\r\n";
+ foreach( $this->properties AS $k => $v ) {
+ if ( $unrestricted || isset($restricted_properties[$v]) ) $rendered .= $v->Render() . "\r\n";
+ }
+ foreach( $this->components AS $v ) { $rendered .= $v->Render(); }
+ $rendered .= "END:$this->type\r\n";
+// $rendered = $this->WrapComponent($rendered);
+
+ if ( $unrestricted ) $this->rendered = $rendered;
+
+ return $rendered;
+ }
+
+ /**
+ * Return an array of properties matching the specified path
+ *
+ * @return array An array of iCalProp within the tree which match the path given, in the form
+ * [/]COMPONENT[/...]/PROPERTY in a syntax kind of similar to our poor man's XML queries. We
+ * also allow COMPONENT and PROPERTY to be !COMPONENT and !PROPERTY for ++fun.
+ *
+ * @note At some point post PHP4 this could be re-done with an iterator, which should be more efficient for common use cases.
+ */
+ function GetPropertiesByPath( $path ) {
+ $properties = array();
+ dbg_error_log( "iCalendar", "GetPropertiesByPath: Querying within '%s' for path '%s'", $this->type, $path );
+ if ( !preg_match( '#(/?)(!?)([^/]+)(/?.*)$#', $path, $matches ) ) return $properties;
+
+ $adrift = ($matches[1] == '');
+ $normal = ($matches[2] == '');
+ $ourtest = $matches[3];
+ $therest = $matches[4];
+ dbg_error_log( "iCalendar", "GetPropertiesByPath: Matches: %s -- %s -- %s -- %s\n", $matches[1], $matches[2], $matches[3], $matches[4] );
+ if ( $ourtest == '*' || (($ourtest == $this->type) === $normal) && $therest != '' ) {
+ if ( preg_match( '#^/(!?)([^/]+)$#', $therest, $matches ) ) {
+ $normmatch = ($matches[1] =='');
+ $proptest = $matches[2];
+ foreach( $this->properties AS $k => $v ) {
+ if ( $proptest = '*' || (($v->Name() == $proptest) === $normmatch ) ) {
+ $properties[] = $v;
+ }
+ }
+ }
+ else {
+ /**
+ * There is more to the path, so we recurse into that sub-part
+ */
+ foreach( $this->components AS $k => $v ) {
+ $properties = array_merge( $properties, $v->GetPropertiesByPath($therest) );
+ }
+ }
+ }
+
+ if ( $adrift ) {
+ /**
+ * Our input $path was not rooted, so we recurse further
+ */
+ foreach( $this->components AS $k => $v ) {
+ $properties = array_merge( $properties, $v->GetPropertiesByPath($path) );
+ }
+ }
+ dbg_error_log("iCalendar", "GetPropertiesByPath: Found %d within '%s' for path '%s'\n", count($properties), $this->type, $path );
+ return $properties;
+ }
+
+}
+
+/**
+************************************************************************************
+* Pretty much everything below here is deprecated and should be avoided in favour
+* of using, improving and enhancing the more sensible structures above.
+************************************************************************************
+*/
+
+/**
+* A Class for handling Events on a calendar
+*
+* @package awl
+*/
+class iCalendar {
+ /**#@+
+ * @access private
+ */
+
+ /**
+ * The component-ised version of the iCalendar
+ * @var component iCalComponent
+ */
+ var $component;
+
+ /**
+ * An array of arbitrary properties, containing arbitrary arrays of arbitrary properties
+ * @var properties array
+ */
+ var $properties;
+
+ /**
+ * An array of the lines of this iCalendar resource
+ * @var lines array
+ */
+ var $lines;
+
+ /**
+ * The typical location name for the standard timezone such as "Pacific/Auckland"
+ * @var tz_locn string
+ */
+ var $tz_locn;
+
+ /**
+ * The type of iCalendar data VEVENT/VTODO/VJOURNAL
+ * @var type string
+ */
+ var $type;
+
+ /**#@-*/
+
+ /**
+ * The constructor takes an array of args. If there is an element called 'icalendar'
+ * then that will be parsed into the iCalendar object. Otherwise the array elements
+ * are converted into properties of the iCalendar object directly.
+ */
+ function iCalendar( $args ) {
+ global $c;
+
+ $this->tz_locn = "";
+ if ( !isset($args) || !(is_array($args) || is_object($args)) ) return;
+ if ( is_object($args) ) {
+ settype($args,'array');
+ }
+
+ $this->component = new iCalComponent();
+ if ( isset($args['icalendar']) ) {
+ $this->component->ParseFrom($args['icalendar']);
+ $this->lines = preg_split('/\r?\n/', $args['icalendar'] );
+ $this->SaveTimeZones();
+ $first =& $this->component->FirstNonTimezone();
+ if ( $first ) {
+ $this->type = $first->GetType();
+ $this->properties = $first->GetProperties();
+ }
+ else {
+ $this->properties = array();
+ }
+ $this->properties['VCALENDAR'] = array('***ERROR*** This class is being referenced in an unsupported way!');
+ return;
+ }
+
+ if ( isset($args['type'] ) ) {
+ $this->type = $args['type'];
+ unset( $args['type'] );
+ }
+ else {
+ $this->type = 'VEVENT'; // Default to event
+ }
+ $this->component->SetType('VCALENDAR');
+ $this->component->SetProperties(
+ array(
+ new iCalProp('PRODID:-//davical.org//NONSGML AWL Calendar//EN'),
+ new iCalProp('VERSION:2.0'),
+ new iCalProp('CALSCALE:GREGORIAN')
+ )
+ );
+ $first = new iCalComponent();
+ $first->SetType($this->type);
+ $this->properties = array();
+
+ foreach( $args AS $k => $v ) {
+ dbg_error_log( "iCalendar", ":Initialise: %s to >>>%s<<<", $k, $v );
+ $property = new iCalProp();
+ $property->Name($k);
+ $property->Value($v);
+ $this->properties[] = $property;
+ }
+ $first->SetProperties($this->properties);
+ $this->component->SetComponents( array($first) );
+
+ $this->properties['VCALENDAR'] = array('***ERROR*** This class is being referenced in an unsupported way!');
+
+ /**
+ * @todo Need to handle timezones!!!
+ */
+ if ( $this->tz_locn == "" ) {
+ $this->tz_locn = $this->Get("tzid");
+ if ( (!isset($this->tz_locn) || $this->tz_locn == "") && isset($c->local_tzid) ) {
+ $this->tz_locn = $c->local_tzid;
+ }
+ }
+ }
+
+
+ /**
+ * Save any timezones by TZID in the PostgreSQL database for future re-use.
+ */
+ function SaveTimeZones() {
+ global $c;
+
+ $this->tzid_list = array_keys($this->component->CollectParameterValues('TZID'));
+ if ( ! isset($this->tzid) && count($this->tzid_list) > 0 ) {
+ dbg_error_log( "icalendar", "::TZID_List[0] = '%s', count=%d", $this->tzid_list[0], count($this->tzid_list) );
+ $this->tzid = $this->tzid_list[0];
+ }
+
+ $timezones = $this->component->GetComponents('VTIMEZONE');
+ if ( $timezones === false || count($timezones) == 0 ) return;
+ $this->vtimezone = $timezones[0]->Render(); // Backward compatibility
+
+ $tzid = $this->Get('TZID');
+ if ( isset($c->save_time_zone_defs) && $c->save_time_zone_defs ) {
+ foreach( $timezones AS $k => $tz ) {
+ $tzid = $tz->GetPValue('TZID');
+
+ $qry = new PgQuery( "SELECT tz_locn FROM time_zone WHERE tz_id = ?;", $tzid );
+ if ( $qry->Exec('iCalendar') && $qry->rows == 1 ) {
+ $row = $qry->Fetch();
+ if ( !isset($first_tzid) ) $first_tzid = $row->tz_locn;
+ continue;
+ }
+
+ if ( $tzid != "" && $qry->rows == 0 ) {
+
+ $tzname = $tz->GetPValue('X-LIC-LOCATION');
+ if ( !isset($tzname) ) {
+ /**
+ * Try and convert the TZID to a string like "Pacific/Auckland" if possible.
+ */
+ $tzname = preg_replace('#^(.*[^a-z])?([a-z]+/[a-z]+)$#i','$2',$tzid );
+ }
+
+ $qry2 = new PgQuery( "INSERT INTO time_zone (tz_id, tz_locn, tz_spec) VALUES( ?, ?, ? );",
+ $tzid, $tzname, $tz->Render() );
+ $qry2->Exec("iCalendar");
+ }
+ }
+ }
+ if ( ! isset($this->tzid) && isset($first_tzid) ) $this->tzid = $first_tzid;
+
+ if ( (!isset($this->tz_locn) || $this->tz_locn == '') && isset($first_tzid) && $first_tzid != '' ) {
+ $tzname = preg_replace('#^(.*[^a-z])?([a-z]+/[a-z]+)$#i','$2', $first_tzid );
+ if ( preg_match( '#\S+/\S+#', $tzname) ) {
+ $this->tz_locn = $tzname;
+ }
+ dbg_error_log( "icalendar", " TZCrap1: TZID '%s', Location '%s', Perhaps: %s", $tzid, $this->tz_locn, $tzname );
+ }
+
+ if ( (!isset($this->tz_locn) || $this->tz_locn == "") && isset($c->local_tzid) ) {
+ $this->tz_locn = $c->local_tzid;
+ }
+ if ( ! isset($this->tzid) && isset($this->tz_locn) ) $this->tzid = $this->tz_locn;
+ }
+
+
+ /**
+ * An array of property names that we should always want when rendering an iCalendar
+ *
+ * @deprecated This function is deprecated and will be removed eventually.
+ * @todo Remove this function.
+ */
+ function DefaultPropertyList() {
+ dbg_error_log( "LOG", " iCalendar: Call to deprecated method '%s'", 'DefaultPropertyList' );
+ return array( "UID" => 1, "DTSTAMP" => 1, "DTSTART" => 1, "DURATION" => 1,
+ "LAST-MODIFIED" => 1,"CLASS" => 1, "TRANSP" => 1, "SEQUENCE" => 1,
+ "DUE" => 1, "SUMMARY" => 1, "RRULE" => 1 );
+ }
+
+ /**
+ * A function to extract the contents of a BEGIN:SOMETHING to END:SOMETHING (perhaps multiply)
+ * and return just that bit (or, of course, those bits :-)
+ *
+ * @var string The type of thing(s) we want returned.
+ * @var integer The number of SOMETHINGS we want to get.
+ *
+ * @return string A string from BEGIN:SOMETHING to END:SOMETHING, possibly multiple of these
+ *
+ * @deprecated This function is deprecated and will be removed eventually.
+ * @todo Remove this function.
+ */
+ function JustThisBitPlease( $type, $count=1 ) {
+ dbg_error_log( "LOG", " iCalendar: Call to deprecated method '%s'", 'JustThisBitPlease' );
+ $answer = "";
+ $intags = false;
+ $start = "BEGIN:$type";
+ $finish = "END:$type";
+ dbg_error_log( "iCalendar", ":JTBP: Looking for %d subsets of type %s", $count, $type );
+ reset($this->lines);
+ foreach( $this->lines AS $k => $v ) {
+ if ( !$intags && $v == $start ) {
+ $answer .= $v . "\n";
+ $intags = true;
+ }
+ else if ( $intags && $v == $finish ) {
+ $answer .= $v . "\n";
+ $intags = false;
+ }
+ else if ( $intags ) {
+ $answer .= $v . "\n";
+ }
+ }
+ return $answer;
+ }
+
+
+ /**
+ * Function to parse lines from BEGIN:SOMETHING to END:SOMETHING into a nested array structure
+ *
+ * @var string The "SOMETHING" from the BEGIN:SOMETHING line we just met
+ * @return arrayref An array of the things we found between (excluding) the BEGIN & END, some of which might be sub-arrays
+ *
+ * @deprecated This function is deprecated and will be removed eventually.
+ * @todo Remove this function.
+ */
+ function &ParseSomeLines( $type ) {
+ dbg_error_log( "LOG", " iCalendar: Call to deprecated method '%s'", 'ParseSomeLines' );
+ $props = array();
+ $properties =& $props;
+ while( isset($this->lines[$this->_current_parse_line]) ) {
+ $i = $this->_current_parse_line++;
+ $line =& $this->lines[$i];
+ dbg_error_log( "iCalendar", ":Parse:%s LINE %03d: >>>%s<<<", $type, $i, $line );
+ if ( $this->parsing_vtimezone ) {
+ $this->vtimezone .= $line."\n";
+ }
+ if ( preg_match( '/^(BEGIN|END):([^:]+)$/', $line, $matches ) ) {
+ if ( $matches[1] == 'END' && $matches[2] == $type ) {
+ if ( $type == 'VTIMEZONE' ) {
+ $this->parsing_vtimezone = false;
+ }
+ return $properties;
+ }
+ else if( $matches[1] == 'END' ) {
+ dbg_error_log("ERROR"," iCalendar: parse error: Unexpected END:%s when we were looking for END:%s", $matches[2], $type );
+ return $properties;
+ }
+ else if( $matches[1] == 'BEGIN' ) {
+ $subtype = $matches[2];
+ if ( $subtype == 'VTIMEZONE' ) {
+ $this->parsing_vtimezone = true;
+ $this->vtimezone = $line."\n";
+ }
+ if ( !isset($properties['INSIDE']) ) $properties['INSIDE'] = array();
+ $properties['INSIDE'][] = $subtype;
+ if ( !isset($properties[$subtype]) ) $properties[$subtype] = array();
+ $properties[$subtype][] = $this->ParseSomeLines($subtype);
+ }
+ }
+ else {
+ // Parse the property
+ @list( $property, $value ) = preg_split('/:/', $line, 2 );
+ if ( strpos( $property, ';' ) > 0 ) {
+ $parameterlist = preg_split('/;/', $property );
+ $property = array_shift($parameterlist);
+ foreach( $parameterlist AS $pk => $pv ) {
+ if ( $pv == "VALUE=DATE" ) {
+ $value .= 'T000000';
+ }
+ elseif ( preg_match('/^([^;:=]+)=([^;:=]+)$/', $pv, $matches) ) {
+ switch( $matches[1] ) {
+ case 'TZID': $properties['TZID'] = $matches[2]; break;
+ default:
+ dbg_error_log( "icalendar", " FYI: Ignoring Resource '%s', Property '%s', Parameter '%s', Value '%s'", $type, $property, $matches[1], $matches[2] );
+ }
+ }
+ }
+ }
+ if ( $this->parsing_vtimezone && (!isset($this->tz_locn) || $this->tz_locn == "") && $property == 'X-LIC-LOCATION' ) {
+ $this->tz_locn = $value;
+ }
+ $properties[strtoupper($property)] = $this->RFC2445ContentUnescape($value);
+ }
+ }
+ return $properties;
+ }
+
+
+ /**
+ * Build the iCalendar object from a text string which is a single iCalendar resource
+ *
+ * @var string The RFC2445 iCalendar resource to be parsed
+ *
+ * @deprecated This function is deprecated and will be removed eventually.
+ * @todo Remove this function.
+ */
+ function BuildFromText( $icalendar ) {
+ dbg_error_log( "LOG", " iCalendar: Call to deprecated method '%s'", 'BuildFromText' );
+ /**
+ * This unescapes the (CRLF + linear space) wrapping specified in RFC2445. According
+ * to RFC2445 we should always end with CRLF but the CalDAV spec says that normalising
+ * XML parsers often muck with it and may remove the CR.
+ */
+ $icalendar = preg_replace('/\r?\n[ \t]/', '', $icalendar );
+
+ $this->lines = preg_split('/\r?\n/', $icalendar );
+
+ $this->_current_parse_line = 0;
+ $this->properties = $this->ParseSomeLines('');
+
+ /**
+ * Our 'type' is the type of non-timezone inside a VCALENDAR
+ */
+ if ( isset($this->properties['VCALENDAR'][0]['INSIDE']) ) {
+ foreach ( $this->properties['VCALENDAR'][0]['INSIDE'] AS $k => $v ) {
+ if ( $v == 'VTIMEZONE' ) continue;
+ $this->type = $v;
+ break;
+ }
+ }
+
+ }
+
+
+ /**
+ * Returns a content string with the RFC2445 escaping removed
+ *
+ * @param string $escaped The incoming string to be escaped.
+ * @return string The string with RFC2445 content escaping removed.
+ *
+ * @deprecated This function is deprecated and will be removed eventually.
+ * @todo Remove this function.
+ */
+ function RFC2445ContentUnescape( $escaped ) {
+ dbg_error_log( "LOG", " iCalendar: Call to deprecated method '%s'", 'RFC2445ContentUnescape' );
+ $unescaped = str_replace( '\\n', "\n", $escaped);
+ $unescaped = str_replace( '\\N', "\n", $unescaped);
+ $unescaped = preg_replace( "/\\\\([,;:\"\\\\])/", '$1', $unescaped);
+ return $unescaped;
+ }
+
+
+
+ /**
+ * Do what must be done with time zones from on file. Attempt to turn
+ * them into something that PostgreSQL can understand...
+ *
+ * @deprecated This function is deprecated and will be removed eventually.
+ * @todo Remove this function.
+ */
+ function DealWithTimeZones() {
+ global $c;
+
+ dbg_error_log( "LOG", " iCalendar: Call to deprecated method '%s'", 'DealWithTimeZones' );
+ $tzid = $this->Get('TZID');
+ if ( isset($c->save_time_zone_defs) && $c->save_time_zone_defs ) {
+ $qry = new PgQuery( "SELECT tz_locn FROM time_zone WHERE tz_id = ?;", $tzid );
+ if ( $qry->Exec('iCalendar') && $qry->rows == 1 ) {
+ $row = $qry->Fetch();
+ $this->tz_locn = $row->tz_locn;
+ }
+ dbg_error_log( "icalendar", " TZCrap2: TZID '%s', DB Rows=%d, Location '%s'", $tzid, $qry->rows, $this->tz_locn );
+ }
+
+ if ( (!isset($this->tz_locn) || $this->tz_locn == '') && $tzid != '' ) {
+ /**
+ * In case there was no X-LIC-LOCATION defined, let's hope there is something in the TZID
+ * that we can use. We are looking for a string like "Pacific/Auckland" if possible.
+ */
+ $tzname = preg_replace('#^(.*[^a-z])?([a-z]+/[a-z]+)$#i','$1',$tzid );
+ /**
+ * Unfortunately this kind of thing will never work well :-(
+ *
+ if ( strstr( $tzname, ' ' ) ) {
+ $words = preg_split('/\s/', $tzname );
+ $tzabbr = '';
+ foreach( $words AS $i => $word ) {
+ $tzabbr .= substr( $word, 0, 1);
+ }
+ $this->tz_locn = $tzabbr;
+ }
+ */
+ if ( preg_match( '#\S+/\S+#', $tzname) ) {
+ $this->tz_locn = $tzname;
+ }
+ dbg_error_log( "icalendar", " TZCrap3: TZID '%s', Location '%s', Perhaps: %s", $tzid, $this->tz_locn, $tzname );
+ }
+
+ if ( $tzid != '' && isset($c->save_time_zone_defs) && $c->save_time_zone_defs && $qry->rows != 1 && isset($this->vtimezone) && $this->vtimezone != "" ) {
+ $qry2 = new PgQuery( "INSERT INTO time_zone (tz_id, tz_locn, tz_spec) VALUES( ?, ?, ? );",
+ $tzid, $this->tz_locn, $this->vtimezone );
+ $qry2->Exec("iCalendar");
+ }
+
+ if ( (!isset($this->tz_locn) || $this->tz_locn == "") && isset($c->local_tzid) ) {
+ $this->tz_locn = $c->local_tzid;
+ }
+ }
+
+
+ /**
+ * Get the value of a property in the first non-VTIMEZONE
+ */
+ function Get( $key ) {
+ if ( strtoupper($key) == 'TZID' ) {
+ // backward compatibility hack
+ dbg_error_log( "icalendar", " Get(TZID): TZID '%s', Location '%s'", (isset($this->tzid)?$this->tzid:"[not set]"), $this->tz_locn );
+ if ( isset($this->tzid) ) return $this->tzid;
+ return $this->tz_locn;
+ }
+ /**
+ * The property we work on is the first non-VTIMEZONE we find.
+ */
+ $component =& $this->component->FirstNonTimezone();
+ if ( $component === false ) return null;
+ return $component->GetPValue(strtoupper($key));
+ }
+
+
+ /**
+ * Set the value of a property
+ */
+ function Set( $key, $value ) {
+ if ( $value == "" ) return;
+ $key = strtoupper($key);
+ $property = new iCalProp();
+ $property->Name($key);
+ $property->Value($value);
+ if (isset($this->component->rendered) ) unset( $this->component->rendered );
+ $component =& $this->component->FirstNonTimezone();
+ $component->SetProperties( array($property), $key);
+ return $this->Get($key);
+ }
+
+
+ /**
+ * Add a new property/value, regardless of whether it exists already
+ *
+ * @param string $key The property key
+ * @param string $value The property value
+ * @param string $parameters Any parameters to set for the property, as an array of key/value pairs
+ */
+ function Add( $key, $value, $parameters = null ) {
+ if ( $value == "" ) return;
+ $key = strtoupper($key);
+ $property = new iCalProp();
+ $property->Name($key);
+ $property->Value($value);
+ if ( isset($parameters) && is_array($parameters) ) {
+ $property->parameters = $parameters;
+ }
+ $component =& $this->component->FirstNonTimezone();
+ $component->AddProperty($property);
+ if (isset($this->component->rendered) ) unset( $this->component->rendered );
+ }
+
+
+ /**
+ * Because I screwed up with the name originally...
+ * @DEPRECATED
+ * todo:: Remove this function after June 2008.
+ */
+ function Put( $key, $value ) {
+ dbg_error_log( "LOG", " iCalendar: Call to deprecated method '%s'", 'Put' );
+ $this->Set($key,$value);
+ }
+
+ /**
+ * Returns a PostgreSQL Date Format string suitable for returning HTTP (RFC2068) dates
+ * Preferred is "Sun, 06 Nov 1994 08:49:37 GMT" so we do that.
+ */
+ function HttpDateFormat() {
+ return "'Dy, DD Mon IYYY HH24:MI:SS \"GMT\"'";
+ }
+
+
+ /**
+ * Returns a PostgreSQL Date Format string suitable for returning iCal dates
+ */
+ function SqlDateFormat() {
+ return "'YYYYMMDD\"T\"HH24MISS'";
+ }
+
+
+ /**
+ * Returns a PostgreSQL Date Format string suitable for returning dates which
+ * have been cast to UTC
+ */
+ function SqlUTCFormat() {
+ return "'YYYYMMDD\"T\"HH24MISS\"Z\"'";
+ }
+
+
+ /**
+ * Returns a PostgreSQL Date Format string suitable for returning iCal durations
+ * - this doesn't work for negative intervals, but events should not have such!
+ */
+ function SqlDurationFormat() {
+ return "'\"PT\"HH24\"H\"MI\"M\"'";
+ }
+
+ /**
+ * Returns a suitably escaped RFC2445 content string.
+ *
+ * @param string $name The incoming name[;param] prefixing the string.
+ * @param string $value The incoming string to be escaped.
+ *
+ * @deprecated This function is deprecated and will be removed eventually.
+ * @todo Remove this function.
+ */
+ function RFC2445ContentEscape( $name, $value ) {
+ dbg_error_log( "LOG", " iCalendar: Call to deprecated method '%s'", 'RFC2445ContentEscape' );
+ $property = preg_replace( '/[;].*$/', '', $name );
+ switch( $property ) {
+ /** Content escaping does not apply to these properties culled from RFC2445 */
+ case 'ATTACH': case 'GEO': case 'PERCENT-COMPLETE': case 'PRIORITY':
+ case 'COMPLETED': case 'DTEND': case 'DUE': case 'DTSTART':
+ case 'DURATION': case 'FREEBUSY': case 'TZOFFSETFROM': case 'TZOFFSETTO':
+ case 'TZURL': case 'ATTENDEE': case 'ORGANIZER': case 'RECURRENCE-ID':
+ case 'URL': case 'EXDATE': case 'EXRULE': case 'RDATE':
+ case 'RRULE': case 'REPEAT': case 'TRIGGER': case 'CREATED':
+ case 'DTSTAMP': case 'LAST-MODIFIED': case 'SEQUENCE':
+ break;
+
+ /** Content escaping applies by default to other properties */
+ default:
+ $value = str_replace( '\\', '\\\\', $value);
+ $value = preg_replace( '/\r?\n/', '\\n', $value);
+ $value = preg_replace( "/([,;:\"])/", '\\\\$1', $value);
+ }
+ $result = wordwrap("$name:$value", 73, " \r\n ", true ) . "\r\n";
+ return $result;
+ }
+
+ /**
+ * Return all sub-components of the given type, which are part of the
+ * component we pass in as an array of lines.
+ *
+ * @param array $component The component to be parsed
+ * @param string $type The type of sub-components to be extracted
+ * @param int $count The number of sub-components to extract (default: 9999)
+ *
+ * @return array The sub-component lines
+ */
+ function ExtractSubComponent( $component, $type, $count=9999 ) {
+ $answer = array();
+ $intags = false;
+ $start = "BEGIN:$type";
+ $finish = "END:$type";
+ dbg_error_log( "iCalendar", ":ExtractSubComponent: Looking for %d subsets of type %s", $count, $type );
+ reset($component);
+ foreach( $component AS $k => $v ) {
+ if ( !$intags && $v == $start ) {
+ $answer[] = $v;
+ $intags = true;
+ }
+ else if ( $intags && $v == $finish ) {
+ $answer[] = $v;
+ $intags = false;
+ }
+ else if ( $intags ) {
+ $answer[] = $v;
+ }
+ }
+ return $answer;
+ }
+
+
+ /**
+ * Extract a particular property from the provided component. In doing so we
+ * assume that the content was unescaped when iCalComponent::ParseFrom()
+ * called iCalComponent::UnwrapComponent().
+ *
+ * @param array $component An array of lines of this component
+ * @param string $type The type of parameter
+ *
+ * @return array An array of iCalProperty objects
+ */
+ function ExtractProperty( $component, $type, $count=9999 ) {
+ $answer = array();
+ dbg_error_log( "iCalendar", ":ExtractProperty: Looking for %d properties of type %s", $count, $type );
+ reset($component);
+ foreach( $component AS $k => $v ) {
+ if ( preg_match( "/$type"."[;:]/i", $v ) ) {
+ $answer[] = new iCalProp($v);
+ dbg_error_log( "iCalendar", ":ExtractProperty: Found property %s", $type );
+ if ( --$count < 1 ) return $answer;
+ }
+ }
+ return $answer;
+ }
+
+
+ /**
+ * Applies the filter conditions, possibly recursively, to the value which will be either
+ * a single property, or an array of lines of the component under test.
+ *
+ * @todo Eventually we need to handle all of these possibilities, which will mean writing
+ * several routines:
+ * - Get Property from Component
+ * - Get Parameter from Property
+ * - Test TimeRange
+ * For the moment we will leave these, until there is a perceived need.
+ *
+ * @param array $filter An array of XMLElement defining the filter(s)
+ * @param mixed $value Either a string which is the single property, or an array of lines, for the component.
+ * @return boolean Whether the filter passed / failed.
+ */
+ function ApplyFilter( $filter, $value ) {
+ foreach( $filter AS $k => $v ) {
+ $tag = $v->GetTag();
+ $value_type = gettype($value);
+ $value_defined = (isset($value) && $value_type == 'string') || ($value_type == 'array' && count($value) > 0 );
+ if ( $tag == 'urn:ietf:params:xml:ns:caldav:is-not-defined' && $value_defined ) {
+ dbg_error_log( "iCalendar", ":ApplyFilter: Value is set ('%s'), want unset, for filter %s", count($value), $tag );
+ return false;
+ }
+ elseif ( $tag == 'urn:ietf:params:xml:ns:caldav:is-defined' && !$value_defined ) {
+ dbg_error_log( "iCalendar", ":ApplyFilter: Want value, but it is not set for filter %s", $tag );
+ return false;
+ }
+ else {
+ switch( $tag ) {
+ case 'urn:ietf:params:xml:ns:caldav:time-range':
+ /** todo:: While this is unimplemented here at present, most time-range tests should occur at the SQL level. */
+ break;
+ case 'urn:ietf:params:xml:ns:caldav:text-match':
+ $search = $v->GetContent();
+ // In this case $value will either be a string, or an array of iCalProp objects
+ // since TEXT-MATCH does not apply to COMPONENT level - only property/parameter
+ if ( gettype($value) != 'string' ) {
+ if ( gettype($value) == 'array' ) {
+ $match = false;
+ foreach( $value AS $k1 => $v1 ) {
+ // $v1 could be an iCalProp object
+ if ( $match = $v1->TextMatch($search)) break;
+ }
+ }
+ else {
+ dbg_error_log( "iCalendar", ":ApplyFilter: TEXT-MATCH will only work on strings or arrays of iCalProp. %s unsupported", gettype($value) );
+ return true; // We return _true_ in this case, so the client sees the item
+ }
+ }
+ else {
+ $match = strstr( $value, $search[0] );
+ }
+ $negate = $v->GetAttribute("negate-condition");
+ if ( isset($negate) && strtolower($negate) == "yes" && $match ) {
+ dbg_error_log( "iCalendar", ":ApplyFilter: TEXT-MATCH of %s'%s' against '%s'", (isset($negate) && strtolower($negate) == "yes"?'!':''), $search, $value );
+ return false;
+ }
+ break;
+ case 'urn:ietf:params:xml:ns:caldav:comp-filter':
+ $subfilter = $v->GetContent();
+ $component = $this->ExtractSubComponent($value,$v->GetAttribute("name"));
+ if ( ! $this->ApplyFilter($subfilter,$component) ) return false;
+ break;
+ case 'urn:ietf:params:xml:ns:caldav:prop-filter':
+ $subfilter = $v->GetContent();
+ $properties = $this->ExtractProperty($value,$v->GetAttribute("name"));
+ if ( ! $this->ApplyFilter($subfilter,$properties) ) return false;
+ break;
+ case 'urn:ietf:params:xml:ns:caldav:param-filter':
+ $subfilter = $v->GetContent();
+ $parameter = $this->ExtractParameter($value,$v->GetAttribute("NAME"));
+ if ( ! $this->ApplyFilter($subfilter,$parameter) ) return false;
+ break;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Test a PROP-FILTER or COMP-FILTER and return a true/false
+ * COMP-FILTER (is-defined | is-not-defined | (time-range?, prop-filter*, comp-filter*))
+ * PROP-FILTER (is-defined | is-not-defined | ((time-range | text-match)?, param-filter*))
+ *
+ * @param array $filter An array of XMLElement defining the filter
+ *
+ * @return boolean Whether or not this iCalendar passes the test
+ */
+ function TestFilter( $filters ) {
+
+ foreach( $filters AS $k => $v ) {
+ $tag = $v->GetTag();
+ $name = $v->GetAttribute("name");
+ $filter = $v->GetContent();
+ if ( $tag == "urn:ietf:params:xml:ns:caldav:prop-filter" ) {
+ $value = $this->ExtractProperty($this->lines,$name);
+ }
+ else {
+ $value = $this->ExtractSubComponent($this->lines,$v->GetAttribute("name"));
+ }
+ if ( count($value) == 0 ) unset($value);
+ if ( ! $this->ApplyFilter($filter,$value) ) return false;
+ }
+ return true;
+ }
+
+ /**
+ * Returns the header we always use at the start of our iCalendar resources
+ *
+ * @deprecated This function is deprecated and will be removed eventually.
+ * @todo Remove this function.
+ */
+ function iCalHeader() {
+ dbg_error_log( "LOG", " iCalendar: Call to deprecated method '%s'", 'iCalHeader' );
+ return <<<EOTXT
+BEGIN:VCALENDAR\r
+PRODID:-//davical.org//NONSGML AWL Calendar//EN\r
+VERSION:2.0\r
+
+EOTXT;
+ }
+
+
+
+ /**
+ * Returns the footer we always use at the finish of our iCalendar resources
+ *
+ * @deprecated This function is deprecated and will be removed eventually.
+ * @todo Remove this function.
+ */
+ function iCalFooter() {
+ dbg_error_log( "LOG", " iCalendar: Call to deprecated method '%s'", 'iCalFooter' );
+ return "END:VCALENDAR\r\n";
+ }
+
+
+ /**
+ * Render the iCalendar object as a text string which is a single VEVENT (or other)
+ *
+ * @param boolean $as_calendar Whether or not to wrap the event in a VCALENDAR
+ * @param string $type The type of iCalendar object (VEVENT, VTODO, VFREEBUSY etc.)
+ * @param array $restrict_properties The names of the properties we want in our rendered result.
+ */
+ function Render( $as_calendar = true, $type = null, $restrict_properties = null ) {
+ if ( $as_calendar ) {
+ return $this->component->Render();
+ }
+ else {
+ $components = $this->component->GetComponents($type);
+ $rendered = "";
+ foreach( $components AS $k => $v ) {
+ $rendered .= $v->Render($restrict_properties);
+ }
+ return $rendered;
+ }
+ }
+
+}
--- /dev/null
+<?php
+/**
+* A Class for connecting to a caldav server
+*
+* @package awl
+* removed curl - now using fsockopen
+* changed 2009 by Andres Obrero - Switzerland andres@obrero.ch
+*
+* @subpackage caldav
+* @author Andrew McMillan <debian@mcmillan.net.nz>
+* @copyright Andrew McMillan
+* @license http://gnu.org/copyleft/gpl.html GNU GPL v2
+*/
+
+
+/**
+* A class for accessing DAViCal via CalDAV, as a client
+*
+* @package awl
+*/
+class CalDAVClient {
+ /**
+ * Server, username, password, calendar
+ *
+ * @var string
+ */
+ var $base_url, $user, $pass, $calendar, $entry, $protocol, $server, $port;
+
+ /**
+ * The useragent which is send to the caldav server
+ *
+ * @var string
+ */
+ var $user_agent = 'DAViCalClient';
+
+ var $headers = array();
+ var $body = "";
+ var $requestMethod = "GET";
+ var $httpRequest = ""; // for debugging http headers sent
+ var $xmlRequest = ""; // for debugging xml sent
+ var $httpResponse = ""; // for debugging http headers received
+ var $xmlResponse = ""; // for debugging xml received
+
+ /**
+ * Constructor, initialises the class
+ *
+ * @param string $base_url The URL for the calendar server
+ * @param string $user The name of the user logging in
+ * @param string $pass The password for that user
+ * @param string $calendar The name of the calendar (not currently used)
+ */
+ function CalDAVClient( $base_url, $user, $pass, $calendar ) {
+ $this->user = $user;
+ $this->pass = $pass;
+ $this->calendar = $calendar;
+ $this->headers = array();
+
+ if ( preg_match( '#^(https?)://([a-z0-9.-]+)(:([0-9]+))?(/.*)$#', $base_url, $matches ) ) {
+ $this->server = $matches[2];
+ $this->base_url = $matches[5];
+ if ( $matches[1] == 'https' ) {
+ $this->protocol = 'ssl';
+ $this->port = 443;
+ }
+ else {
+ $this->protocol = 'tcp';
+ $this->port = 80;
+ }
+ if ( $matches[4] != '' ) {
+ $this->port = intval($matches[4]);
+ }
+ }
+ else {
+ trigger_error("Invalid URL: '".$base_url."'", E_USER_ERROR);
+ }
+ }
+
+ /**
+ * Adds an If-Match or If-None-Match header
+ *
+ * @param bool $match to Match or Not to Match, that is the question!
+ * @param string $etag The etag to match / not match against.
+ */
+ function SetMatch( $match, $etag = '*' ) {
+ $this->headers[] = sprintf( "%s-Match: \"%s\"", ($match ? "If" : "If-None"), $etag);
+ }
+
+ /**
+ * Add a Depth: header. Valid values are 1 or infinity
+ *
+ * @param int $depth The depth, default to infinity
+ */
+ function SetDepth( $depth = 'infinity' ) {
+ $this->headers[] = "Depth: ". ($depth == 1 ? "1" : "infinity" );
+ }
+
+ /**
+ * Add a Depth: header. Valid values are 1 or infinity
+ *
+ * @param int $depth The depth, default to infinity
+ */
+ function SetUserAgent( $user_agent = null ) {
+ if ( !isset($user_agent) ) $user_agent = $this->user_agent;
+ $this->user_agent = $user_agent;
+ }
+
+ /**
+ * Add a Content-type: header.
+ *
+ * @param int $type The content type
+ */
+ function SetContentType( $type ) {
+ $this->headers[] = "Content-type: $type";
+ }
+
+ /**
+ * Split response into httpResponse and xmlResponse
+ *
+ * @param string Response from server
+ */
+ function ParseResponse( $response ) {
+ $pos = strpos($response, '<?xml');
+ if ($pos == false) {
+ $this->httpResponse = trim($response);
+ }
+ else {
+ $this->httpResponse = trim(substr($response, 0, $pos));
+ $this->xmlResponse = trim(substr($response, $pos));
+ }
+ }
+
+ /**
+ * Output http request headers
+ *
+ * @return HTTP headers
+ */
+ function GetHttpRequest() {
+ return $this->httpRequest;
+ }
+ /**
+ * Output http response headers
+ *
+ * @return HTTP headers
+ */
+ function GetHttpResponse() {
+ return $this->httpResponse;
+ }
+ /**
+ * Output xml request
+ *
+ * @return raw xml
+ */
+ function GetXmlRequest() {
+ return $this->xmlRequest;
+ }
+ /**
+ * Output xml response
+ *
+ * @return raw xml
+ */
+ function GetXmlResponse() {
+ return $this->xmlResponse;
+ }
+
+ /**
+ * Send a request to the server
+ *
+ * @param string $relative_url The URL to make the request to, relative to $base_url
+ *
+ * @return string The content of the response from the server
+ */
+ function DoRequest( $relative_url = "" ) {
+ if(!defined("_FSOCK_TIMEOUT")){ define("_FSOCK_TIMEOUT", 10); }
+ $headers = array();
+
+ $headers[] = $this->requestMethod." ". $this->base_url . $relative_url . " HTTP/1.1";
+ $headers[] = "Authorization: Basic ".base64_encode($this->user .":". $this->pass );
+ $headers[] = "Host: ".$this->server .":".$this->port;
+
+ foreach( $this->headers as $ii => $head ) {
+ $headers[] = $head;
+ }
+ $headers[] = "Content-Length: " . strlen($this->body);
+ $headers[] = "User-Agent: " . $this->user_agent;
+ $headers[] = 'Connection: close';
+ $this->httpRequest = join("\r\n",$headers);
+ $this->xmlRequest = $this->body;
+
+ $fip = fsockopen( $this->protocol . '://' . $this->server, $this->port, $errno, $errstr, _FSOCK_TIMEOUT); //error handling?
+ if ( !(get_resource_type($fip) == 'stream') ) return false;
+ if ( !fwrite($fip, $this->httpRequest."\r\n\r\n".$this->body) ) { fclose($fip); return false; }
+ $rsp = "";
+ while( !feof($fip) ) { $rsp .= fgets($fip,8192); }
+ fclose($fip);
+
+ $this->headers = array(); // reset the headers array for our next request
+ $this->ParseResponse($rsp);
+ return $rsp;
+ }
+
+
+ /**
+ * Send an OPTIONS request to the server
+ *
+ * @param string $relative_url The URL to make the request to, relative to $base_url
+ *
+ * @return array The allowed options
+ */
+ function DoOptionsRequest( $relative_url = "" ) {
+ $this->requestMethod = "OPTIONS";
+ $this->body = "";
+ $headers = $this->DoRequest($relative_url);
+ $options_header = preg_replace( '/^.*Allow: ([a-z, ]+)\r?\n.*/is', '$1', $headers );
+ $options = array_flip( preg_split( '/[, ]+/', $options_header ));
+ return $options;
+ }
+
+
+
+ /**
+ * Send an XML request to the server (e.g. PROPFIND, REPORT, MKCALENDAR)
+ *
+ * @param string $method The method (PROPFIND, REPORT, etc) to use with the request
+ * @param string $xml The XML to send along with the request
+ * @param string $relative_url The URL to make the request to, relative to $base_url
+ *
+ * @return array An array of the allowed methods
+ */
+ function DoXMLRequest( $request_method, $xml, $relative_url = '' ) {
+ $this->body = $xml;
+ $this->requestMethod = $request_method;
+ $this->SetContentType("text/xml");
+ return $this->DoRequest($relative_url);
+ }
+
+
+
+ /**
+ * Get a single item from the server.
+ *
+ * @param string $relative_url The part of the URL after the calendar
+ */
+ function DoGETRequest( $relative_url ) {
+ $this->body = "";
+ $this->requestMethod = "GET";
+ return $this->DoRequest( $relative_url );
+ }
+
+ /**
+ * PUT a text/icalendar resource, returning the etag
+ *
+ * @param string $relative_url The URL to make the request to, relative to $base_url
+ * @param string $icalendar The iCalendar resource to send to the server
+ * @param string $etag The etag of an existing resource to be overwritten, or '*' for a new resource.
+ *
+ * @return string The content of the response from the server
+ */
+ function DoPUTRequest( $relative_url, $icalendar, $etag = null ) {
+ $this->body = $icalendar;
+
+ $this->requestMethod = "PUT";
+ if ( $etag != null ) {
+ $this->SetMatch( ($etag != '*'), $etag );
+ }
+ $this->SetContentType("text/calendar");
+ $headers = $this->DoRequest($relative_url);
+
+ /**
+ * RSCDS will always return the real etag on PUT. Other CalDAV servers may need
+ * more work, but we are assuming we are running against RSCDS in this case.
+ */
+ preg_match('/^HTTP\/1\.[01]+\s+(\d+)\s+/i', $headers, $match);
+ if ($match) {
+ //print htmlentities($this->GetXmlResponse())."<br/>";
+ $xml = simplexml_load_string($this->GetXmlResponse());
+ $xml->registerXPathNamespace('e', 'DAV:');
+ $elems = $xml->xpath('//e:error');
+ $error = $elems[0];
+ switch ($match[1]) {
+ case 412:
+ //echo "$error<br/>";
+ preg_match('/^"?[^"]+"+([0-9a-zA-Z]+)"+.*"+([0-9a-zA-Z]+)"+/', $error, $m);
+ //print_r($m);
+ if ($m) {
+ if (strcasecmp($m[1], $m[2]) !== 0) {
+ $error = "Remote changes discovered.\n";
+ $error .= "Enter changes again after reload\n";
+ }
+ }
+ $etag = array($match[1] => "$error");
+ //print_r($etag);
+ break;
+ default: break;
+ }
+ }
+ else
+ $etag = preg_replace( '/^.*Etag: "?([^"\r\n]+)"?\r?\n.*/is', '$1', $headers );
+ return $etag;
+ }
+
+
+ /**
+ * DELETE a text/icalendar resource
+ *
+ * @param string $relative_url The URL to make the request to, relative to $base_url
+ * @param string $etag The etag of an existing resource to be deleted, or '*' for any resource at that URL.
+ *
+ * @return int The HTTP Result Code for the DELETE
+ */
+ function DoDELETERequest( $relative_url, $etag = null ) {
+ $this->body = "";
+
+ $this->requestMethod = "DELETE";
+ if ( $etag != null ) {
+ $this->SetMatch( true, $etag );
+ }
+ $this->DoRequest($relative_url);
+ return $this->resultcode;
+ }
+
+
+ /**
+ * Given XML for a calendar query, return an array of the events (/todos) in the
+ * response. Each event in the array will have a 'href', 'etag' and '$response_type'
+ * part, where the 'href' is relative to the calendar and the '$response_type' contains the
+ * definition of the calendar data in iCalendar format.
+ *
+ * @param string $filter XML fragment which is the <filter> element of a calendar-query
+ * @param string $relative_url The URL relative to the base_url specified when the calendar was opened. Default ''.
+ * @param string $report_type Used as a name for the array element containing the calendar data. @deprecated
+ *
+ * @return array An array of the relative URLs, etags, and events from the server. Each element of the array will
+ * be an array with 'href', 'etag' and 'data' elements, corresponding to the URL, the server-supplied
+ * etag (which only varies when the data changes) and the calendar data in iCalendar format.
+ */
+ function DoCalendarQuery( $filter, $relative_url = '' ) {
+
+ $xml = <<<EOXML
+<?xml version="1.0" encoding="utf-8" ?>
+<C:calendar-query xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav">
+ <D:prop>
+ <C:calendar-data/>
+ <D:getetag/>
+ </D:prop>
+$filter
+</C:calendar-query>
+EOXML;
+
+ $this->DoXMLRequest( 'REPORT', $xml, $relative_url );
+ $xml_parser = xml_parser_create_ns('UTF-8');
+ $this->xml_tags = array();
+ xml_parser_set_option ( $xml_parser, XML_OPTION_SKIP_WHITE, 1 );
+ xml_parse_into_struct( $xml_parser, $this->xmlResponse, $this->xml_tags );
+ xml_parser_free($xml_parser);
+
+ $report = array();
+ foreach( $this->xml_tags as $k => $v ) {
+ switch( $v['tag'] ) {
+ case 'DAV::RESPONSE':
+ if ( $v['type'] == 'open' ) {
+ $response = array();
+ }
+ elseif ( $v['type'] == 'close' ) {
+ $report[] = $response;
+ }
+ break;
+ case 'DAV::HREF':
+ $response['href'] = basename( $v['value'] );
+ break;
+ case 'DAV::GETETAG':
+ $response['etag'] = preg_replace('/^"?([^"]+)"?/', '$1', $v['value']);
+ break;
+ case 'URN:IETF:PARAMS:XML:NS:CALDAV:CALENDAR-DATA':
+ $response['data'] = $v['value'];
+ break;
+ }
+ }
+ return $report;
+ }
+
+
+ /**
+ * Get the events in a range from $start to $finish. The dates should be in the
+ * format yyyymmddThhmmssZ and should be in GMT. The events are returned as an
+ * array of event arrays. Each event array will have a 'href', 'etag' and 'event'
+ * part, where the 'href' is relative to the calendar and the event contains the
+ * definition of the event in iCalendar format.
+ *
+ * @param timestamp $start The start time for the period
+ * @param timestamp $finish The finish time for the period
+ * @param string $relative_url The URL relative to the base_url specified when the calendar was opened. Default ''.
+ *
+ * @return array An array of the relative URLs, etags, and events, returned from DoCalendarQuery() @see DoCalendarQuery()
+ */
+ function GetEvents( $start = null, $finish = null, $relative_url = '' ) {
+ $filter = "";
+ if ( isset($start) && isset($finish) )
+ $range = "<C:time-range start=\"$start\" end=\"$finish\"/>";
+ else
+ $range = '';
+
+ $filter = <<<EOFILTER
+ <C:filter>
+ <C:comp-filter name="VCALENDAR">
+ <C:comp-filter name="VEVENT">
+ $range
+ </C:comp-filter>
+ </C:comp-filter>
+ </C:filter>
+EOFILTER;
+
+ return $this->DoCalendarQuery($filter, $relative_url);
+ }
+
+
+ /**
+ * Get the todo's in a range from $start to $finish. The dates should be in the
+ * format yyyymmddThhmmssZ and should be in GMT. The events are returned as an
+ * array of event arrays. Each event array will have a 'href', 'etag' and 'event'
+ * part, where the 'href' is relative to the calendar and the event contains the
+ * definition of the event in iCalendar format.
+ *
+ * @param timestamp $start The start time for the period
+ * @param timestamp $finish The finish time for the period
+ * @param boolean $completed Whether to include completed tasks
+ * @param boolean $cancelled Whether to include cancelled tasks
+ * @param string $relative_url The URL relative to the base_url specified when the calendar was opened. Default ''.
+ *
+ * @return array An array of the relative URLs, etags, and events, returned from DoCalendarQuery() @see DoCalendarQuery()
+ */
+ function GetTodos( $start, $finish, $completed = false, $cancelled = false, $relative_url = "" ) {
+
+ if ( $start && $finish ) {
+$time_range = <<<EOTIME
+ <C:time-range start="$start" end="$finish"/>
+EOTIME;
+ }
+
+ // Warning! May contain traces of double negatives...
+ $neg_cancelled = ( $cancelled === true ? "no" : "yes" );
+ $neg_completed = ( $cancelled === true ? "no" : "yes" );
+
+ $filter = <<<EOFILTER
+ <C:filter>
+ <C:comp-filter name="VCALENDAR">
+ <C:comp-filter name="VTODO">
+ <C:prop-filter name="STATUS">
+ <C:text-match negate-condition="$neg_completed">COMPLETED</C:text-match>
+ </C:prop-filter>
+ <C:prop-filter name="STATUS">
+ <C:text-match negate-condition="$neg_cancelled">CANCELLED</C:text-match>
+ </C:prop-filter>$time_range
+ </C:comp-filter>
+ </C:comp-filter>
+ </C:filter>
+EOFILTER;
+
+ return $this->DoCalendarQuery($filter, $relative_url);
+ }
+
+
+ /**
+ * Get the calendar entry by UID
+ *
+ * @param uid
+ * @param string $relative_url The URL relative to the base_url specified when the calendar was opened. Default ''.
+ *
+ * @return array An array of the relative URL, etag, and calendar data returned from DoCalendarQuery() @see DoCalendarQuery()
+ */
+ function GetEntryByUid( $uid, $relative_url = '' ) {
+ $filter = "";
+ if ( $uid ) {
+ $filter = <<<EOFILTER
+ <C:filter>
+ <C:comp-filter name="VCALENDAR">
+ <C:comp-filter name="VEVENT">
+ <C:prop-filter name="UID">
+ <C:text-match icollation="i;octet">$uid</C:text-match>
+ </C:prop-filter>
+ </C:comp-filter>
+ </C:comp-filter>
+ </C:filter>
+EOFILTER;
+ }
+
+ return $this->DoCalendarQuery($filter, $relative_url);
+ }
+
+
+ /**
+ * Get the calendar entry by HREF
+ *
+ * @param string $href The href from a call to GetEvents or GetTodos etc.
+ * @param string $relative_url The URL relative to the base_url specified when the calendar was opened. Default ''.
+ *
+ * @return string The iCalendar of the calendar entry
+ */
+ function GetEntryByHref( $href, $relative_url = '' ) {
+ return $this->DoGETRequest( $relative_url . $href );
+ }
+
+}
+
+//$cal = new CalDAVClient( "https://www.google.com/calendar/dav/[mail id]/events/", "uid", "pwd", "calendar" );
+//$cal = new CalDAVClient( "http://calendar.datanom.net/caldav.php/[uid]/home", "uid", "pwd", "calendar" );
+//$cal->SetDepth(1);
+/*$folder_xml = $cal->DoXMLRequest("PROPFIND",
+'<?xml version="1.0" encoding="utf-8" ?>
+ <propfind xmlns="DAV:">
+ <prop>
+ <getcontentlength/>
+ <getcontenttype/>
+ <resourcetype/>
+ <getetag/>
+ </prop>
+</propfind>' );*/
+//print_r($folder_xml);
+
+
+/*$events = $cal->GetEvents("20100616T000000Z", "20100616T235959Z");
+foreach ( $events AS $k => $event ) {
+ print_r( $event['data'] );
+}*/
+
+
+/*
+print "Debug information\n";
+print "Headers sent:\n".$cal->GetHttpRequest()."\n".
+ "XML sent:\n".$cal->GetXmlRequest()."\n".
+ "Headers received:\n".$cal->GetHttpResponse()."\n".
+ "XML received:\n".$cal->GetXmlResponse()."\n";
+ */
\ No newline at end of file
--- /dev/null
+<?php
+
+/* $Id$ */
+ final class VTYPE {
+ const VEVENT = 1;
+ const VTODO = 2;
+ const VJOURNAL = 3;
+ const VFREEBUSY = 4;
+ const VTIMEZONE = 5;
+ const VALARM = 6;
+ private $value;
+
+ public function __construct($value) {
+ switch ($value) {
+ case 'VEVENT': $this->value = self::VEVENT; break;
+ case 'VTODO': $this->value = self::VTODO; break;
+ case 'VJOURNAL': $this->value = self::VJOURNAL; break;
+ case 'VFREEBUSY': $this->value = self::VFREEBUSY; break;
+ case 'VTIMEZONE': $this->value = self::VTIMEZONE; break;
+ case 'VALARM': $this->value = self::VALARM; break;
+ case self::VEVENT:
+ case self::VTODO:
+ case self::VJOURNAL:
+ case self::VFREEBUSY:
+ case self::VTIMEZONE:
+ case self::VALARM: $this->value = $value; break;
+ default: throw new Exception ("$value: Invalid VTYPE");
+ }
+ }
+
+ private function __clone() {}
+
+ public function ordinal() {
+ return $this->value;
+ }
+
+ public function __toString() {
+ switch ($this->value) {
+ case self::VEVENT: return 'VEVENT'; break;
+ case self::VTODO: return 'VTODO'; break;
+ case self::VJOURNAL: return 'VJOURNAL'; break;
+ case self::VFREEBUSY: return 'VFREEBUSY'; break;
+ case self::VTIMEZONE: return 'VTIMEZONE'; break;
+ case self::VALARM: return 'VALARM'; break;
+ }
+ }
+
+ }
+
+ abstract class CaldavRessource
+ implements ArrayAccess, IteratorAggregate {
+
+ private $client;
+
+ function __construct($url, $uid = '', $pwd = '', $cal = '') {
+ if (empty($url))
+ throw new Exception("Missing URL");
+ $this->client = new CalDAVClient($url, $uid, $pwd, $cal);
+ }
+
+ /**
+ * abstract functions to be implemented by sub classes
+ */
+ abstract function update($url, $etag = NULL);
+ abstract function newComponent($c_type);
+ abstract function getComponents($start, $end);
+ abstract function delete($url, $etag = NULL);
+
+ protected function callServer($method, $param = array()) {
+ $error = TRUE;
+ $msg = "Unknown error";
+
+ if (! is_array($param))
+ throw new Exception("Parameters must be inclosed in an array");
+ switch (strtolower($method)) {
+ case 'getevents':
+ if (count($param) != 2) {
+ $error = TRUE;
+ $msg = "Expected 2 parameters";
+ break;
+ }
+ if ($this->isDateTime($param[0]) &&
+ $this->isDateTime($param[1])) {
+ $res = $this->client->GetEvents($param[0], $param[1]);
+ $error = FALSE;
+ }
+ else {
+ $msg = "[${param[0]},${param[1]}]: Invalid DateTime";
+ $error = TRUE;
+ }
+ break;
+ case 'getbyuid':
+ if (count($param) != 1) {
+ $error = TRUE;
+ $msg = "Expected 1 parameter";
+ break;
+ }
+ $res = $this->client->GetEntryByUid($param[0]);
+ $error = FALSE;
+ break;
+ case 'put':
+ if (count($param) < 2 || count($param) > 3) {
+ $error = TRUE;
+ $msg = "Syntax: URL, CalDAV_resource[, ETag]";
+ break;
+ }
+ if (count($param) == 2)
+ $res = $this->client->DoPUTRequest($param[0], $param[1]);
+ else
+ $res = $this->client->DoPUTRequest($param[0], $param[1], $param[2]);
+ $error = FALSE;
+ break;
+ case 'delete':
+ if (count($param) < 1 || count($param) > 2) {
+ $error = TRUE;
+ $msg = "Syntax: URL[, ETag]";
+ break;
+ }
+ if (count($param) == 1)
+ $res = $this->client->DoDELETERequest($param[0]);
+ else
+ $res = $this->client->DoDELETERequest($param[0], $param[1]);
+ $error = FALSE;
+ break;
+ default:
+ throw new Exception("$method: Unknown method");
+ }
+ if ($error)
+ throw new Exception($msg);
+ else
+ return $res;
+ }
+
+ static function isDateTime($var) {
+ return (preg_match("/^([0-9]{8})T([0-9]{6})Z?$/", $var) > 0);
+ }
+
+ /**
+ * Returned date-time will always be in UTC
+ */
+ static function timestamp2ICal($ts, $localtime = TRUE) {
+ $ts = (int) $ts;
+ if ($ts < 0)
+ throw new Exception("$ts: invalid timestamp");
+ if ($localtime) {
+ $date = date('Ymd', $ts);
+ $time = date('His', $ts);
+ $res = sprintf("%sT%s", $date, $time);
+ }
+ else {
+ $date = gmdate('Ymd', $ts);
+ $time = gmdate('His', $ts);
+ $res = sprintf("%sT%sZ", $date, $time);
+ }
+ return $res;
+ }
+
+ static function iCal2Timestamp($ical) {
+ if (! self::isDateTime($ical)) {
+ // test for badly formed all-day event
+ //print "$ical";
+ $res = preg_match("/^([0-9]{4})([0-9]{2})([0-9]{2})$/",
+ $ical, $parts);
+ if ($res == 0)
+ throw new Exception("$ical: invalid CalDAV Date-Time");
+ else {
+ $timepart = array('00', '00', '00');
+ $parts = array_merge($parts, $timepart);
+ }
+ }
+ else {
+ $date = "([0-9]{4})([0-9]{2})([0-9]{2})";
+ $time = "([0-9]{2})([0-9]{2})([0-9]{2})";
+ preg_match("/^${date}T${time}(Z?)$/", $ical, $parts);
+ }
+ if (count($parts) == 8 && ! empty($parts[7]))
+ return gmmktime($parts[4], $parts[5], $parts[6],
+ $parts[2], $parts[3], $parts[1]);
+ else
+ return mktime($parts[4], $parts[5], $parts[6],
+ $parts[2], $parts[3], $parts[1]);
+ }
+
+ private static function down_hour($date) {
+ //print "$date<br/>";
+ if (! self::isDateTime($date)) {
+ // test for badly formed all-day event
+ $res = preg_match("/^([0-9]{4})([0-9]{2})([0-9]{2})$/",
+ $date, $parts);
+ if ($res == 0)
+ throw new Exception("$date: invalid CalDAV Date-Time");
+ else {
+ array_shift($parts);
+ $timepart = array('T', '00', '00', '00');
+ $parts = array_merge($parts, $timepart);
+ return implode('', $parts);
+ }
+ }
+ else {
+ $a = explode('T', $date);
+ $a[1] = substr_replace($a[1], '0000', 2);
+ return $a[0].'T'.$a[1];
+ }
+ }
+
+ static function fix_allday_event(&$date_a, &$date_b) {
+ //print "$date_a : $date_b<br/>";
+ if ($date_a == $date_b) {
+ if (! self::isDateTime($date_a) && ! self::isDateTime($date_b)) {
+ $res1 = preg_match("/^([0-9]{4})([0-9]{2})([0-9]{2})$/",
+ $date_a);
+ $res2 = preg_match("/^([0-9]{4})([0-9]{2})([0-9]{2})$/",
+ $date_b);
+ if ($res1 == 0 || $res2 == 0)
+ throw new Exception("$date_a, $date_b: invalid CalDAV Date-Time");
+ else {
+ $date_a .= "T000000";
+ $date_b .= "T235959";
+ }
+ }
+ else {
+ preg_match("/^([0-9]{4}[0-9]{2}[0-9]{2})T([0-9]{6})$/",
+ $date_a, $part_a);
+ preg_match("/^([0-9]{4}[0-9]{2}[0-9]{2})T([0-9]{6})$/",
+ $date_b, $part_b);
+ $date_a = $part_a[1]."T000000";
+ $date_b = $part_b[1]."T235959";
+ //print "$date_a : $date_b<br/>";
+ }
+ //print "$date_a : $date_b<br/>";
+ }
+ }
+
+ static function datecmp($date_a, $date_b) {
+ $date_a = self::iCal2Timestamp($date_a);
+ $date_b = self::iCal2Timestamp(self::down_hour($date_b));
+ if ($date_a < $date_b)
+ $res = -1;
+ else if ($date_a > $date_b)
+ $res = 1;
+ else
+ $res = 0;
+ return $res;
+ }
+
+ private static function intcmpstr($a_str, $b_str) {
+ $a = (int) $a_str;
+ $b = (int) $b_str;
+ //print "$a:$b<br/>";
+ if ($a > $b)
+ return 1;
+ else if ($a < $b)
+ return -1;
+ else
+ return 0;
+ }
+
+ static function cmpdate($date_a, $date_b) {
+ $datepart = explode('T', $date_a);
+ $d_a = $datepart[0];
+ $datepart = explode('T', $date_b);
+ $d_b = $datepart[0];
+ $y_cmp = self::intcmpstr(substr($d_a, 0, 4), substr($d_b, 0, 4));
+ if ($y_cmp == 0) {
+ $m_cmp = self::intcmpstr(substr($d_a, 4, 2), substr($d_b, 4, 2));
+ if ($m_cmp == 0) {
+ return self::intcmpstr(substr($d_a, 6, 2), substr($d_b, 6, 2));
+ }
+ return $m_cmp;
+ }
+ return $y_cmp;
+ }
+
+ static function cmptime($time_a, $time_b) {
+ $timepart = explode('T', $time_a);
+ $t_a = $timepart[1];
+ $timepart = explode('T', $time_b);
+ $t_b = $timepart[1];
+ //print "$t_a:$t_b<br/>";
+ $h_cmp = self::intcmpstr(substr($t_a, 0, 2), substr($t_b, 0, 2));
+ if ($h_cmp == 0) {
+ $m_cmp = self::intcmpstr(substr($t_a, 2, 2), substr($t_b, 2, 2));
+ if ($m_cmp == 0) {
+ return self::intcmpstr(substr($t_a, 4, 2), substr($t_b, 4, 2));
+ }
+ return $m_cmp;
+ }
+ return $h_cmp;
+ }
+
+ static function allDayEvent($time_a, $time_b) {
+ //echo $time_a.':'.$time_b.'<br/>';
+ $a = explode('T', $time_a);
+ if (count($a) < 2)
+ array_push($a, '0000');
+ $b = explode('T', $time_b);
+ if (count($b) < 2)
+ array_push($b, '0000');
+ $t = strtotime($time_b) - 3600;
+ $t = date("Ymd\THm", $t);
+ return (self::cmpdate($time_a, $t) == 0 &&
+ $a[1] == '0000' && $b[1] == '0000');
+ }
+ }
--- /dev/null
+<?php
+/* $Id$ */
+
+ require_once 'caldav-client.php';
+ require_once 'awl/iCalendar.php';
+ require_once 'caldavresource.class.php';
+ require_once 'rruleparser.class.php';
+ require_once 'vevent.class.php';
+ require_once 'icomponent.class.php';
+
+ class CalendarIterator implements Iterator {
+ private $list;
+
+ function __construct(array $list) {
+ $this->list = $list;
+ }
+
+ function current() {
+ return current($this->list);
+ }
+
+ function next() {
+ next($this->list);
+ }
+
+ function key() {
+ return key($this->list);
+ }
+
+ function rewind() {
+ reset($this->list);
+ }
+
+ function valid() {
+ $obj = current($this->list);
+ return ($obj !== FALSE);
+ }
+
+ }
+
+ class Calendar extends CaldavRessource {
+
+ private $calendar;
+
+ function __construct($url, $uid = '', $pwd = '', $cal = '') {
+ //file_put_contents('/tmp/dump', "$url\n$uid\n$pwd\n$cal\n", FILE_APPEND);
+ if (empty($url))
+ throw new Exception("Missing URL");
+ parent::__construct($url, $uid, $pwd, $cal);
+ }
+
+ private function setComponent(VTYPE $type, array $item, $new = FALSE) {
+ switch ($type) {
+ case VTYPE::VEVENT:
+ $ical = new VEvent(
+ $item['etag'], $item['href'],
+ $type, $item['ical'], $new);
+ break;
+ default:
+ throw new Exception(
+ "$thisType: Unsupported iCalendar component");
+ }
+ $this->calendar[$item['etag']] = $ical;
+ //var_dump($this->calendar[$item['etag']]);
+ //print "-------------------------------<br/>";
+ }
+
+ private function setResource($etag, $resource) {
+ if ($resource === NULL)
+ unset($this->calendar[$etag]);
+ else if (isset($this->calendar[$etag]))
+ $this->calendar[$etag]->setResource($resource);
+ else {
+ $type = new VTYPE($this->getType($resource));
+ $this->setComponent($type, array(
+ 'etag' => $etag,
+ 'href' => NULL,
+ 'ical' => $resource),
+ TRUE
+ );
+ }
+ }
+
+ private function getType(iCalendar $iCalendar) {
+ $components = $iCalendar->component->GetComponents();
+ // Find VCalender component
+ foreach($components as $type) {
+ try {
+ $vtype = new VTYPE($type->GetType());
+ if ($vtype->ordinal() != VTYPE::VTIMEZONE)
+ break;
+ }
+ catch (Exception $ex) {}
+ }
+ return $vtype;
+ }
+
+ private function wrapCalendar($component) {
+ $cal = "BEGIN:VCALENDAR\r\n";
+ $cal .= "PRODID:-//datanom.net//NONSGML WEBCAL Calendar//EN\r\n";
+ $cal .= "VERSION:2.0\r\n";
+ $cal .= "CALSCALE:GREGORIAN\r\n";
+ $cal .= $component;
+ $cal .= "END:VCALENDAR\r\n";
+
+ return $cal;
+ }
+
+ function getComponents($start, $end) {
+ $this->calendar = array();
+
+ if (! $this->isDateTime($start) || ! $this->isDateTime($end))
+ throw new Exception("[$start:$end]: Invalid DateTime format");
+ //print "$start:$end<br/>";
+ //file_put_contents('/tmp/dump', "$start, $end\n", FILE_APPEND);
+ $events = $this->callServer('getEvents', array($start, $end));
+ //var_export($events, FALSE);
+ //file_put_contents('/tmp/dump', var_export($events, TRUE), FILE_APPEND);
+ foreach ($events as $k => $event) {
+ $iCalendar = new iCalendar(
+ array('icalendar' => $event['data']));
+ $vtype = $this->getType($iCalendar);
+ $this->setComponent($vtype, array(
+ 'etag' => $event['etag'],
+ 'href' => $event['href'],
+ 'ical' => $iCalendar
+ )
+ );
+ }
+ }
+
+ function newComponent($c_type) {
+ switch (strtoupper($c_type)) {
+ case 'VEVENT': $type = 'VEVENT'; break;
+ default:
+ throw new Exception(
+ "$thisType: Unsupported iCalendar component");
+ }
+ $start = gmdate("Ymd\THm\Z");
+ $end = strtotime($start) + (60*60);
+ $end = gmdate("Ymd\THm\Z", $end);
+ //echo "$start:$end<br/>";
+ $uid = sha1(microtime() . $start . $end);
+ $iCalendar = new iCalendar(array(
+ 'type' => $type,
+ 'DTSTART' => $start,
+ 'DTEND' => $end,
+ 'UID' => $uid
+ )
+ );
+ $vtype = $this->getType($iCalendar);
+ $etag = sha1("This is a new component");
+ $this->setComponent($vtype, array(
+ 'etag' => $etag,
+ 'href' => NULL,
+ 'ical' => $iCalendar
+ )
+ );
+ return $this->calendar[$etag];
+ }
+/*
+ function reload($start, $end) {
+ $res = $this->update();
+ if (count($res) < 1) {
+ $this->getComponents($start, $end);
+ }
+ return $res;
+ }
+*/
+ private function updateEvent($url, $etag) {
+ $res = array();
+ $resource = $this->calendar[$etag];
+ if ($resource && $resource->isDirty()) {
+ // update (call put)
+ $component = $resource->getBaseComponent();
+ //print "$etag: update\n";
+ $uid = $component->GetPValue('UID');
+ $ical = $this->wrapCalendar($component->Render());
+ //echo "$uid<br/>".nl2br($ical)."$etag<br/>";
+ $url = $resource->getUrl();
+ if ($url) {
+ $newEtag = $this->callServer('put',
+ array("$uid.ics", $ical, $etag));
+ }
+ else {
+ $newEtag = $this->callServer('put',
+ array("$uid.ics", $ical));
+ }
+ if (is_array($newEtag))
+ array_push($res, $newEtag);
+ else {
+ $resource->setEtag($newEtag);
+ }
+ }
+ return $res;
+ }
+
+ function update($url, $etag = NULL) {
+ //var_dump($this->calendar);
+ if (! $etag) {
+ foreach($this->calendar as $id => $resource) {
+ //var_dump($resource);
+ $thisUrl = $resource->getUrl();
+ if ($thisUrl && strcasecmp($url, $thisUrl) == 0) {
+ $etag = $id;
+ break;
+ }
+ }
+ }
+ if ($etag)
+ $res = $this->updateEvent($url, $etag);
+ else
+ $res = array($url => 'Event does not exist');
+ return $res;
+ }
+
+ function delete($url, $etag = NULL) {
+ if ($etag) {
+ $res = $this->callServer('delete', array($url, $etag));
+ }
+ else {
+ $res = $this->callServer('delete', array($url));
+ }
+ return $res;
+ }
+
+ // inherited abstract methods from parent
+ function offsetExists($etag) {
+ return (is_object($this->calendar[$etag]) &&
+ $this->calendar[$etag] instanceof IComponent);
+ }
+
+ function offsetGet($etag) {
+ if ($this->offsetExists($etag))
+ return $this->calendar[$etag]->getResource();
+ }
+
+ function offsetSet($etag, $ical) {
+ $this->setResource($etag, $ical);
+ }
+
+ function offsetUnset($etag) {
+ $this->setResource($etag, NULL);
+ }
+
+ function getIterator() {
+ return new CalendarIterator($this->calendar);
+ }
+
+ }
+/*
+$cal = new Calendar(
+ 'http://calendar.datanom.net/caldav.php/mir/home/',
+ 'uid',
+ 'pwd'
+);
+$cal->getComponents("20030830T000000Z","20031201T000000Z");
+//print_r($cal);
+$i = 0;
+foreach($cal as $obj) {
+ $i++;
+ print "========= [$i] =========\n";
+ //print_r($obj);
+ //print_r ($obj->getAlarm());
+ print_r($obj->getActiveDates("20031014T000000Z","20031114T000000Z"));
+ //print "{$obj->isUTCTime()}\n";
+ //$obj->getActiveDates();
+}
+print "Found $i event(s)\n";
+
+//print_r ($cal->getUrlByEtag($cal->getEtagFromUid('KOrganizer-1670268771.406')));
+$time = time();
+print "time: $time\n";
+$dt = $cal->timestamp2ICal($time, TRUE);
+print "dt: $dt\n";
+$time = $cal->iCal2Timestamp($dt);
+print "time: $time\n";
+$dt = $cal->timestamp2ICal($time, FALSE);
+print "dt: $dt\n";
+$time = $cal->iCal2Timestamp(substr($dt, 0, strpos($dt, 'T')));
+$dt = $cal->timestamp2ICal($time, TRUE);
+print "dt: $dt\n";
+$r = new RRuleParser(
+ 'FREQ=HOURLY;INTERVAL=3;UNTIL=20070101T170000Z',
+ '20070101T090000Z', '20070101T090000Z');
+$r = new RRuleParser(
+ 'FREQ=WEEKLY;COUNT=12;INTERVAL=2',
+ '20070101T140000Z', '20070101T120000Z');
+print "$r\n";
+print_r($r->getEventDates('20070301T140000Z','20070501T140000Z'));
+$r = new RRuleParser(
+ 'FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1',
+ '20070101T000100Z', '20070101T001100Z');
+//DTSTART;TZID=US-Eastern:19970105T083000
+print "$r\n";
+$r = new RRuleParser(
+ 'FREQ=YEARLY;INTERVAL=2;BYMONTH=1;BYDAY=SU;BYHOUR=8,9;BYMINUTE=30',
+ '20070101T000100Z', '20070101T001100Z');
+print "$r\n";
+print_r ($r->getEventDates('20060101T000100Z', '20060101T001100Z'));
+$r = new RRuleParser(
+ 'FREQ=DAILY;COUNT=10;INTERVAL=2',
+ '20070101T000100Z', '20070101T001100Z');
+print "$r\n";
+//foreach ($cal as $obj)
+// var_dump($obj->getBaseComponent());
+//$bak = $cal['3ba46312e910765bf7059a53909d149b'];
+//print_r($bak);
+//print_r(new Icalendar(array('SUMMARY' => 'test')));
+//$cal['3ba46312e910765bf7059a53909d149b'] = new Icalendar(array('SUMMARY' => 'test'));
+//print_r($cal['3ba46312e910765bf7059a53909d149b']);
+//unset($cal['3ba46312e910765bf7059a53909d149b']);
+//var_dump($cal['3ba46312e910765bf7059a53909d149b']);
+//$cal['3ba46312e910765bf7059a53909d149b'] = $bak;
+//var_dump($cal['3ba46312e910765bf7059a53909d149b']);
+//$cal->update();
+//print_r($cal['3ba46312e910765bf7059a53909d149b']);*/
--- /dev/null
+<?php
+/* $Id$ */
+
+$msg = <<<EOF
+BEGIN:VCALENDAR
+PRODID:-//davical.org//NONSGML AWL Calendar//EN
+VERSION:2.0
+CALSCALE:GREGORIAN
+BEGIN:VEVENT
+DTSTAMP:20070417T195323Z
+ORGANIZER:MAILTO:
+X-PILOTID:12451851
+X-PILOTSTAT:0
+CREATED:20050814T160951Z
+UID:libkcal-1123041440.757
+SEQUENCE:0
+LAST-MODIFIED:20070124T213448Z
+SUMMARY:møde carl christian\, hovedopgave
+CLASS:PUBLIC
+PRIORITY:3
+RRULE:FREQ=DAILY;UNTIL=20020528T153000Z;INTERVAL=14
+EXDATE;VALUE=DATE:20020402
+DTSTART:20020219T163000Z
+DTEND:20020219T180000Z
+TRANSP:OPAQUE
+BEGIN:VALARM
+DESCRIPTION:
+ACTION:DISPLAY
+TRIGGER;VALUE=DURATION:-P1D
+END:VALARM
+END:VEVENT
+END:VCALENDAR
+BEGIN:VCALENDAR
+PRODID:-//davical.org//NONSGML AWL Calendar//EN
+VERSION:2.0
+CALSCALE:GREGORIAN
+BEGIN:VEVENT
+DTSTAMP:20070417T195323Z
+ORGANIZER:MAILTO:
+X-PILOTID:12451851
+X-PILOTSTAT:0
+CREATED:20050814T160951Z
+UID:libkcal-1123041440.757
+SEQUENCE:0
+LAST-MODIFIED:20070124T213448Z
+SUMMARY:event number 2
+CLASS:PUBLIC
+PRIORITY:3
+RRULE:FREQ=DAILY;UNTIL=20020528T153000Z;INTERVAL=14
+EXDATE;VALUE=DATE:20020402
+DTSTART:20020219T163000Z
+DTEND:20020219T180000Z
+TRANSP:OPAQUE
+BEGIN:VALARM
+DESCRIPTION:
+ACTION:DISPLAY
+TRIGGER;VALUE=DURATION:-P1D
+END:VALARM
+END:VEVENT
+END:VCALENDAR
+EOF;
+
+require_once 'caldav-client.php';
+
+interface ICalendar {
+ function getProperty($name);
+ function setProperty($name, $value);
+ function getAllProperties();
+ function setAllProperties(array $assoc_array);
+ function isChanged();
+}
+
+class VEvent implements ICalendar {
+ private $attendee;
+ private $class;
+ private $created;
+ private $dtstamp;
+ private $description;
+ private $dtend;
+ private $dtstart;
+ private $duration;
+ private $exdate;
+ private $lastmodified;
+ private $location;
+ private $organizer;
+ private $priority;
+ private $rrule;
+ private $sequence;
+ private $status;
+ private $summary;
+ private $transp;
+ private $uid;
+ private $xprop = array();
+ // Properties must not contain hypens in their name
+ private static $translate = array(
+ 'lastmodified' => 'last-modified',
+ 'xprop' => 'x-prop'
+ );
+ private $changed;
+
+ function __construct($values = array()) {
+ if (! is_array($values))
+ throw new Exception("Attribute to constructor must be an array");
+ $this->setProperties($values);
+ $this->changed = FALSE;
+ }
+
+ private function setProperties(array $props) {
+ foreach ($props as $k => $v) {
+ switch (strtoupper($k)) {
+ case 'DTSTAMP':
+ $this->dtstamp = $v;
+ break;
+ case 'ORGANIZER':
+ $this->organizer = $v;
+ break;
+ case 'CREATED':
+ $this->created = $v;
+ break;
+ case 'UID':
+ $this->uid = $v;
+ break;
+ case 'SEQUENCE':
+ $this->sequence = $v;
+ break;
+ case 'LAST-MODIFIED':
+ $this->lastmodified = $v;
+ break;
+ case 'SUMMARY':
+ $this->summary = $v;
+ break;
+ case 'CLASS':
+ $this->class = $v;
+ break;
+ case 'PRIORITY':
+ $this->priority = $v;
+ break;
+ case 'RRULE':
+ $this->rrule = $v;
+ break;
+ case 'EXDATE':
+ $this->exdate = $v;
+ break;
+ case 'DTSTART':
+ $this->dtstart = $v;
+ break;
+ case 'DTEND':
+ $this->dtend = $v;
+ break;
+ case 'TRANSP':
+ $this->transp = $v;
+ break;
+ case 'ATTENDEE':
+ $this->attendee = $v;
+ break;
+ case 'DURATION':
+ $this->duration = $v;
+ break;
+ case 'LOCATION':
+ $this->location = $v;
+ break;
+ case 'STATUS':
+ $this->status = $v;
+ break;
+ case 'DESCRIPTION':
+ $this->description = $v;
+ break;
+ default:
+ if (($k[0] == 'x' || $k[0] == 'X') && $k[1] == '-')
+ $this->xprop[$k] = $v;
+ else
+ throw new Exception("[$k,$v]: Unknown attribute");
+ }
+ }
+ }
+
+ public function getProperty($name) {
+ $prop = strtolower($name);
+ if (($trans = array_search($prop, self::$translate)) !== false)
+ $prop = $trans;
+ if (! property_exists($this, $prop)) {
+ // Support for PHP 5 < 5.3
+ $obj = new ReflectionClass(get_class($this));
+ if (! $obj->hasProperty($prop))
+ throw new Exception("$name: Unknown property");
+ }
+ return $this->$prop;
+ }
+
+ public function setProperty($name, $value) {
+ $prop = strtolower($name);
+ if (($trans = array_search($prop, self::$translate)) !== false)
+ $prop = $trans;
+ if (! property_exists($this, $prop)) {
+ // Support for PHP 5 < 5.3
+ $obj = new ReflectionClass(get_class($this));
+ if (! $obj->hasProperty($prop))
+ throw new Exception("$name: Unknown property");
+ }
+ $this->$prop = $value;
+ $this->changed = TRUE;
+ }
+
+ function getAllProperties() {
+ $props = array();
+ $p = get_object_vars($this);
+ foreach ($p as $k => $v){
+ if ($k == 'changed')
+ continue;
+ if (array_key_exists($k, self::$translate))
+ $k = strtoupper(self::$translate[$k]);
+ else
+ $k = strtoupper($k);
+ $props[$k] = $v;
+ }
+ return $props;
+ }
+
+ function setAllProperties(array $assoc_array) {
+ $props = array();
+ foreach ($assoc_array as $k => $v){
+ $k = strtolower($k);
+ if (is_array($v)) {
+ foreach ($v as $k1 => $v1)
+ $props[$k1] = $v1;
+ }
+ else
+ $props[$k] = $v;
+ }
+ $this->setProperties($props);
+ $this->changed = TRUE;
+ }
+
+ function isChanged() {
+ return $this->changed;
+ }
+
+}
+
+class VAlarm implements ICalendar {
+ private $action;
+ private $description;
+ private $duration;
+ private $repeat;
+ private $trigger;
+ // Properties must not contain hypens in their name
+ private static $translate = array();
+ private $changed;
+
+ function __construct($values = array()) {
+ if (! is_array($values))
+ throw new Exception("Attribute to constructor must be an array");
+ $this->setProperties($values);
+ $this->changed = FALSE;
+ }
+
+ private function setProperties(array $props) {
+ foreach ($props as $k => $v) {
+ switch (strtoupper($k)) {
+ case 'ACTION':
+ $this->action = $v;
+ break;
+ case 'DESCRIPTION':
+ $this->description = $v;
+ break;
+ case 'DURATION':
+ $this->duration = $v;
+ break;
+ case 'REPEAT':
+ $this->repeat = $v;
+ break;
+ case 'TRIGGER':
+ $this->trigger = $v;
+ break;
+ default:
+ throw new Exception("$k: Unknown attribute");
+ }
+ }
+ }
+
+ public function getProperty($name) {
+ $prop = strtolower($name);
+ if (($trans = array_search($prop, self::$translate)) !== false)
+ $prop = $trans;
+ if (! property_exists($this, $prop)) {
+ // Support for PHP 5 < 5.3
+ $obj = new ReflectionClass(get_class($this));
+ if (! $obj->hasProperty($prop))
+ throw new Exception("$name: Unknown property");
+ }
+ return $this->$prop;
+ }
+
+ public function setProperty($name, $value) {
+ $prop = strtolower($name);
+ if (($trans = array_search($prop, self::$translate)) !== false)
+ $prop = $trans;
+ if (! property_exists($this, $prop)) {
+ // Support for PHP 5 < 5.3
+ $obj = new ReflectionClass(get_class($this));
+ if (! $obj->hasProperty($prop))
+ throw new Exception("$name: Unknown property");
+ }
+ $this->$prop = $value;
+ $this->changed = TRUE;
+ }
+
+ function getAllProperties() {
+ $props = array();
+ $p = get_object_vars($this);
+ foreach ($p as $k => $v){
+ if ($k == 'changed')
+ continue;
+ if (array_key_exists($k, self::$translate))
+ $k = strtoupper(self::$translate[$k]);
+ else
+ $k = strtoupper($k);
+ $props[$k] = $v;
+ }
+ return $props;
+ }
+
+ function setAllProperties(array $assoc_array) {
+ $props = array();
+ foreach ($assoc_array as $k => $v){
+ $k = strtolower($k);
+ if (is_array($v)) {
+ foreach ($v as $k1 => $v1)
+ $props[$k1] = $v1;
+ }
+ else
+ $props[$k] = $v;
+ }
+ $this->setProperties($props);
+ $this->changed = TRUE;
+ }
+
+ function isChanged() {
+ return $this->changed;
+ }
+
+}
+
+class VTimezone implements ICalendar {
+
+ private $tzid;
+ private $xprop;
+ private $standard;
+ private $daylight;
+
+ // Properties must not contain hypens in their name
+ private static $translate = array();
+ private $changed;
+
+ function __construct($values = array()) {
+ if (! is_array($values))
+ throw new Exception("Attribute to constructor must be an array");
+ $this->setProperties($values);
+ $this->changed = FALSE;
+ }
+
+ private function setProperties(array $props) {
+ foreach ($props as $k => $v) {
+ switch (strtoupper($k)) {
+ case 'TZID':
+ $this->tzid = $v;
+ break;
+ default:
+ if (($k[0] == 'x' || $k[0] == 'X') && $k[1] == '-')
+ $this->xprop[$k] = $v;
+ else
+ throw new Exception("[$k,$v]: Unknown attribute");
+ }
+ }
+ }
+
+ function getProperty($name){}
+ function setProperty($name, $value) {
+ $prop = strtolower($name);
+ if (($trans = array_search($prop, self::$translate)) !== false)
+ $prop = $trans;
+ if (! property_exists($this, $prop)) {
+ // Support for PHP 5 < 5.3
+ $obj = new ReflectionClass(get_class($this));
+ if (! $obj->hasProperty($prop))
+ throw new Exception("$name: Unknown property");
+ }
+ $this->$prop = $value;
+ if (
+ $this->$prop == 'standard' && ! isset($this->standard) ||
+ $this->$prop == 'daylight' && ! isset($this->daylight)
+ ) {
+ // we are constructing the object
+ }
+ else
+ $this->changed = TRUE;
+ }
+ function getAllProperties(){}
+ function setAllProperties(array $assoc_array){}
+ function isChanged(){}
+}
+
+class VCalendar {
+ private $calscale;
+ private $prodid;
+ private $version;
+ private $objects;
+
+ function __construct($values = array()) {
+ if (! is_array($values))
+ throw new Exception("Attribute to constructor must be an array");
+ $this->objects = array();
+ //print_r($values);
+ foreach ($values as $k => $v) {
+ switch (strtoupper($k)) {
+ case 'CALSCALE':
+ $this->calscale = $v;
+ break;
+ case 'PRODID':
+ $this->prodid = $v;
+ break;
+ case 'VERSION':
+ $this->version = $v;
+ break;
+ default:
+ throw new Exception("$k: Unknown attribute");
+ }
+ }
+ }
+
+ public function addObject(ICalendar $object) {
+ $this->objects[get_class($object)] = $object;
+ }
+
+ public function getObject($name) {
+ if (isset($this->objects[$name]))
+ return $this->objects[$name];
+ else
+ return null;
+ }
+
+ public function getObjects() {
+ return $this->objects;
+ }
+
+}
+
+class IcalParserIterator implements Iterator {
+ private $icalParser;
+ private $pos;
+
+ function __construct(IcalParser $icalParser) {
+ if (! $icalParser instanceof IcalParser)
+ throw new Exception(get_class($icalParser) . ': Can only handle instances of class IcalParser');
+ $this->icalParser = $icalParser;
+ $this->pos = 0;
+ }
+
+ public function current() {
+ return $this->icalParser->getIcal($this->pos);
+ }
+
+ public function key() {
+ return $this->pos;
+ }
+
+ public function next() {
+ $this->pos++;
+ }
+
+ public function rewind() {
+ $this->pos = 0;
+ }
+
+ public function valid() {
+ return $this->icalParser->peek($this->pos);
+ }
+
+}
+
+class IcalParser implements IteratorAggregate {
+// private $elements = array('VCALENDAR', 'VEVENT', 'VALARM', 'VTIMEZONE');
+// private $subelem = array('VTIMEZONE' => array('STANDARD', 'DAYLIGHT'));
+ private $items;
+
+ function __construct($message = NULL) {
+ $this->items = array();
+ if ($message)
+ $this->setMessage($message);
+ }
+
+ function setMessage($message) {
+ $this->split_message($message);
+ }
+
+ private function remove_value(array &$array, $key) {
+ $tmp = array();
+ $val;
+
+ foreach ($array as $k => $v) {
+ if ($k == $key)
+ $val = $v;
+ else
+ $tmp[$k] = $v;
+ }
+ $array = $tmp;
+ return $val;
+ }
+
+ private function newObject($name, $props = array()) {
+ try {
+ $obj = new ReflectionClass($name);
+ }
+ catch (ReflectionException $ex) {
+ print $ex->getMessage();
+ throw new Exception("$name: Class not found");
+ }
+ $obj = NULL;
+ return new $name($props);
+ }
+
+ private function split_message($message) {
+ $data = null;
+ $elem_data = array();
+ $data_list = array();
+ $elem_list = array();
+
+ if (empty($message))
+ return;
+ //print "$message\n";
+ $lines = explode("\n", $message);
+ foreach ($lines as $line) {
+ $a = explode(":", $line);
+ //print_r($a);
+ $item = strtoupper($a[0]);
+ if (count($a) > 2) {
+ $elem = '';
+ for ($i = 1; $i < count($a); $i++) {
+ if ($elem != '')
+ $elem .= ':';
+ $elem .= $a[$i];
+ }
+ //print "elem: $elem\n";
+ }
+ else
+ $elem = $a[1];
+ switch ($item) {
+ case 'BEGIN':
+ /*if (! in_array($elem, $this->elements)) {
+ $found = TRUE;
+ if (($sub = end($elem_list)) !== FALSE) {
+ if (! array_key_exists($sub, $this->subelem))
+ $found = FALSE;
+ }
+ else
+ $found = FALSE;
+ reset($elem_list);
+ if (! $found)
+ break;
+ }*/
+ if (count($data) > 0) {
+ if (count($elem_list) > 0) {
+ /*$name = array_pop($elem_list);
+ if (array_key_exists($name, $this->subelem)) {
+ print "BEGIN: $name\n";
+ print_r($data);
+ }*/
+ $elem_data[array_pop($elem_list)] = $data;
+ }
+ else
+ $elem_data[$elem] = $data;
+ }
+ array_push($elem_list, $elem);
+ $data = array();
+ break;
+ case 'END':
+ if (count($elem_list) > 0) {
+ /*$name = array_pop($elem_list);
+ if (array_key_exists($name, $this->subelem)) {
+ print "END: $name\n";
+ print_r($data);
+ }*/
+ $elem_data[array_pop($elem_list)] = $data;
+ }
+ $data = array();
+ if ($elem == 'VCALENDAR' && count($elem_data) > 1) {
+ array_push($data_list, $elem_data);
+ $elem_data = array();
+ $elem_list = array();
+ }
+ break;
+ default:
+ if (! is_array($data))
+ throw new Exception("Message is not valid [missing 'BEGIN']");
+ if (($pos = strpos($item, ';')) !== false) {
+ $head = substr($item, 0, $pos);
+ $elem = substr($item, $pos + 1) . ';' . $elem;
+ $item = $head;
+ //print "Ny elem: $item:$elem\n";
+ }
+ $data[$item] = $elem;
+ }
+ }
+ //print_r($data_list);
+ foreach ($data_list as $item) {
+ $c = $this->remove_value($item, 'VCALENDAR');
+ $calendar = new VCalendar($c);
+ foreach ($item as $k => $v) {
+ if ($k == 'DAYLIGHT' || $k == 'STANDARD') {
+ $object = $calendar->getObject('VTimezone');
+ if (! is_object($object)) {
+ $object = $this->newObject('VTimezone');
+ $calendar->addObject($object);
+ }
+ $object->setProperty($k, $v);
+ }
+ else {
+ if (($object = $calendar->getObject($k)) == NULL) {
+ $object = $this->newObject($k, $v);
+ $calendar->addObject($object);
+ }
+ else {
+ $object->setAllProperties($v);
+ }
+ }
+ }
+ array_push($this->items, $calendar);
+ }
+ }
+
+ public function getIterator() {
+ return new IcalParserIterator($this);
+ }
+
+ public function getIcal($id) {
+ if ($this->peek($id))
+ return $this->items[$id];
+ else
+ throw new Exception("Index out of bounds");
+ }
+
+ public function peek($id) {
+ return isset($this->items[$id]);
+ }
+
+}
+
+?>
--- /dev/null
+<?php
+/* $Id$ */
+
+ require_once 'caldavresource.class.php';
+
+ abstract class IComponent {
+
+ public $type;
+ private $component;
+ private $url;
+ private $etag;
+ private $dirty;
+
+ function __construct($etag, $url, VTYPE $type,
+ iCalendar $component, $new) {
+ $this->etag = $etag;
+ $this->url = $url;
+ $this->component = $component;
+ $this->type = $type;
+ $this->dirty = $new;
+ }
+
+ public function isDirty() {
+ return $this->dirty;
+ }
+
+ public function setDirty() {
+ $this->dirty = TRUE;
+ }
+
+ public function getResource() {
+ return $this->component;
+ }
+
+ public function setResource(iCalendar $component) {
+ $this->component = $component;
+ $this->dirty = TRUE;
+ }
+
+ public function getBaseComponent() {
+ return $this->getComponent($this->type);
+ }
+
+ public function getUrl() {
+ return $this->url;
+ }
+
+ public function getEtag() {
+ return $this->etag;
+ }
+
+ public function setEtag($etag) {
+ $this->etag = $etag;
+ }
+
+ public function getComponent($type) {
+ $ref = $this->component;
+ //print_r($ref);
+
+ if ($this->component === NULL)
+ $ical = NULL;
+ else if ($type instanceof VTYPE && $type->ordinal() == VTYPE::VTIMEZONE) {
+ $ical = $ref->component->GetComponents('VTIMEZONE');
+ }
+ else {
+ //$theType = sprintf("%s", $this->type);
+ //print "self: $theType\n";
+ $component = $ref->component->GetComponents($this->type);
+ //print_r($component);
+ if (! $type instanceof VTYPE)
+ $type = new VTYPE($type);
+ //$theType = sprintf("%s", $type);
+ //print "instance: $theType\n";
+ if (count($component) > 0)
+ $ical = $component[0];
+ if ($type->ordinal() != $this->type->ordinal() && $ical) {
+ $ical = $ical->GetComponents($type);
+ }
+ }
+ return $ical;
+ }
+
+ public function isUTCTime() {
+ $event = $this->getBaseComponent();
+ $start = $event->GetPValue('DTSTART');
+ $end = $event->GetPValue('DTEND');
+
+ if (! ($start && $end))
+ throw new Exception("Not a valid iCal component");
+ return ($start[strlen($start) - 1] == 'Z' ||
+ $nd[strlen($end) - 1] == 'Z');
+ }
+
+ public function getDetails() {
+ $event = $this->getBaseComponent();
+ $start = strtotime($event->GetPValue('DTSTART'));
+ $start = date("Y-m-d H:m", $start);
+ $end = strtotime($event->GetPValue('DTEND'));
+ $end = date("Y-m-d H:m", $end);
+ $title = $event->GetPValue('SUMMARY');
+
+ return "$start-$end: $title";
+ }
+
+ public function getTZID() {
+ $res = 'UTC';
+
+ if (! $this->isUTCTime()) {
+ $timezone = $this->getTimeZone();
+ if ($timezone) {
+ $res = $timezone->GetPValue('TZID');
+ }
+ // timezone not given assume TZID = server's timezone
+ // servers default timezone is UTC
+ }
+ return $res;
+ }
+
+ function getTimeZone() {
+ $timezone = $this->getComponent(VTYPE::VTIMEZONE);
+ if ($timezone)
+ $timezone = $timezone[0];
+ return $timezone;
+ }
+
+ public function __toString() {
+ return $this->type->__toString();
+ }
+
+ /**
+ * The following functions should be overloaded in
+ * the child classes if the have specific functionality
+ */
+
+ function isActive($start, $end) {
+ return FALSE;
+ }
+
+ function getActiveDates() {
+ return array();
+ }
+
+ function getAlarm() {
+ return NULL;
+ }
+
+ }
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml" lang="en"><head>
+
+
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <meta name="robots" content="index,follow">
+ <meta name="creator" content="rfcmarkup version 1.74">
+ <link rel="icon" href="http://tools.ietf.org/images/rfc.png" type="image/png">
+ <link rel="shortcut icon" href="http://tools.ietf.org/images/rfc.png" type="image/png">
+ <title>RFC 2445 - Internet Calendaring and Scheduling Core Object Specification (iCalendar)</title>
+
+ <style type="text/css">
+ body {
+ margin: 0px 8px;
+ font-size: 1em;
+ }
+ h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 {
+ font-weight: bold;
+ line-height: 0pt;
+ display: inline;
+ white-space: pre;
+ font-family: monospace;
+ font-size: 1em;
+ font-weight: bold;
+ }
+ pre {
+ font-size: 1em;
+ margin-top: 0px;
+ margin-bottom: 0px;
+ }
+ .pre {
+ white-space: pre;
+ font-family: monospace;
+ }
+ .header{
+ font-weight: bold;
+ }
+ .newpage {
+ page-break-before: always;
+ }
+ .invisible {
+ text-decoration: none;
+ color: white;
+ }
+ @media print {
+ body {
+ font-size: 10.5pt;
+ }
+ h1, h2, h3, h4, h5, h6 {
+ font-size: 10.5pt;
+ }
+
+ a:link, a:visited {
+ color: inherit;
+ text-decoration: none;
+ }
+ .noprint {
+ display: none;
+ }
+ }
+ @media screen {
+ .grey, .grey a:link, .grey a:visited {
+ color: #777;
+ }
+ .docinfo {
+ background-color: #EEE;
+ }
+ .top {
+ border-top: 7px solid #EEE;
+ }
+ .bgwhite { background-color: white; }
+ .bgred { background-color: #F44; }
+ .bggrey { background-color: #666; }
+ .bgbrown { background-color: #840; }
+ .bgorange { background-color: #FA0; }
+ .bgyellow { background-color: #EE0; }
+ .bgmagenta{ background-color: #F4F; }
+ .bgblue { background-color: #66F; }
+ .bgcyan { background-color: #4DD; }
+ .bggreen { background-color: #4F4; }
+
+ .legend { font-size: 90%; }
+ .cplate { font-size: 70%; border: solid grey 1px; }
+ }
+ </style>
+
+ <script type="text/javascript"><!--
+ function addHeaderTags() {
+ var spans = document.getElementsByTagName("span");
+ for (var i=0; i < spans.length; i++) {
+ var elem = spans[i];
+ if (elem) {
+ var level = elem.getAttribute("class");
+ if (level == "h1" || level == "h2" || level == "h3" || level == "h4" || level == "h5" || level == "h6") {
+ elem.innerHTML = "<"+level+">"+elem.innerHTML+"</"+level+">";
+ }
+ }
+ }
+ }
+ var legend_html = "Colour legend:<br /> <table> <tr><td>Unknown:</td> <td><span class='cplate bgwhite'> </span></td></tr> <tr><td>Draft:</td> <td><span class='cplate bgred'> </span></td></tr> <tr><td>Informational:</td> <td><span class='cplate bgorange'> </span></td></tr> <tr><td>Experimental:</td> <td><span class='cplate bgyellow'> </span></td></tr> <tr><td>Best Common Practice:</td><td><span class='cplate bgmagenta'> </span></td></tr> <tr><td>Proposed Standard:</td><td><span class='cplate bgblue'> </span></td></tr> <tr><td>Draft Standard:</td> <td><span class='cplate bgcyan'> </span></td></tr> <tr><td>Standard:</td> <td><span class='cplate bggreen'> </span></td></tr> <tr><td>Historic:</td> <td><span class='cplate bggrey'> </span></td></tr> <tr><td>Obsolete:</td> <td><span class='cplate bgbrown'> </span></td></tr> </table>";
+ function showElem(id) {
+ var elem = document.getElementById(id);
+ elem.innerHTML = eval(id+"_html");
+ elem.style.visibility='visible';
+ }
+ function hideElem(id) {
+ var elem = document.getElementById(id);
+ elem.style.visibility='hidden';
+ elem.innerHTML = "";
+ }
+ // -->
+ </script>
+</head><body onload="addHeaderTags()">
+ <div style="height: 13px;">
+ <div onmouseover="this.style.cursor='pointer';" onclick="showElem('legend');" onmouseout="hideElem('legend')" style="height: 6px; position: absolute; cursor: pointer;" class="pre noprint docinfo bgblue" title="Click for colour legend."> </div>
+ <div id="legend" class="docinfo noprint pre legend" style="border: 1px solid rgb(51, 68, 85); padding: 4px 9px 5px 7px; position: absolute; top: 4px; left: 4ex; visibility: hidden; background-color: white;" onmouseover="showElem('legend');" onmouseout="hideElem('legend');"></div>
+ </div>
+<span class="pre noprint docinfo top">[<a style="" href="http://tools.ietf.org/html/" title="Document search and retrieval page">RFCs/IDs</a>] [<a href="http://tools.ietf.org/rfc/rfc2445.txt" title="Plaintext version of this document">Plain</a>] [From <a href="http://tools.ietf.org/html/draft-ietf-calsch-ical">draft-ietf-calsch-ical</a>] </span><br>
+<span class="pre noprint docinfo"> </span><br>
+<span class="pre noprint docinfo"> PROPOSED STANDARD</span><br>
+<span class="pre noprint docinfo"> <a style="" href="http://www.rfc-editor.org/errata_search.php?rfc=2445">Errata</a></span><br>
+<pre>Network Working Group F. Dawson
+Request for Comments: 2445 Lotus
+Category: Standards Track D. Stenerson
+ Microsoft
+ November 1998
+
+
+ <span class="h1"><h1>Internet Calendaring and Scheduling Core Object Specification</h1></span>
+ <span class="h1"><h1>(iCalendar)</h1></span>
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (1998). All Rights Reserved.
+
+Abstract
+
+ There is a clear need to provide and deploy interoperable calendaring
+ and scheduling services for the Internet. Current group scheduling
+ and Personal Information Management (PIM) products are being extended
+ for use across the Internet, today, in proprietary ways. This memo
+ has been defined to provide the definition of a common format for
+ openly exchanging calendaring and scheduling information across the
+ Internet.
+
+ This memo is formatted as a registration for a MIME media type per
+ [<a href="http://tools.ietf.org/html/rfc2048" title=""Multipurpose Internet Mail Extensions (MIME) - Part Four: Registration Procedures"">RFC 2048</a>]. However, the format in this memo is equally applicable
+ for use outside of a MIME message content type.
+
+ The proposed media type value is 'text/calendar'. This string would
+ label a media type containing calendaring and scheduling information
+ encoded as text characters formatted in a manner outlined below.
+
+ This MIME media type provides a standard content type for capturing
+ calendar event, to-do and journal entry information. It also can be
+ used to convey free/busy time information. The content type is
+ suitable as a MIME message entity that can be transferred over MIME
+ based email systems, using HTTP or some other Internet transport. In
+
+
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 1]</span>
+</pre><pre class="newpage"><a name="page-2" id="page-2" href="#page-2" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ addition, the content type is useful as an object for interactions
+ between desktop applications using the operating system clipboard,
+ drag/drop or file systems capabilities.
+
+ This memo is based on the earlier work of the vCalendar specification
+ for the exchange of personal calendaring and scheduling information.
+ In order to avoid confusion with this referenced work, this memo is
+ to be known as the iCalendar specification.
+
+ This memo defines the format for specifying iCalendar object methods.
+ An iCalendar object method is a set of usage constraints for the
+ iCalendar object. For example, these methods might define scheduling
+ messages that request an event be scheduled, reply to an event
+ request, send a cancellation notice for an event, modify or replace
+ the definition of an event, provide a counter proposal for an
+ original event request, delegate an event request to another
+ individual, request free or busy time, reply to a free or busy time
+ request, or provide similar scheduling messages for a to-do or
+ journal entry calendar component. The iCalendar Transport-indendent
+ Interoperability Protocol (iTIP) defined in [<a href="#ref-ITIP" title=""iCalendar Transport-Independent Interoperability Protocol (iTIP) : Scheduling Events, Busy Time, To-dos and Journal Entries"">ITIP</a>] is one such
+ scheduling protocol.
+
+Table of Contents
+
+ <a href="#section-1">1</a> Introduction.....................................................<a href="#page-5">5</a>
+ <a href="#section-2">2</a> Basic Grammar and Conventions....................................<a href="#page-6">6</a>
+ <a href="#section-2.1">2.1</a> Formatting Conventions .......................................<a href="#page-7">7</a>
+ <a href="#section-2.2">2.2</a> Related Memos ................................................<a href="#page-8">8</a>
+ <a href="#section-2.3">2.3</a> International Considerations .................................<a href="#page-8">8</a>
+ <a href="#section-3">3</a> Registration Information.........................................<a href="#page-8">8</a>
+ <a href="#section-3.1">3.1</a> Content Type .................................................<a href="#page-8">8</a>
+ <a href="#section-3.2">3.2</a> Parameters ...................................................<a href="#page-9">9</a>
+ <a href="#section-3.3">3.3</a> Content Header Fields .......................................<a href="#page-10">10</a>
+ <a href="#section-3.4">3.4</a> Encoding Considerations .....................................<a href="#page-10">10</a>
+ <a href="#section-3.5">3.5</a> Security Considerations .....................................<a href="#page-10">10</a>
+ <a href="#section-3.6">3.6</a> Interoperability Considerations .............................<a href="#page-11">11</a>
+ <a href="#section-3.7">3.7</a> Applications Which Use This Media Type ......................<a href="#page-11">11</a>
+ <a href="#section-3.8">3.8</a> Additional Information ......................................<a href="#page-11">11</a>
+ <a href="#section-3.9">3.9</a> Magic Numbers ...............................................<a href="#page-11">11</a>
+ <a href="#section-3.10">3.10</a> File Extensions ............................................<a href="#page-11">11</a>
+ <a href="#section-3.11">3.11</a> Contact for Further Information: ...........................<a href="#page-12">12</a>
+ <a href="#section-3.12">3.12</a> Intended Usage .............................................<a href="#page-12">12</a>
+ <a href="#section-3.13">3.13</a> Authors/Change Controllers .................................<a href="#page-12">12</a>
+ <a href="#section-4">4</a> iCalendar Object Specification..................................<a href="#page-13">13</a>
+ <a href="#section-4.1">4.1</a> Content Lines ...............................................<a href="#page-13">13</a>
+ <a href="#section-4.1.1">4.1.1</a> List and Field Separators ................................<a href="#page-16">16</a>
+ <a href="#section-4.1.2">4.1.2</a> Multiple Values ..........................................<a href="#page-16">16</a>
+ <a href="#section-4.1.3">4.1.3</a> Binary Content ...........................................<a href="#page-16">16</a>
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 2]</span>
+</pre><pre class="newpage"><a name="page-3" id="page-3" href="#page-3" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ <a href="#section-4.1.4">4.1.4</a> Character Set ............................................<a href="#page-17">17</a>
+ <a href="#section-4.2">4.2</a> Property Parameters .........................................<a href="#page-17">17</a>
+ <a href="#section-4.2.1">4.2.1</a> Alternate Text Representation ............................<a href="#page-18">18</a>
+ <a href="#section-4.2.2">4.2.2</a> Common Name ..............................................<a href="#page-19">19</a>
+ <a href="#section-4.2.3">4.2.3</a> Calendar User Type .......................................<a href="#page-20">20</a>
+ <a href="#section-4.2.4">4.2.4</a> Delegators ...............................................<a href="#page-20">20</a>
+ <a href="#section-4.2.5">4.2.5</a> Delegatees ...............................................<a href="#page-21">21</a>
+ <a href="#section-4.2.6">4.2.6</a> Directory Entry Reference ................................<a href="#page-21">21</a>
+ <a href="#section-4.2.7">4.2.7</a> Inline Encoding ..........................................<a href="#page-22">22</a>
+ <a href="#section-4.2.8">4.2.8</a> Format Type ..............................................<a href="#page-23">23</a>
+ <a href="#section-4.2.9">4.2.9</a> Free/Busy Time Type ......................................<a href="#page-23">23</a>
+ <a href="#section-4.2.10">4.2.10</a> Language ................................................<a href="#page-24">24</a>
+ <a href="#section-4.2.11">4.2.11</a> Group or List Membership ................................<a href="#page-25">25</a>
+ <a href="#section-4.2.12">4.2.12</a> Participation Status ....................................<a href="#page-25">25</a>
+ <a href="#section-4.2.13">4.2.13</a> Recurrence Identifier Range .............................<a href="#page-27">27</a>
+ <a href="#section-4.2.14">4.2.14</a> Alarm Trigger Relationship ..............................<a href="#page-27">27</a>
+ <a href="#section-4.2.15">4.2.15</a> Relationship Type .......................................<a href="#page-28">28</a>
+ <a href="#section-4.2.16">4.2.16</a> Participation Role ......................................<a href="#page-29">29</a>
+ <a href="#section-4.2.17">4.2.17</a> RSVP Expectation ........................................<a href="#page-29">29</a>
+ <a href="#section-4.2.18">4.2.18</a> Sent By .................................................<a href="#page-30">30</a>
+ <a href="#section-4.2.19">4.2.19</a> Time Zone Identifier ....................................<a href="#page-30">30</a>
+ <a href="#section-4.2.20">4.2.20</a> Value Data Types ........................................<a href="#page-32">32</a>
+ <a href="#section-4.3">4.3</a> Property Value Data Types ...................................<a href="#page-32">32</a>
+ <a href="#section-4.3.1">4.3.1</a> Binary ...................................................<a href="#page-33">33</a>
+ <a href="#section-4.3.2">4.3.2</a> Boolean ..................................................<a href="#page-33">33</a>
+ <a href="#section-4.3.3">4.3.3</a> Calendar User Address ....................................<a href="#page-34">34</a>
+ <a href="#section-4.3.4">4.3.4</a> Date .....................................................<a href="#page-34">34</a>
+ <a href="#section-4.3.5">4.3.5</a> Date-Time ................................................<a href="#page-35">35</a>
+ <a href="#section-4.3.6">4.3.6</a> Duration .................................................<a href="#page-37">37</a>
+ <a href="#section-4.3.7">4.3.7</a> Float ....................................................<a href="#page-38">38</a>
+ <a href="#section-4.3.8">4.3.8</a> Integer ..................................................<a href="#page-38">38</a>
+ <a href="#section-4.3.9">4.3.9</a> Period of Time ...........................................<a href="#page-39">39</a>
+ <a href="#section-4.3.10">4.3.10</a> Recurrence Rule .........................................<a href="#page-40">40</a>
+ <a href="#section-4.3.11">4.3.11</a> Text ....................................................<a href="#page-45">45</a>
+ <a href="#section-4.3.12">4.3.12</a> Time ....................................................<a href="#page-47">47</a>
+ <a href="#section-4.3.13">4.3.13</a> URI .....................................................<a href="#page-49">49</a>
+ <a href="#section-4.3.14">4.3.14</a> UTC Offset ..............................................<a href="#page-49">49</a>
+ <a href="#section-4.4">4.4</a> iCalendar Object ............................................<a href="#page-50">50</a>
+ <a href="#section-4.5">4.5</a> Property ....................................................<a href="#page-51">51</a>
+ <a href="#section-4.6">4.6</a> Calendar Components .........................................<a href="#page-51">51</a>
+ <a href="#section-4.6.1">4.6.1</a> Event Component ..........................................<a href="#page-52">52</a>
+ <a href="#section-4.6.2">4.6.2</a> To-do Component ..........................................<a href="#page-55">55</a>
+ <a href="#section-4.6.3">4.6.3</a> Journal Component ........................................<a href="#page-56">56</a>
+ <a href="#section-4.6.4">4.6.4</a> Free/Busy Component ......................................<a href="#page-58">58</a>
+ <a href="#section-4.6.5">4.6.5</a> Time Zone Component ......................................<a href="#page-60">60</a>
+ <a href="#section-4.6.6">4.6.6</a> Alarm Component ..........................................<a href="#page-67">67</a>
+ <a href="#section-4.7">4.7</a> Calendar Properties .........................................<a href="#page-73">73</a>
+ <a href="#section-4.7.1">4.7.1</a> Calendar Scale ...........................................<a href="#page-73">73</a>
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 3]</span>
+</pre><pre class="newpage"><a name="page-4" id="page-4" href="#page-4" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ <a href="#section-4.7.2">4.7.2</a> Method ...................................................<a href="#page-74">74</a>
+ <a href="#section-4.7.3">4.7.3</a> Product Identifier .......................................<a href="#page-75">75</a>
+ <a href="#section-4.7.4">4.7.4</a> Version ..................................................<a href="#page-76">76</a>
+ <a href="#section-4.8">4.8</a> Component Properties ........................................<a href="#page-77">77</a>
+ <a href="#section-4.8.1">4.8.1</a> Descriptive Component Properties .........................<a href="#page-77">77</a>
+ <a href="#section-4.8.1.1">4.8.1.1</a> Attachment ...........................................<a href="#page-77">77</a>
+ <a href="#section-4.8.1.2">4.8.1.2</a> Categories ...........................................<a href="#page-78">78</a>
+ <a href="#section-4.8.1.3">4.8.1.3</a> Classification .......................................<a href="#page-79">79</a>
+ <a href="#section-4.8.1.4">4.8.1.4</a> Comment ..............................................<a href="#page-80">80</a>
+ <a href="#section-4.8.1.5">4.8.1.5</a> Description ..........................................<a href="#page-81">81</a>
+ <a href="#section-4.8.1.6">4.8.1.6</a> Geographic Position ..................................<a href="#page-82">82</a>
+ <a href="#section-4.8.1.7">4.8.1.7</a> Location .............................................<a href="#page-84">84</a>
+ <a href="#section-4.8.1.8">4.8.1.8</a> Percent Complete .....................................<a href="#page-85">85</a>
+ <a href="#section-4.8.1.9">4.8.1.9</a> Priority .............................................<a href="#page-85">85</a>
+ <a href="#section-4.8.1.10">4.8.1.10</a> Resources ...........................................<a href="#page-87">87</a>
+ <a href="#section-4.8.1.11">4.8.1.11</a> Status ..............................................<a href="#page-88">88</a>
+ <a href="#section-4.8.1.12">4.8.1.12</a> Summary .............................................<a href="#page-89">89</a>
+ <a href="#section-4.8.2">4.8.2</a> Date and Time Component Properties .......................<a href="#page-90">90</a>
+ <a href="#section-4.8.2.1">4.8.2.1</a> Date/Time Completed ..................................<a href="#page-90">90</a>
+ <a href="#section-4.8.2.2">4.8.2.2</a> Date/Time End ........................................<a href="#page-91">91</a>
+ <a href="#section-4.8.2.3">4.8.2.3</a> Date/Time Due ........................................<a href="#page-92">92</a>
+ <a href="#section-4.8.2.4">4.8.2.4</a> Date/Time Start ......................................<a href="#page-93">93</a>
+ <a href="#section-4.8.2.5">4.8.2.5</a> Duration .............................................<a href="#page-94">94</a>
+ <a href="#section-4.8.2.6">4.8.2.6</a> Free/Busy Time .......................................<a href="#page-95">95</a>
+ <a href="#section-4.8.2.7">4.8.2.7</a> Time Transparency ....................................<a href="#page-96">96</a>
+ <a href="#section-4.8.3">4.8.3</a> Time Zone Component Properties ...........................<a href="#page-97">97</a>
+ <a href="#section-4.8.3.1">4.8.3.1</a> Time Zone Identifier .................................<a href="#page-97">97</a>
+ <a href="#section-4.8.3.2">4.8.3.2</a> Time Zone Name .......................................<a href="#page-98">98</a>
+ <a href="#section-4.8.3.3">4.8.3.3</a> Time Zone Offset From ................................<a href="#page-99">99</a>
+ <a href="#section-4.8.3.4">4.8.3.4</a> Time Zone Offset To .................................<a href="#page-100">100</a>
+ <a href="#section-4.8.3.5">4.8.3.5</a> Time Zone URL .......................................<a href="#page-101">101</a>
+ <a href="#section-4.8.4">4.8.4</a> Relationship Component Properties .......................<a href="#page-102">102</a>
+ <a href="#section-4.8.4.1">4.8.4.1</a> Attendee ............................................<a href="#page-102">102</a>
+ <a href="#section-4.8.4.2">4.8.4.2</a> Contact .............................................<a href="#page-104">104</a>
+ <a href="#section-4.8.4.3">4.8.4.3</a> Organizer ...........................................<a href="#page-106">106</a>
+ <a href="#section-4.8.4.4">4.8.4.4</a> Recurrence ID .......................................<a href="#page-107">107</a>
+ <a href="#section-4.8.4.5">4.8.4.5</a> Related To ..........................................<a href="#page-109">109</a>
+ <a href="#section-4.8.4.6">4.8.4.6</a> Uniform Resource Locator ............................<a href="#page-110">110</a>
+ <a href="#section-4.8.4.7">4.8.4.7</a> Unique Identifier ...................................<a href="#page-111">111</a>
+ <a href="#section-4.8.5">4.8.5</a> Recurrence Component Properties .........................<a href="#page-112">112</a>
+ <a href="#section-4.8.5.1">4.8.5.1</a> Exception Date/Times ................................<a href="#page-112">112</a>
+ <a href="#section-4.8.5.2">4.8.5.2</a> Exception Rule ......................................<a href="#page-114">114</a>
+ <a href="#section-4.8.5.3">4.8.5.3</a> Recurrence Date/Times ...............................<a href="#page-115">115</a>
+ <a href="#section-4.8.5.4">4.8.5.4</a> Recurrence Rule .....................................<a href="#page-117">117</a>
+ <a href="#section-4.8.6">4.8.6</a> Alarm Component Properties ..............................<a href="#page-126">126</a>
+ <a href="#section-4.8.6.1">4.8.6.1</a> Action ..............................................<a href="#page-126">126</a>
+ <a href="#section-4.8.6.2">4.8.6.2</a> Repeat Count ........................................<a href="#page-126">126</a>
+ <a href="#section-4.8.6.3">4.8.6.3</a> Trigger .............................................<a href="#page-127">127</a>
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 4]</span>
+</pre><pre class="newpage"><a name="page-5" id="page-5" href="#page-5" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ <a href="#section-4.8.7">4.8.7</a> Change Management Component Properties ..................<a href="#page-129">129</a>
+ <a href="#section-4.8.7.1">4.8.7.1</a> Date/Time Created ...................................<a href="#page-129">129</a>
+ <a href="#section-4.8.7.2">4.8.7.2</a> Date/Time Stamp .....................................<a href="#page-130">130</a>
+ <a href="#section-4.8.7.3">4.8.7.3</a> Last Modified .......................................<a href="#page-131">131</a>
+ <a href="#section-4.8.7.4">4.8.7.4</a> Sequence Number .....................................<a href="#page-131">131</a>
+ <a href="#section-4.8.8">4.8.8</a> Miscellaneous Component Properties ......................<a href="#page-133">133</a>
+ <a href="#section-4.8.8.1">4.8.8.1</a> Non-standard Properties .............................<a href="#page-133">133</a>
+ <a href="#section-4.8.8.2">4.8.8.2</a> Request Status ......................................<a href="#page-134">134</a>
+ <a href="#section-5">5</a> iCalendar Object Examples......................................<a href="#page-136">136</a>
+ <a href="#section-6">6</a> Recommended Practices..........................................<a href="#page-140">140</a>
+ <a href="#section-7">7</a> Registration of Content Type Elements..........................<a href="#page-141">141</a>
+ <a href="#section-7.1">7.1</a> Registration of New and Modified iCalendar Object Methods ..<a href="#page-141">141</a>
+ <a href="#section-7.2">7.2</a> Registration of New Properties .............................<a href="#page-141">141</a>
+ <a href="#section-7.2.1">7.2.1</a> Define the property .....................................<a href="#page-142">142</a>
+ <a href="#section-7.2.2">7.2.2</a> Post the Property definition ............................<a href="#page-143">143</a>
+ <a href="#section-7.2.3">7.2.3</a> Allow a comment period ..................................<a href="#page-143">143</a>
+ <a href="#section-7.2.4">7.2.4</a> Submit the property for approval ........................<a href="#page-143">143</a>
+ <a href="#section-7.3">7.3</a> Property Change Control ....................................<a href="#page-143">143</a>
+ <a href="#section-8">8</a> References.....................................................<a href="#page-144">144</a>
+ <a href="#section-9">9</a> Acknowledgments................................................<a href="#page-145">145</a>
+ <a href="#section-10">10</a> Authors' and Chairs' Addresses................................<a href="#page-146">146</a>
+ <a href="#section-11">11</a> Full Copyright Statement......................................<a href="#page-148">148</a>
+
+<span class="h2"><h2><a name="section-1">1</a> Introduction</h2></span>
+
+ 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
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 5]</span>
+</pre><pre class="newpage"><a name="page-6" id="page-6" href="#page-6" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ unwired transport such as infrared might also be used.
+
+ The memo also provides for the definition of iCalendar object methods
+ that will map this content type to a set of messages for supporting
+ calendaring and scheduling operations such as requesting, replying
+ to, modifying, and canceling meetings or appointments, to-dos and
+ journal entries. The iCalendar object methods can be used to define
+ other calendaring and scheduling operations such a requesting for and
+ replying with free/busy time data. Such a scheduling protocol is
+ defined in the iCalendar Transport-independent Interoperability
+ Protocol (iTIP) defined in [<a href="#ref-ITIP" title=""iCalendar Transport-Independent Interoperability Protocol (iTIP) : Scheduling Events, Busy Time, To-dos and Journal Entries"">ITIP</a>].
+
+ The memo also includes a formal grammar for the content type based on
+ the Internet ABNF defined in [<a href="http://tools.ietf.org/html/rfc2234" title=""Augmented BNF for Syntax Specifications: ABNF"">RFC 2234</a>]. This ABNF is required for
+ the implementation of parsers and to serve as the definitive
+ reference when ambiguities or questions arise in interpreting the
+ descriptive prose definition of the memo.
+
+<span class="h2"><h2><a name="section-2">2</a> Basic Grammar and Conventions</h2></span>
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY" and
+ "OPTIONAL" in this document are to be interoperated as described in
+ [<a href="http://tools.ietf.org/html/rfc2119" title=""Key words for use in RFCs to Indicate Requirement Levels"">RFC 2119</a>].
+
+ This memo makes use of both a descriptive prose and a more formal
+ notation for defining the calendaring and scheduling format.
+
+ The notation used in this memo is the ABNF notation of [<a href="http://tools.ietf.org/html/rfc2234" title=""Augmented BNF for Syntax Specifications: ABNF"">RFC 2234</a>].
+ Readers intending on implementing this format defined in this memo
+ should be familiar with this notation in order to properly interpret
+ the specifications of this memo.
+
+ All numeric and hexadecimal values used in this memo are given in
+ decimal notation.
+
+ All names of properties, property parameters, enumerated property
+ values and property parameter values are case-insensitive. However,
+ all other property values are case-sensitive, unless otherwise
+ stated.
+
+ Note: All indented editorial notes, such as this one, are
+ intended to provide the reader with additional information. The
+ information is not essential to the building of an
+ implementation conformant with this memo. The information is
+ provided to highlight a particular feature or characteristic of
+ the memo.
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 6]</span>
+</pre><pre class="newpage"><a name="page-7" id="page-7" href="#page-7" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ The format for the iCalendar object is based on the syntax of the
+ [<a href="http://tools.ietf.org/html/rfc2425" title=""A MIME Content-Type for Directory Information"">RFC 2425</a>] content type. While the iCalendar object is not a profile
+ of the [<a href="http://tools.ietf.org/html/rfc2425" title=""A MIME Content-Type for Directory Information"">RFC 2425</a>] content type, it does reuse a number of the
+ elements from the [<a href="http://tools.ietf.org/html/rfc2425" title=""A MIME Content-Type for Directory Information"">RFC 2425</a>] specification.
+
+<span class="h3"><h3><a name="section-2.1">2.1</a> Formatting Conventions</h3></span>
+
+ The mechanisms defined in this memo are defined in prose. Many of the
+ terms used to describe these have common usage that is different than
+ the standards usage of this memo. In order to reference within this
+ memo elements of the calendaring and scheduling model, core object
+ (this memo) or interoperability protocol [<a href="#ref-ITIP" title=""iCalendar Transport-Independent Interoperability Protocol (iTIP) : Scheduling Events, Busy Time, To-dos and Journal Entries"">ITIP</a>] some formatting
+ conventions have been used. Calendaring and scheduling roles are
+ referred to in quoted-strings of text with the first character of
+ each word in upper case. For example, "Organizer" refers to a role of
+ a "Calendar User" within the scheduling protocol defined by [<a href="#ref-ITIP" title=""iCalendar Transport-Independent Interoperability Protocol (iTIP) : Scheduling Events, Busy Time, To-dos and Journal Entries"">ITIP</a>].
+ Calendar components defined by this memo are referred to with
+ capitalized, quoted-strings of text. All calendar components start
+ with the letter "V". For example, "VEVENT" refers to the event
+ calendar component, "VTODO" refers to the to-do calendar component
+ and "VJOURNAL" refers to the daily journal calendar component.
+ Scheduling methods defined by [<a href="#ref-ITIP" title=""iCalendar Transport-Independent Interoperability Protocol (iTIP) : Scheduling Events, Busy Time, To-dos and Journal Entries"">ITIP</a>] are referred to with
+ capitalized, quoted-strings of text. For example, "REQUEST" refers to
+ the method for requesting a scheduling calendar component be created
+ or modified, "REPLY" refers to the method a recipient of a request
+ uses to update their status with the "Organizer" of the calendar
+ component.
+
+ The properties defined by this memo are referred to with capitalized,
+ quoted-strings of text, followed by the word "property". For example,
+ "ATTENDEE" property refers to the iCalendar property used to convey
+ the calendar address of a calendar user. Property parameters defined
+ by this memo are referred to with lowercase, quoted-strings of text,
+ followed by the word "parameter". For example, "value" parameter
+ refers to the iCalendar property parameter used to override the
+ default data type for a property value. Enumerated values defined by
+ this memo are referred to with capitalized text, either alone or
+ followed by the word "value". For example, the "MINUTELY" value can
+ be used with the "FREQ" component of the "RECUR" data type to specify
+ repeating components based on an interval of one minute or more.
+
+
+
+
+
+
+
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 7]</span>
+</pre><pre class="newpage"><a name="page-8" id="page-8" href="#page-8" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+<span class="h3"><h3><a name="section-2.2">2.2</a> Related Memos</h3></span>
+
+ Implementers will need to be familiar with several other memos that,
+ along with this memo, form a framework for Internet calendaring and
+ scheduling standards. This memo, [<a href="#ref-ICAL">ICAL</a>], specifies a core
+ specification of objects, data types, properties and property
+ parameters.
+
+ [<a name="ref-ITIP" id="ref-ITIP">ITIP</a>] - specifies an interoperability protocol for scheduling
+ between different implementations;
+
+ [<a name="ref-IMIP" id="ref-IMIP">IMIP</a>] specifies an Internet email binding for [<a href="#ref-ITIP" title=""iCalendar Transport-Independent Interoperability Protocol (iTIP) : Scheduling Events, Busy Time, To-dos and Journal Entries"">ITIP</a>].
+
+ This memo does not attempt to repeat the specification of concepts or
+ definitions from these other memos. Where possible, references are
+ made to the memo that provides for the specification of these
+ concepts or definitions.
+
+<span class="h3"><h3><a name="section-2.3">2.3</a> International Considerations</h3></span>
+
+ In the rest of this document, descriptions of characters are of the
+ form "character name (codepoint)", where "codepoint" is from the US-
+ ASCII character set. The "character name" is the authoritative
+ description; (codepoint) is a reference to that character in US-ASCII
+ or US-ASCII compatible sets (for example the ISO-8859-x family, UTF-
+ 8, ISO-2022-xx, KOI8-R). If a non-US-ASCII compatible character set
+ is used, appropriate code-point from that character set MUST be
+ chosen instead. Use of non-US-ASCII-compatible character sets is NOT
+ recommended.
+
+<span class="h2"><h2><a name="section-3">3</a> Registration Information</h2></span>
+
+ The Calendaring and Scheduling Core Object Specification is intended
+ for use as a MIME content type. However, the implementation of the
+ memo is in no way limited solely as a MIME content type.
+
+<span class="h3"><h3><a name="section-3.1">3.1</a> Content Type</h3></span>
+
+ The following text is intended to register this memo as the MIME
+ content type "text/calendar".
+
+ To: ietf-types@uninett.no
+
+ Subject: Registration of MIME content type text/calendar.
+
+ MIME media type name: text
+
+ MIME subtype name: calendar
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 8]</span>
+</pre><pre class="newpage"><a name="page-9" id="page-9" href="#page-9" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+<span class="h3"><h3><a name="section-3.2">3.2</a> Parameters</h3></span>
+
+ Required parameters: none
+
+ Optional parameters: charset, method, component and optinfo
+
+ The "charset" parameter is defined in [<a href="http://tools.ietf.org/html/rfc2046" title="" Multipurpose Internet Mail Extensions (MIME) - Part Two: Media Types"">RFC 2046</a>] for other body
+ parts. It is used to identify the default character set used within
+ the body part.
+
+ The "method" parameter is used to convey the iCalendar object method
+ or transaction semantics for the calendaring and scheduling
+ information. It also is an identifier for the restricted set of
+ properties and values that the iCalendar object consists of. The
+ parameter is to be used as a guide for applications interpreting the
+ information contained within the body part. It SHOULD NOT be used to
+ exclude or require particular pieces of information unless the
+ identified method definition specifically calls for this behavior.
+ Unless specifically forbidden by a particular method definition, a
+ text/calendar content type can contain any set of properties
+ permitted by the Calendaring and Scheduling Core Object
+ Specification. The "method" parameter MUST be the same value as that
+ specified in the "METHOD" component property in the iCalendar object.
+ If one is present, the other MUST also be present.
+
+ The value for the "method" parameter is defined as follows:
+
+ method = 1*(ALPHA / DIGIT / "-")
+ ; IANA registered iCalendar object method
+
+ The "component" parameter conveys the type of iCalendar calendar
+ component within the body part. If the iCalendar object contains more
+ than one calendar component type, then multiple component parameters
+ MUST be specified.
+
+ The value for the "component" parameter is defined as follows:
+
+ component = ("VEVENT" / "VTODO" / "VJOURNAL" / "VFREEBUSY"
+ / "VTIMEZONE" / x-name / iana-token)
+
+ The "optinfo" parameter conveys optional information about the
+ iCalendar object within the body part. This parameter can only
+ specify semantics already specified by the iCalendar object and that
+ can be otherwise determined by parsing the body part. In addition,
+ the optional information specified by this parameter MUST be
+ consistent with that information specified by the iCalendar object.
+ For example, it can be used to convey the "Attendee" response status
+ to a meeting request. The parameter value consists of a string value.
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 9]</span>
+</pre><pre class="newpage"><a name="page-10" id="page-10" href="#page-10" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ The parameter can be specified multiple times.
+
+ This parameter MAY only specify semantics already specified by the
+ iCalendar object and that can be otherwise determined by parsing the
+ body part.
+
+ The value for the "optinfo" parameter is defined as follows:
+
+ optinfo = infovalue / qinfovalue
+
+ infovalue = iana-token / x-name
+
+ qinfovalue = DQUOTE (infovalue) DQUOTE
+
+<span class="h3"><h3><a name="section-3.3">3.3</a> Content Header Fields</h3></span>
+
+ Optional content header fields: Any header fields defined by [RFC
+ 2045].
+
+<span class="h3"><h3><a name="section-3.4">3.4</a> Encoding Considerations</h3></span>
+
+ This MIME content type can contain 8bit characters, so the use of
+ quoted-printable or BASE64 MIME content-transfer-encodings might be
+ necessary when iCalendar objects are transferred across protocols
+ restricted to the 7bit repertoire. Note that a text valued property
+ in the content entity can also have content encoding of special
+ characters using a BACKSLASH character (US-ASCII decimal 92)
+ escapement technique. This means that content values can end up
+ encoded twice.
+
+<span class="h3"><h3><a name="section-3.5">3.5</a> Security Considerations</h3></span>
+
+ SPOOFING - - In this memo, the "Organizer" is the only person
+ authorized to make changes to an existing "VEVENT", "VTODO",
+ "VJOURNAL" calendar component and redistribute the updates to the
+ "Attendees". An iCalendar object that maliciously changes or cancels
+ an existing "VEVENT", "VTODO" or "VJOURNAL" or "VFREEBUSY" calendar
+ component might be constructed by someone other than the "Organizer"
+ and sent to the "Attendees". In addition in this memo, other than the
+ "Organizer", an "Attendee" of a "VEVENT", "VTODO", "VJOURNAL"
+ calendar component is the only other person authorized to update any
+ parameter associated with their "ATTENDEE" property and send it to
+ the "Organizer". An iCalendar object that maliciously changes the
+ "ATTENDEE" parameters can be constructed by someone other than the
+ real "Attendee" and sent to the "Organizer".
+
+
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 10]</span>
+</pre><pre class="newpage"><a name="page-11" id="page-11" href="#page-11" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ PROCEDURAL ALARMS - - An iCalendar object can be created that
+ contains a "VEVENT" and "VTODO" calendar component with "VALARM"
+ calendar components. The "VALARM" calendar component can be of type
+ PROCEDURE and can have an attachment containing some sort of
+ executable program. Implementations that incorporate these types of
+ alarms are subject to any virus or malicious attack that might occur
+ as a result of executing the attachment.
+
+ ATTACHMENTS - - An iCalendar object can include references to Uniform
+ Resource Locators that can be programmed resources.
+
+ Implementers and users of this memo should be aware of the network
+ security implications of accepting and parsing such information. In
+ addition, the security considerations observed by implementations of
+ electronic mail systems should be followed for this memo.
+
+<span class="h3"><h3><a name="section-3.6">3.6</a> Interoperability Considerations</h3></span>
+
+ This MIME content type is intended to define a common format for
+ conveying calendaring and scheduling information between different
+ systems. It is heavily based on the earlier [<a href="#ref-VCAL" title=""vCalendar - The Electronic Calendaring and Scheduling Exchange Format"">VCAL</a>] industry
+ specification.
+
+<span class="h3"><h3><a name="section-3.7">3.7</a> Applications Which Use This Media Type</h3></span>
+
+ This content-type is designed for widespread use by Internet
+ calendaring and scheduling applications. In addition, applications in
+ the workflow and document management area might find this content-
+ type applicable. The [<a href="#ref-ITIP" title=""iCalendar Transport-Independent Interoperability Protocol (iTIP) : Scheduling Events, Busy Time, To-dos and Journal Entries"">ITIP</a>] and [<a href="#ref-IMIP" title=""iCalendar Message-based Interoperability Protocol (IMIP)"">IMIP</a>] Internet protocols directly
+ use this content-type also. Future work on an Internet calendar
+ access protocol will utilize this content-type too.
+
+<span class="h3"><h3><a name="section-3.8">3.8</a> Additional Information</h3></span>
+
+ This memo defines this content-type.
+
+<span class="h3"><h3><a name="section-3.9">3.9</a> Magic Numbers</h3></span>
+
+ None.
+
+<span class="h3"><h3><a name="section-3.10">3.10</a> File Extensions</h3></span>
+
+ The file extension of "ics" is to be used to designate a file
+ containing (an arbitrary set of) calendaring and scheduling
+ information consistent with this MIME content type.
+
+
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 11]</span>
+</pre><pre class="newpage"><a name="page-12" id="page-12" href="#page-12" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ The file extension of "ifb" is to be used to designate a file
+ containing free or busy time information consistent with this MIME
+ content type.
+
+ Macintosh file type codes: The file type code of "iCal" is to be used
+ in Apple MacIntosh operating system environments to designate a file
+ containing calendaring and scheduling information consistent with
+ this MIME media type.
+
+ The file type code of "iFBf" is to be used in Apple MacIntosh
+ operating system environments to designate a file containing free or
+ busy time information consistent with this MIME media type.
+
+<span class="h3"><h3><a name="section-3.11">3.11</a> Contact for Further Information:</h3></span>
+
+ Frank Dawson
+ 6544 Battleford Drive
+ Raleigh, NC 27613-3502
+ 919-676-9515 (Telephone)
+ 919-676-9564 (Data/Facsimile)
+ Frank_Dawson@Lotus.com (Internet Mail)
+
+ Derik Stenerson
+ One Microsoft Way
+ Redmond, WA 98052-6399
+ 425-936-5522 (Telephone)
+ 425-936-7329 (Facsimile)
+ deriks@microsoft.com (Internet Mail)
+
+<span class="h3"><h3><a name="section-3.12">3.12</a> Intended Usage</h3></span>
+
+ COMMON
+
+<span class="h3"><h3><a name="section-3.13">3.13</a> Authors/Change Controllers</h3></span>
+
+ Frank Dawson
+ 6544 Battleford Drive
+ Raleigh, NC 27613-3502
+ 919-676-9515 (Telephone)
+ 919-676-9564 (Data/Facsimile)
+ Frank_Dawson@Lotus.com (Internet Mail)
+
+ Derik Stenerson
+ One Microsoft Way
+ Redmond, WA 98052-6399
+ 425-936-5522 (Telephone)
+ 425-936-7329 (Facsimile)
+ deriks@microsoft.com (Internet Mail)
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 12]</span>
+</pre><pre class="newpage"><a name="page-13" id="page-13" href="#page-13" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+<span class="h2"><h2><a name="section-4">4</a> iCalendar Object Specification</h2></span>
+
+ The following sections define the details of a Calendaring and
+ Scheduling Core Object Specification. This information is intended to
+ be an integral part of the MIME content type registration. In
+ addition, this information can be used independent of such content
+ registration. In particular, this memo has direct applicability for
+ use as a calendaring and scheduling exchange format in file-, memory-
+ or network-based transport mechanisms.
+
+<span class="h3"><h3><a name="section-4.1">4.1</a> Content Lines</h3></span>
+
+ The iCalendar object is organized into individual lines of text,
+ called content lines. Content lines are delimited by a line break,
+ which is a CRLF sequence (US-ASCII decimal 13, followed by US-ASCII
+ decimal 10).
+
+ Lines of text SHOULD NOT be longer than 75 octets, excluding the line
+ break. Long content lines SHOULD be split into a multiple line
+ representations using a line "folding" technique. That is, a long
+ line can be split between any two characters by inserting a CRLF
+ immediately followed by a single linear white space character (i.e.,
+ SPACE, US-ASCII decimal 32 or HTAB, US-ASCII decimal 9). Any sequence
+ of CRLF followed immediately by a single linear white space character
+ is ignored (i.e., removed) when processing the content type.
+
+ For example the line:
+
+ DESCRIPTION:This is a long description that exists on a long line.
+
+ Can be represented as:
+
+ DESCRIPTION:This is a lo
+ ng description
+ that exists on a long line.
+
+ The process of moving from this folded multiple line representation
+ to its single line representation is called "unfolding". Unfolding is
+ accomplished by removing the CRLF character and the linear white
+ space character that immediately follows.
+
+ When parsing a content line, folded lines MUST first be unfolded
+ according to the unfolding procedure described above. When generating
+ a content line, lines longer than 75 octets SHOULD be folded
+ according to the folding procedure described above.
+
+
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 13]</span>
+</pre><pre class="newpage"><a name="page-14" id="page-14" href="#page-14" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ The content information associated with an iCalendar object is
+ formatted using a syntax similar to that defined by [<a href="http://tools.ietf.org/html/rfc2425" title=""A MIME Content-Type for Directory Information"">RFC 2425</a>]. That
+ is, the content information consists of CRLF-separated content lines.
+
+ The following notation defines the lines of content in an iCalendar
+ object:
+
+ contentline = name *(";" param ) ":" value CRLF
+ ; This ABNF is just a general definition for an initial parsing
+ ; of the content line into its property name, parameter list,
+ ; and value string
+
+ ; When parsing a content line, folded lines MUST first
+ ; be unfolded according to the unfolding procedure
+ ; described above. When generating a content line, lines
+ ; longer than 75 octets SHOULD be folded according to
+ ; the folding procedure described above.
+
+ name = x-name / iana-token
+
+ iana-token = 1*(ALPHA / DIGIT / "-")
+ ; iCalendar identifier registered with IANA
+
+ x-name = "X-" [vendorid "-"] 1*(ALPHA / DIGIT / "-")
+ ; Reservered for experimental use. Not intended for use in
+ ; released products.
+
+ vendorid = 3*(ALPHA / DIGIT) ;Vendor identification
+
+ param = param-name "=" param-value
+ *("," param-value)
+ ; Each property defines the specific ABNF for the parameters
+ ; allowed on the property. Refer to specific properties for
+ ; precise parameter ABNF.
+
+ param-name = iana-token / x-token
+
+ param-value = paramtext / quoted-string
+
+ paramtext = *SAFE-CHAR
+
+ value = *VALUE-CHAR
+
+ quoted-string = DQUOTE *QSAFE-CHAR DQUOTE
+
+ NON-US-ASCII = %x80-F8
+ ; Use restricted by charset parameter
+ ; on outer MIME object (UTF-8 preferred)
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 14]</span>
+</pre><pre class="newpage"><a name="page-15" id="page-15" href="#page-15" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ QSAFE-CHAR = WSP / %x21 / %x23-7E / NON-US-ASCII
+ ; Any character except CTLs and DQUOTE
+
+ SAFE-CHAR = WSP / %x21 / %x23-2B / %x2D-39 / %x3C-7E
+ / NON-US-ASCII
+ ; Any character except CTLs, DQUOTE, ";", ":", ","
+
+ VALUE-CHAR = WSP / %x21-7E / NON-US-ASCII
+ ; Any textual character
+
+ CR = %x0D
+ ; carriage return
+
+ LF = %x0A
+ ; line feed
+
+ CRLF = CR LF
+ ; Internet standard newline
+
+ CTL = %x00-08 / %x0A-1F / %x7F
+ ; Controls
+
+ ALPHA = %x41-5A / %x61-7A ; A-Z / a-z
+
+ DIGIT = %x30-39
+ ; 0-9
+
+ DQUOTE = %x22
+ ; Quotation Mark
+
+ WSP = SPACE / HTAB
+
+ SPACE = %x20
+
+ HTAB = %x09
+
+ The property value component of a content line has a format that is
+ property specific. Refer to the section describing each property for
+ a definition of this format.
+
+ All names of properties, property parameters, enumerated property
+ values and property parameter values are case-insensitive. However,
+ all other property values are case-sensitive, unless otherwise
+ stated.
+
+
+
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 15]</span>
+</pre><pre class="newpage"><a name="page-16" id="page-16" href="#page-16" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+<span class="h4"><h4><a name="section-4.1.1">4.1.1</a> List and Field Separators</h4></span>
+
+ Some properties and parameters allow a list of values. Values in a
+ list of values MUST be separated by a COMMA character (US-ASCII
+ decimal 44). There is no significance to the order of values in a
+ list. For those parameter values (such as those that specify URI
+ values) that are specified in quoted-strings, the individual quoted-
+ strings are separated by a COMMA character (US-ASCII decimal 44).
+
+ Some property values are defined in terms of multiple parts. These
+ structured property values MUST have their value parts separated by a
+ SEMICOLON character (US-ASCII decimal 59).
+
+ Some properties allow a list of parameters. Each property parameter
+ in a list of property parameters MUST be separated by a SEMICOLON
+ character (US-ASCII decimal 59).
+
+ Property parameters with values containing a COLON, a SEMICOLON or a
+ COMMA character MUST be placed in quoted text.
+
+ For example, in the following properties a SEMICOLON is used to
+ separate property parameters from each other, and a COMMA is used to
+ separate property values in a value list.
+
+ ATTENDEE;RSVP=TRUE;ROLE=REQ-PARTICIPANT:MAILTO:
+ jsmith@host.com
+
+ RDATE;VALUE=DATE:19970304,19970504,19970704,19970904
+
+<span class="h4"><h4><a name="section-4.1.2">4.1.2</a> Multiple Values</h4></span>
+
+ Some properties defined in the iCalendar object can have multiple
+ values. The general rule for encoding multi-valued items is to simply
+ create a new content line for each value, including the property
+ name. However, it should be noted that some properties support
+ encoding multiple values in a single property by separating the
+ values with a COMMA character (US-ASCII decimal 44). Individual
+ property definitions should be consulted for determining whether a
+ specific property allows multiple values and in which of these two
+ forms.
+
+<span class="h4"><h4><a name="section-4.1.3">4.1.3</a> Binary Content</h4></span>
+
+ Binary content information in an iCalendar object SHOULD be
+ referenced using a URI within a property value. That is the binary
+ content information SHOULD be placed in an external MIME entity that
+ can be referenced by a URI from within the iCalendar object. In
+ applications where this is not feasible, binary content information
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 16]</span>
+</pre><pre class="newpage"><a name="page-17" id="page-17" href="#page-17" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ can be included within an iCalendar object, but only after first
+ encoding it into text using the "BASE64" encoding method defined in
+ [<a href="http://tools.ietf.org/html/rfc2045" title="" Multipurpose Internet Mail Extensions (MIME) - Part One: Format of Internet Message Bodies"">RFC 2045</a>]. Inline binary contact SHOULD only be used in applications
+ whose special circumstances demand that an iCalendar object be
+ expressed as a single entity. A property containing inline binary
+ content information MUST specify the "ENCODING" property parameter.
+ Binary content information placed external to the iCalendar object
+ MUST be referenced by a uniform resource identifier (URI).
+
+ The following example specifies an "ATTACH" property that references
+ an attachment external to the iCalendar object with a URI reference:
+
+ ATTACH:http://xyz.com/public/quarterly-report.doc
+
+ The following example specifies an "ATTACH" property with inline
+ binary encoded content information:
+
+ ATTACH;FMTTYPE=image/basic;ENCODING=BASE64;VALUE=BINARY:
+ MIICajCCAdOgAwIBAgICBEUwDQYJKoZIhvcNAQEEBQAwdzELMAkGA1U
+ EBhMCVVMxLDAqBgNVBAoTI05ldHNjYXBlIENvbW11bmljYXRpb25zIE
+ <...remainder of "BASE64" encoded binary data...>
+
+<span class="h4"><h4><a name="section-4.1.4">4.1.4</a> Character Set</h4></span>
+
+ There is not a property parameter to declare the character set used
+ in a property value. The default character set for an iCalendar
+ object is UTF-8 as defined in [<a href="http://tools.ietf.org/html/rfc2279" title=""UTF-8, a transformation format of ISO 10646"">RFC 2279</a>].
+
+ The "charset" Content-Type parameter can be used in MIME transports
+ to specify any other IANA registered character set.
+
+<span class="h3"><h3><a name="section-4.2">4.2</a> Property Parameters</h3></span>
+
+ A property can have attributes associated with it. These "property
+ parameters" contain meta-information about the property or the
+ property value. Property parameters are provided to specify such
+ information as the location of an alternate text representation for a
+ property value, the language of a text property value, the data type
+ of the property value and other attributes.
+
+ Property parameter values that contain the COLON (US-ASCII decimal
+ 58), SEMICOLON (US-ASCII decimal 59) or COMMA (US-ASCII decimal 44)
+ character separators MUST be specified as quoted-string text values.
+ Property parameter values MUST NOT contain the DOUBLE-QUOTE (US-ASCII
+ decimal 22) character. The DOUBLE-QUOTE (US-ASCII decimal 22)
+ character is used as a delimiter for parameter values that contain
+ restricted characters or URI text. For example:
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 17]</span>
+</pre><pre class="newpage"><a name="page-18" id="page-18" href="#page-18" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ DESCRIPTION;ALTREP="http://www.wiz.org":The Fall'98 Wild Wizards
+ Conference - - Las Vegas, NV, USA
+
+ Property parameter values that are not in quoted strings are case
+ insensitive.
+
+ The general property parameters defined by this memo are defined by
+ the following notation:
+
+ parameter = altrepparam ; Alternate text representation
+ / cnparam ; Common name
+ / cutypeparam ; Calendar user type
+ / delfromparam ; Delegator
+ / deltoparam ; Delegatee
+ / dirparam ; Directory entry
+ / encodingparam ; Inline encoding
+ / fmttypeparam ; Format type
+ / fbtypeparam ; Free/busy time type
+ / languageparam ; Language for text
+ / memberparam ; Group or list membership
+ / partstatparam ; Participation status
+ / rangeparam ; Recurrence identifier range
+ / trigrelparam ; Alarm trigger relationship
+ / reltypeparam ; Relationship type
+ / roleparam ; Participation role
+ / rsvpparam ; RSVP expectation
+ / sentbyparam ; Sent by
+ / tzidparam ; Reference to time zone object
+ / valuetypeparam ; Property value data type
+ / ianaparam
+ ; Some other IANA registered iCalendar parameter.
+ / xparam
+ ; A non-standard, experimental parameter.
+
+ ianaparam = iana-token "=" param-value *("," param-value)
+
+ xparam =x-name "=" param-value *("," param-value)
+
+<span class="h4"><h4><a name="section-4.2.1">4.2.1</a> Alternate Text Representation</h4></span>
+
+ Parameter Name: ALTREP
+
+ Purpose: To specify an alternate text representation for the property
+ value.
+
+ Format Definition: The property parameter is defined by the following
+ notation:
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 18]</span>
+</pre><pre class="newpage"><a name="page-19" id="page-19" href="#page-19" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ altrepparam = "ALTREP" "=" DQUOTE uri DQUOTE
+
+ Description: The parameter specifies a URI that points to an
+ alternate representation for a textual property value. A property
+ specifying this parameter MUST also include a value that reflects the
+ default representation of the text value. The individual URI
+ parameter values MUST each be specified in a quoted-string.
+
+ Example:
+
+ DESCRIPTION;ALTREP="CID:<part3.msg.970415T083000@host.com>":Project
+ XYZ Review Meeting will include the following agenda items: (a)
+ Market Overview, (b) Finances, (c) Project Management
+
+ The "ALTREP" property parameter value might point to a "text/html"
+ content portion.
+
+ Content-Type:text/html
+ Content-Id:<part3.msg.970415T083000@host.com>
+
+ <html><body>
+ <p><b>Project XYZ Review Meeting</b> will include the following
+ agenda items:<ol><li>Market
+ Overview</li><li>Finances</li><li>Project Management</li></ol></p>
+ </body></html>
+
+<span class="h4"><h4><a name="section-4.2.2">4.2.2</a> Common Name</h4></span>
+
+ Parameter Name: CN
+
+ Purpose: To specify the common name to be associated with the
+ calendar user specified by the property.
+
+ Format Definition: The property parameter is defined by the following
+ notation:
+
+ cnparam = "CN" "=" param-value
+
+ Description: This parameter can be specified on properties with a
+ CAL-ADDRESS value type. The parameter specifies the common name to be
+ associated with the calendar user specified by the property. The
+ parameter value is text. The parameter value can be used for display
+ text to be associated with the calendar address specified by the
+ property.
+
+
+
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 19]</span>
+</pre><pre class="newpage"><a name="page-20" id="page-20" href="#page-20" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ Example:
+
+ ORGANIZER;CN="John Smith":MAILTO:jsmith@host.com
+
+<span class="h4"><h4><a name="section-4.2.3">4.2.3</a> Calendar User Type</h4></span>
+
+ Parameter Name: CUTYPE
+
+ Purpose: To specify the type of calendar user specified by the
+ property.
+
+ Format Definition: The property parameter is defined by the following
+ notation:
+
+ cutypeparam = "CUTYPE" "="
+ ("INDIVIDUAL" ; An individual
+ / "GROUP" ; A group of individuals
+ / "RESOURCE" ; A physical resource
+ / "ROOM" ; A room resource
+ / "UNKNOWN" ; Otherwise not known
+ / x-name ; Experimental type
+ / iana-token) ; Other IANA registered
+ ; type
+ ; Default is INDIVIDUAL
+
+ Description: This parameter can be specified on properties with a
+ CAL-ADDRESS value type. The parameter identifies the type of calendar
+ user specified by the property. If not specified on a property that
+ allows this parameter, the default is INDIVIDUAL.
+
+ Example:
+
+ ATTENDEE;CUTYPE=GROUP:MAILTO:ietf-calsch@imc.org
+
+<span class="h4"><h4><a name="section-4.2.4">4.2.4</a> Delegators</h4></span>
+
+ Parameter Name: DELEGATED-FROM
+
+ Purpose: To specify the calendar users that have delegated their
+ participation to the calendar user specified by the property.
+
+ Format Definition: The property parameter is defined by the following
+ notation:
+
+ delfromparam = "DELEGATED-FROM" "=" DQUOTE cal-address DQUOTE
+ *("," DQUOTE cal-address DQUOTE)
+
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 20]</span>
+</pre><pre class="newpage"><a name="page-21" id="page-21" href="#page-21" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ Description: This parameter can be specified on properties with a
+ CAL-ADDRESS value type. This parameter can be specified on a property
+ that has a value type of calendar address. This parameter specifies
+ those calendar uses that have delegated their participation in a
+ group scheduled event or to-do to the calendar user specified by the
+ property. The value MUST be a MAILTO URI as defined in [<a href="http://tools.ietf.org/html/rfc1738" title=""Uniform Resource Locators (URL)"">RFC 1738</a>].
+ The individual calendar address parameter values MUST each be
+ specified in a quoted-string.
+
+ Example:
+
+ ATTENDEE;DELEGATED-FROM="MAILTO:jsmith@host.com":MAILTO:
+ jdoe@host.com
+
+<span class="h4"><h4><a name="section-4.2.5">4.2.5</a> Delegatees</h4></span>
+
+ Parameter Name: DELEGATED-TO
+
+ Purpose: To specify the calendar users to whom the calendar user
+ specified by the property has delegated participation.
+
+ Format Definition: The property parameter is defined by the following
+ notation:
+
+ deltoparam = "DELEGATED-TO" "=" DQUOTE cal-address DQUOTE
+ *("," DQUOTE cal-address DQUOTE)
+
+ Description: This parameter can be specified on properties with a
+ CAL-ADDRESS value type. This parameter specifies those calendar users
+ whom have been delegated participation in a group scheduled event or
+ to-do by the calendar user specified by the property. The value MUST
+ be a MAILTO URI as defined in [<a href="http://tools.ietf.org/html/rfc1738" title=""Uniform Resource Locators (URL)"">RFC 1738</a>]. The individual calendar
+ address parameter values MUST each be specified in a quoted-string.
+
+ Example:
+
+ ATTENDEE;DELEGATED-TO="MAILTO:jdoe@host.com","MAILTO:jqpublic@
+ host.com":MAILTO:jsmith@host.com
+
+<span class="h4"><h4><a name="section-4.2.6">4.2.6</a> Directory Entry Reference</h4></span>
+
+ Parameter Name: DIR
+
+ Purpose: To specify reference to a directory entry associated with
+ the calendar user specified by the property.
+
+ Format Definition: The property parameter is defined by the following
+ notation:
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 21]</span>
+</pre><pre class="newpage"><a name="page-22" id="page-22" href="#page-22" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ dirparam = "DIR" "=" DQUOTE uri DQUOTE
+
+ Description: This parameter can be specified on properties with a
+ CAL-ADDRESS value type. The parameter specifies a reference to the
+ directory entry associated with the calendar user specified by the
+ property. The parameter value is a URI. The individual URI parameter
+ values MUST each be specified in a quoted-string.
+
+ Example:
+
+ ORGANIZER;DIR="ldap://host.com:6666/o=eDABC%20Industries,c=3DUS??
+ (cn=3DBJim%20Dolittle)":MAILTO:jimdo@host1.com
+
+<span class="h4"><h4><a name="section-4.2.7">4.2.7</a> Inline Encoding</h4></span>
+
+ Parameter Name: ENCODING
+
+ Purpose: To specify an alternate inline encoding for the property
+ value.
+
+ Format Definition: The property parameter is defined by the following
+ notation:
+
+ encodingparam = "ENCODING" "="
+ ("8BIT"
+ ; "8bit" text encoding is defined in [<a href="http://tools.ietf.org/html/rfc2045" title="" Multipurpose Internet Mail Extensions (MIME) - Part One: Format of Internet Message Bodies"">RFC 2045</a>]
+ / "BASE64"
+ ; "BASE64" binary encoding format is defined in [<a href="http://tools.ietf.org/html/rfc2045" title="" Multipurpose Internet Mail Extensions (MIME) - Part One: Format of Internet Message Bodies"">RFC 2045</a>]
+ / iana-token
+ ; Some other IANA registered iCalendar encoding type
+ / x-name)
+ ; A non-standard, experimental encoding type
+
+ Description: The property parameter identifies the inline encoding
+ used in a property value. The default encoding is "8BIT",
+ corresponding to a property value consisting of text. The "BASE64"
+ encoding type corresponds to a property value encoded using the
+ "BASE64" encoding defined in [<a href="http://tools.ietf.org/html/rfc2045" title="" Multipurpose Internet Mail Extensions (MIME) - Part One: Format of Internet Message Bodies"">RFC 2045</a>].
+
+ If the value type parameter is ";VALUE=BINARY", then the inline
+ encoding parameter MUST be specified with the value
+ ";ENCODING=BASE64".
+
+
+
+
+
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 22]</span>
+</pre><pre class="newpage"><a name="page-23" id="page-23" href="#page-23" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ Example:
+
+ ATTACH;FMTYPE=IMAGE/JPEG;ENCODING=BASE64;VALUE=BINARY:MIICajC
+ CAdOgAwIBAgICBEUwDQYJKoZIhvcNAQEEBQAwdzELMAkGA1UEBhMCVVMxLDA
+ qBgNVBAoTI05ldHNjYXBlIENvbW11bmljYXRpb25zIENvcnBvcmF0aW9uMRw
+ <...remainder of "BASE64" encoded binary data...>
+
+<span class="h4"><h4><a name="section-4.2.8">4.2.8</a> Format Type</h4></span>
+
+ Parameter Name: FMTTYPE
+
+ Purpose: To specify the content type of a referenced object.
+
+ Format Definition: The property parameter is defined by the following
+ notation:
+
+ fmttypeparam = "FMTTYPE" "=" iana-token
+ ; A IANA registered content type
+ / x-name
+ ; A non-standard content type
+
+ Description: This parameter can be specified on properties that are
+ used to reference an object. The parameter specifies the content type
+ of the referenced object. For example, on the "ATTACH" property, a
+ FTP type URI value does not, by itself, necessarily convey the type
+ of content associated with the resource. The parameter value MUST be
+ the TEXT for either an IANA registered content type or a non-standard
+ content type.
+
+ Example:
+
+ ATTACH;FMTTYPE=application/binary:ftp://domain.com/pub/docs/
+ agenda.doc
+
+<span class="h4"><h4><a name="section-4.2.9">4.2.9</a> Free/Busy Time Type</h4></span>
+
+ Parameter Name: FBTYPE
+
+ Purpose: To specify the free or busy time type.
+
+ Format Definition: The property parameter is defined by the following
+ notation:
+
+ fbtypeparam = "FBTYPE" "=" ("FREE" / "BUSY"
+ / "BUSY-UNAVAILABLE" / "BUSY-TENTATIVE"
+ / x-name
+ ; Some experimental iCalendar data type.
+ / iana-token)
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 23]</span>
+</pre><pre class="newpage"><a name="page-24" id="page-24" href="#page-24" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ ; Some other IANA registered iCalendar data type.
+
+ Description: The parameter specifies the free or busy time type. The
+ value FREE indicates that the time interval is free for scheduling.
+ The value BUSY indicates that the time interval is busy because one
+ or more events have been scheduled for that interval. The value
+ BUSY-UNAVAILABLE indicates that the time interval is busy and that
+ the interval can not be scheduled. The value BUSY-TENTATIVE indicates
+ that the time interval is busy because one or more events have been
+ tentatively scheduled for that interval. If not specified on a
+ property that allows this parameter, the default is BUSY.
+
+ Example: The following is an example of this parameter on a FREEBUSY
+ property.
+
+ FREEBUSY;FBTYPE=BUSY:19980415T133000Z/19980415T170000Z
+
+<span class="h4"><h4><a name="section-4.2.10">4.2.10</a> Language</h4></span>
+
+ Parameter Name: LANGUAGE
+
+ Purpose: To specify the language for text values in a property or
+ property parameter.
+
+ Format Definition: The property parameter is defined by the following
+ notation:
+
+ languageparam = "LANGUAGE" "=" language
+
+ language = <Text identifying a language, as defined in [<a href="http://tools.ietf.org/html/rfc1766" title=""Tags for the Identification of Languages"">RFC 1766</a>]>
+
+ Description: This parameter can be specified on properties with a
+ text value type. The parameter identifies the language of the text in
+ the property or property parameter value. The value of the "language"
+ property parameter is that defined in [<a href="http://tools.ietf.org/html/rfc1766" title=""Tags for the Identification of Languages"">RFC 1766</a>].
+
+ For transport in a MIME entity, the Content-Language header field can
+ be used to set the default language for the entire body part.
+ Otherwise, no default language is assumed.
+
+ Example:
+
+ SUMMARY;LANGUAGE=us-EN:Company Holiday Party
+
+ LOCATION;LANGUAGE=en:Germany
+ LOCATION;LANGUAGE=no:Tyskland
+
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 24]</span>
+</pre><pre class="newpage"><a name="page-25" id="page-25" href="#page-25" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ The following example makes use of the Quoted-Printable encoding in
+ order to represent non-ASCII characters.
+
+ LOCATION;LANGUAGE=da:K=F8benhavn
+ LOCATION;LANGUAGE=en:Copenhagen
+
+<span class="h4"><h4><a name="section-4.2.11">4.2.11</a> Group or List Membership</h4></span>
+
+ Parameter Name: MEMBER
+
+ Purpose: To specify the group or list membership of the calendar user
+ specified by the property.
+
+ Format Definition: The property parameter is defined by the following
+ notation:
+
+ memberparam = "MEMBER" "=" DQUOTE cal-address DQUOTE
+ *("," DQUOTE cal-address DQUOTE)
+
+ Description: This parameter can be specified on properties with a
+ CAL-ADDRESS value type. The parameter identifies the groups or list
+ membership for the calendar user specified by the property. The
+ parameter value either a single calendar address in a quoted-string
+ or a COMMA character (US-ASCII decimal 44) list of calendar
+ addresses, each in a quoted-string. The individual calendar address
+ parameter values MUST each be specified in a quoted-string.
+
+ Example:
+
+ ATTENDEE;MEMBER="MAILTO:ietf-calsch@imc.org":MAILTO:jsmith@host.com
+
+ ATTENDEE;MEMBER="MAILTO:projectA@host.com","MAILTO:projectB@host.
+ com":MAILTO:janedoe@host.com
+
+<span class="h4"><h4><a name="section-4.2.12">4.2.12</a> Participation Status</h4></span>
+
+ Parameter Name: PARTSTAT
+
+ Purpose: To specify the participation status for the calendar user
+ specified by the property.
+
+ Format Definition: The property parameter is defined by the following
+ notation:
+
+ partstatparam = "PARTSTAT" "="
+ ("NEEDS-ACTION" ; Event needs action
+ / "ACCEPTED" ; Event accepted
+ / "DECLINED" ; Event declined
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 25]</span>
+</pre><pre class="newpage"><a name="page-26" id="page-26" href="#page-26" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ / "TENTATIVE" ; Event tentatively
+ ; accepted
+ / "DELEGATED" ; Event delegated
+ / x-name ; Experimental status
+ / iana-token) ; Other IANA registered
+ ; status
+ ; These are the participation statuses for a "VEVENT". Default is
+ ; NEEDS-ACTION
+ partstatparam /= "PARTSTAT" "="
+ ("NEEDS-ACTION" ; To-do needs action
+ / "ACCEPTED" ; To-do accepted
+ / "DECLINED" ; To-do declined
+ / "TENTATIVE" ; To-do tentatively
+ ; accepted
+ / "DELEGATED" ; To-do delegated
+ / "COMPLETED" ; To-do completed.
+ ; COMPLETED property has
+ ;date/time completed.
+ / "IN-PROCESS" ; To-do in process of
+ ; being completed
+ / x-name ; Experimental status
+ / iana-token) ; Other IANA registered
+ ; status
+ ; These are the participation statuses for a "VTODO". Default is
+ ; NEEDS-ACTION
+
+ partstatparam /= "PARTSTAT" "="
+ ("NEEDS-ACTION" ; Journal needs action
+ / "ACCEPTED" ; Journal accepted
+ / "DECLINED" ; Journal declined
+ / x-name ; Experimental status
+ / iana-token) ; Other IANA registered
+ ; status
+ ; These are the participation statuses for a "VJOURNAL". Default is
+ ; NEEDS-ACTION
+
+ Description: This parameter can be specified on properties with a
+ CAL-ADDRESS value type. The parameter identifies the participation
+ status for the calendar user specified by the property value. The
+ parameter values differ depending on whether they are associated with
+ a group scheduled "VEVENT", "VTODO" or "VJOURNAL". The values MUST
+ match one of the values allowed for the given calendar component. If
+ not specified on a property that allows this parameter, the default
+ value is NEEDS-ACTION.
+
+ Example:
+
+ ATTENDEE;PARTSTAT=DECLINED:MAILTO:jsmith@host.com
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 26]</span>
+</pre><pre class="newpage"><a name="page-27" id="page-27" href="#page-27" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+<span class="h4"><h4><a name="section-4.2.13">4.2.13</a> Recurrence Identifier Range</h4></span>
+
+ Parameter Name: RANGE
+
+ Purpose: To specify the effective range of recurrence instances from
+ the instance specified by the recurrence identifier specified by the
+ property.
+
+ Format Definition: The property parameter is defined by the following
+ notation:
+
+ rangeparam = "RANGE" "=" ("THISANDPRIOR"
+ ; To specify all instances prior to the recurrence identifier
+ / "THISANDFUTURE")
+ ; To specify the instance specified by the recurrence identifier
+ ; and all subsequent recurrence instances
+
+ Description: The parameter can be specified on a property that
+ specifies a recurrence identifier. The parameter specifies the
+ effective range of recurrence instances that is specified by the
+ property. The effective range is from the recurrence identified
+ specified by the property. If this parameter is not specified an
+ allowed property, then the default range is the single instance
+ specified by the recurrence identifier value of the property. The
+ parameter value can be "THISANDPRIOR" to indicate a range defined by
+ the recurrence identified value of the property and all prior
+ instances. The parameter value can also be "THISANDFUTURE" to
+ indicate a range defined by the recurrence identifier and all
+ subsequent instances.
+
+ Example:
+
+ RECURRENCE-ID;RANGE=THISANDPRIOR:19980401T133000Z
+
+<span class="h4"><h4><a name="section-4.2.14">4.2.14</a> Alarm Trigger Relationship</h4></span>
+
+ Parameter Name: RELATED
+
+ Purpose: To specify the relationship of the alarm trigger with
+ respect to the start or end of the calendar component.
+
+ Format Definition: The property parameter is defined by the following
+ notation:
+
+ trigrelparam = "RELATED" "="
+ ("START" ; Trigger off of start
+ / "END") ; Trigger off of end
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 27]</span>
+</pre><pre class="newpage"><a name="page-28" id="page-28" href="#page-28" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ Description: The parameter can be specified on properties that
+ specify an alarm trigger with a DURATION value type. The parameter
+ specifies whether the alarm will trigger relative to the start or end
+ of the calendar component. The parameter value START will set the
+ alarm to trigger off the start of the calendar component; the
+ parameter value END will set the alarm to trigger off the end of the
+ calendar component. If the parameter is not specified on an allowable
+ property, then the default is START.
+
+ Example:
+
+ TRIGGER;RELATED=END:PT5M
+
+<span class="h4"><h4><a name="section-4.2.15">4.2.15</a> Relationship Type</h4></span>
+
+ Parameter Name: RELTYPE
+
+ Purpose: To specify the type of hierarchical relationship associated
+ with the calendar component specified by the property.
+
+ Format Definition: The property parameter is defined by the following
+ notation:
+
+ reltypeparam = "RELTYPE" "="
+ ("PARENT" ; Parent relationship. Default.
+ / "CHILD" ; Child relationship
+ / "SIBLING ; Sibling relationship
+ / iana-token ; Some other IANA registered
+ ; iCalendar relationship type
+ / x-name) ; A non-standard, experimental
+ ; relationship type
+
+ Description: This parameter can be specified on a property that
+ references another related calendar. The parameter specifies the
+ hierarchical relationship type of the calendar component referenced
+ by the property. The parameter value can be PARENT, to indicate that
+ the referenced calendar component is a superior of calendar
+ component; CHILD to indicate that the referenced calendar component
+ is a subordinate of the calendar component; SIBLING to indicate that
+ the referenced calendar component is a peer of the calendar
+ component. If this parameter is not specified on an allowable
+ property, the default relationship type is PARENT.
+
+ Example:
+
+ RELATED-TO;RELTYPE=SIBLING:<19960401-080045-4000F192713@host.com>
+
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 28]</span>
+</pre><pre class="newpage"><a name="page-29" id="page-29" href="#page-29" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+<span class="h4"><h4><a name="section-4.2.16">4.2.16</a> Participation Role</h4></span>
+
+ Parameter Name: ROLE
+
+ Purpose: To specify the participation role for the calendar user
+ specified by the property.
+
+ Format Definition: The property parameter is defined by the following
+ notation:
+
+ roleparam = "ROLE" "="
+ ("CHAIR" ; Indicates chair of the
+ ; calendar entity
+ / "REQ-PARTICIPANT" ; Indicates a participant whose
+ ; participation is required
+ / "OPT-PARTICIPANT" ; Indicates a participant whose
+ ; participation is optional
+ / "NON-PARTICIPANT" ; Indicates a participant who is
+ ; copied for information
+ ; purposes only
+ / x-name ; Experimental role
+ / iana-token) ; Other IANA role
+ ; Default is REQ-PARTICIPANT
+
+ Description: This parameter can be specified on properties with a
+ CAL-ADDRESS value type. The parameter specifies the participation
+ role for the calendar user specified by the property in the group
+ schedule calendar component. If not specified on a property that
+ allows this parameter, the default value is REQ-PARTICIPANT.
+
+ Example:
+
+ ATTENDEE;ROLE=CHAIR:MAILTO:mrbig@host.com
+
+<span class="h4"><h4><a name="section-4.2.17">4.2.17</a> RSVP Expectation</h4></span>
+
+ Parameter Name: RSVP
+
+ Purpose: To specify whether there is an expectation of a favor of a
+ reply from the calendar user specified by the property value.
+
+ Format Definition: The property parameter is defined by the following
+ notation:
+
+ rsvpparam = "RSVP" "=" ("TRUE" / "FALSE")
+ ; Default is FALSE
+
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 29]</span>
+</pre><pre class="newpage"><a name="page-30" id="page-30" href="#page-30" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ Description: This parameter can be specified on properties with a
+ CAL-ADDRESS value type. The parameter identifies the expectation of a
+ reply from the calendar user specified by the property value. This
+ parameter is used by the "Organizer" to request a participation
+ status reply from an "Attendee" of a group scheduled event or to-do.
+ If not specified on a property that allows this parameter, the
+ default value is FALSE.
+
+ Example:
+
+ ATTENDEE;RSVP=TRUE:MAILTO:jsmith@host.com
+
+<span class="h4"><h4><a name="section-4.2.18">4.2.18</a> Sent By</h4></span>
+
+ Parameter Name: SENT-BY
+
+ Purpose: To specify the calendar user that is acting on behalf of the
+ calendar user specified by the property.
+
+ Format Definition: The property parameter is defined by the following
+ notation:
+
+ sentbyparam = "SENT-BY" "=" DQUOTE cal-address DQUOTE
+
+ Description: This parameter can be specified on properties with a
+ CAL-ADDRESS value type. The parameter specifies the calendar user
+ that is acting on behalf of the calendar user specified by the
+ property. The parameter value MUST be a MAILTO URI as defined in [RFC
+ 1738]. The individual calendar address parameter values MUST each be
+ specified in a quoted-string.
+
+ Example:
+
+ ORGANIZER;SENT-BY:"MAILTO:sray@host.com":MAILTO:jsmith@host.com
+
+<span class="h4"><h4><a name="section-4.2.19">4.2.19</a> Time Zone Identifier</h4></span>
+
+ Parameter Name: TZID
+
+ Purpose: To specify the identifier for the time zone definition for a
+ time component in the property value.
+
+ Format Definition: This property parameter is defined by the
+ following notation:
+
+ tzidparam = "TZID" "=" [<a href="#ref-tzidprefix">tzidprefix</a>] paramtext CRLF
+
+ tzidprefix = "/"
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 30]</span>
+</pre><pre class="newpage"><a name="page-31" id="page-31" href="#page-31" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ Description: The parameter MUST be specified on the "DTSTART",
+ "DTEND", "DUE", "EXDATE" and "RDATE" properties when either a DATE-
+ TIME or TIME value type is specified and when the value is not either
+ a UTC or a "floating" time. Refer to the DATE-TIME or TIME value type
+ definition for a description of UTC and "floating time" formats. This
+ property parameter specifies a text value which uniquely identifies
+ the "VTIMEZONE" calendar component to be used when evaluating the
+ time portion of the property. The value of the TZID property
+ parameter will be equal to the value of the TZID property for the
+ matching time zone definition. An individual "VTIMEZONE" calendar
+ component MUST be specified for each unique "TZID" parameter value
+ specified in the iCalendar object.
+
+ The parameter MUST be specified on properties with a DATE-TIME value
+ if the DATE-TIME is not either a UTC or a "floating" time.
+
+ The presence of the SOLIDUS character (US-ASCII decimal 47) as a
+ prefix, indicates that this TZID represents a unique ID in a globally
+ defined time zone registry (when such registry is defined).
+
+ Note: This document does not define a naming convention for time
+ zone identifiers. Implementers may want to use the naming
+ conventions defined in existing time zone specifications such as
+ the public-domain Olson database [<a href="#ref-TZ" title=""ftp://elsie.nci.nih.gov/pub/"">TZ</a>]. The specification of
+ globally unique time zone identifiers is not addressed by this
+ document and is left for future study.
+
+ The following are examples of this property parameter:
+
+ DTSTART;TZID=US-Eastern:19980119T020000
+
+ DTEND;TZID=US-Eastern:19980119T030000
+
+ The TZID property parameter MUST NOT be applied to DATE-TIME or TIME
+ properties whose time values are specified in UTC.
+
+ The use of local time in a DATE-TIME or TIME value without the TZID
+ property parameter is to be interpreted as a local time value,
+ regardless of the existence of "VTIMEZONE" calendar components in the
+ iCalendar object.
+
+ For more information see the sections on the data types DATE-TIME and
+ TIME.
+
+
+
+
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 31]</span>
+</pre><pre class="newpage"><a name="page-32" id="page-32" href="#page-32" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+<span class="h4"><h4><a name="section-4.2.20">4.2.20</a> Value Data Types</h4></span>
+
+ Parameter Name: VALUE
+
+ Purpose: To explicitly specify the data type format for a property
+ value.
+
+ Format Definition: The "VALUE" property parameter is defined by the
+ following notation:
+
+ valuetypeparam = "VALUE" "=" valuetype
+
+ valuetype = ("BINARY"
+ / "BOOLEAN"
+ / "CAL-ADDRESS"
+ / "DATE"
+ / "DATE-TIME"
+ / "DURATION"
+ / "FLOAT"
+ / "INTEGER"
+ / "PERIOD"
+ / "RECUR"
+ / "TEXT"
+ / "TIME"
+ / "URI"
+ / "UTC-OFFSET"
+ / x-name
+ ; Some experimental iCalendar data type.
+ / iana-token)
+ ; Some other IANA registered iCalendar data type.
+
+ Description: The parameter specifies the data type and format of the
+ property value. The property values MUST be of a single value type.
+ For example, a "RDATE" property cannot have a combination of DATE-
+ TIME and TIME value types.
+
+ If the property's value is the default value type, then this
+ parameter need not be specified. However, if the property's default
+ value type is overridden by some other allowable value type, then
+ this parameter MUST be specified.
+
+<span class="h3"><h3><a name="section-4.3">4.3</a> Property Value Data Types</h3></span>
+
+ The properties in an iCalendar object are strongly typed. The
+ definition of each property restricts the value to be one of the
+ value data types, or simply value types, defined in this section. The
+ value type for a property will either be specified implicitly as the
+ default value type or will be explicitly specified with the "VALUE"
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 32]</span>
+</pre><pre class="newpage"><a name="page-33" id="page-33" href="#page-33" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ parameter. If the value type of a property is one of the alternate
+ valid types, then it MUST be explicitly specified with the "VALUE"
+ parameter.
+
+<span class="h4"><h4><a name="section-4.3.1">4.3.1</a> Binary</h4></span>
+
+ Value Name: BINARY
+
+ Purpose: This value type is used to identify properties that contain
+ a character encoding of inline binary data. For example, an inline
+ attachment of an object code might be included in an iCalendar
+ object.
+
+ Formal Definition: The value type is defined by the following
+ notation:
+
+ binary = *(4b-char) [<a href="#ref-b-end">b-end</a>]
+ ; A "BASE64" encoded character string, as defined by [<a href="http://tools.ietf.org/html/rfc2045" title="" Multipurpose Internet Mail Extensions (MIME) - Part One: Format of Internet Message Bodies"">RFC 2045</a>].
+
+ b-end = (2b-char "==") / (3b-char "=")
+
+ b-char = ALPHA / DIGIT / "+" / "/"
+
+ Description: Property values with this value type MUST also include
+ the inline encoding parameter sequence of ";ENCODING=BASE64". That
+ is, all inline binary data MUST first be character encoded using the
+ "BASE64" encoding method defined in [<a href="http://tools.ietf.org/html/rfc2045" title="" Multipurpose Internet Mail Extensions (MIME) - Part One: Format of Internet Message Bodies"">RFC 2045</a>]. No additional content
+ value encoding (i.e., BACKSLASH character encoding) is defined for
+ this value type.
+
+ Example: The following is an abridged example of a "BASE64" encoded
+ binary value data.
+
+ ATTACH;VALUE=BINARY;ENCODING=BASE64:MIICajCCAdOgAwIBAgICBEUwDQY
+ JKoZIhvcNAQEEBQAwdzELMAkGA1UEBhMCVVMxLDAqBgNVBAoTI05ldHNjYXBlI
+ ENvbW11bmljYXRpb25zIENvcnBvcmF0aW9uMRwwGgYDVQQLExNJbmZv
+ <...remainder of "BASE64" encoded binary data...>
+
+<span class="h4"><h4><a name="section-4.3.2">4.3.2</a> Boolean</h4></span>
+
+ Value Name: BOOLEAN
+
+ Purpose: This value type is used to identify properties that contain
+ either a "TRUE" or "FALSE" Boolean value.
+
+ Formal Definition: The value type is defined by the following
+ notation:
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 33]</span>
+</pre><pre class="newpage"><a name="page-34" id="page-34" href="#page-34" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ boolean = "TRUE" / "FALSE"
+
+ Description: These values are case insensitive text. No additional
+ content value encoding (i.e., BACKSLASH character encoding) is
+ defined for this value type.
+
+ Example: The following is an example of a hypothetical property that
+ has a BOOLEAN value type:
+
+ GIBBERISH:TRUE
+
+<span class="h4"><h4><a name="section-4.3.3">4.3.3</a> Calendar User Address</h4></span>
+
+ Value Name: CAL-ADDRESS
+
+ Purpose: This value type is used to identify properties that contain
+ a calendar user address.
+
+ Formal Definition: The value type is as defined by the following
+ notation:
+
+ cal-address = uri
+
+ Description: The value is a URI as defined by [<a href="http://tools.ietf.org/html/rfc1738" title=""Uniform Resource Locators (URL)"">RFC 1738</a>] or any other
+ IANA registered form for a URI. When used to address an Internet
+ email transport address for a calendar user, the value MUST be a
+ MAILTO URI, as defined by [<a href="http://tools.ietf.org/html/rfc1738" title=""Uniform Resource Locators (URL)"">RFC 1738</a>]. No additional content value
+ encoding (i.e., BACKSLASH character encoding) is defined for this
+ value type.
+
+ Example:
+
+ ATTENDEE:MAILTO:jane_doe@host.com
+
+<span class="h4"><h4><a name="section-4.3.4">4.3.4</a> Date</h4></span>
+
+ Value Name: DATE
+
+ Purpose: This value type is used to identify values that contain a
+ calendar date.
+
+ Formal Definition: The value type is defined by the following
+ notation:
+
+ date = date-value
+
+ date-value = date-fullyear date-month date-mday
+ date-fullyear = 4DIGIT
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 34]</span>
+</pre><pre class="newpage"><a name="page-35" id="page-35" href="#page-35" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ date-month = 2DIGIT ;01-12
+ date-mday = 2DIGIT ;01-28, 01-29, 01-30, 01-31
+ ;based on month/year
+
+ Description: If the property permits, multiple "date" values are
+ specified as a COMMA character (US-ASCII decimal 44) separated list
+ of values. The format for the value type is expressed as the [ISO
+ 8601] complete representation, basic format for a calendar date. The
+ textual format specifies a four-digit year, two-digit month, and
+ two-digit day of the month. There are no separator characters between
+ the year, month and day component text.
+
+ No additional content value encoding (i.e., BACKSLASH character
+ encoding) is defined for this value type.
+
+ Example: The following represents July 14, 1997:
+
+ 19970714
+
+<span class="h4"><h4><a name="section-4.3.5">4.3.5</a> Date-Time</h4></span>
+
+ Value Name: DATE-TIME
+
+ Purpose: This value type is used to identify values that specify a
+ precise calendar date and time of day.
+
+ Formal Definition: The value type is defined by the following
+ notation:
+
+ date-time = date "T" time ;As specified in the date and time
+ ;value definitions
+
+ Description: If the property permits, multiple "date-time" values are
+ specified as a COMMA character (US-ASCII decimal 44) separated list
+ of values. No additional content value encoding (i.e., BACKSLASH
+ character encoding) is defined for this value type.
+
+ The "DATE-TIME" data type is used to identify values that contain a
+ precise calendar date and time of day. The format is based on the
+ [ISO 8601] complete representation, basic format for a calendar date
+ and time of day. The text format is a concatenation of the "date",
+ followed by the LATIN CAPITAL LETTER T character (US-ASCII decimal
+ 84) time designator, followed by the "time" format.
+
+ The "DATE-TIME" data type expresses time values in three forms:
+
+ The form of date and time with UTC offset MUST NOT be used. For
+ example, the following is not valid for a date-time value:
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 35]</span>
+</pre><pre class="newpage"><a name="page-36" id="page-36" href="#page-36" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ DTSTART:19980119T230000-0800 ;Invalid time format
+
+ FORM #1: DATE WITH LOCAL TIME
+
+ The date with local time form is simply a date-time value that does
+ not contain the UTC designator nor does it reference a time zone. For
+ example, the following represents Janurary 18, 1998, at 11 PM:
+
+ DTSTART:19980118T230000
+
+ Date-time values of this type are said to be "floating" and are not
+ bound to any time zone in particular. They are used to represent the
+ same hour, minute, and second value regardless of which time zone is
+ currently being observed. For example, an event can be defined that
+ indicates that an individual will be busy from 11:00 AM to 1:00 PM
+ every day, no matter which time zone the person is in. In these
+ cases, a local time can be specified. The recipient of an iCalendar
+ object with a property value consisting of a local time, without any
+ relative time zone information, SHOULD interpret the value as being
+ fixed to whatever time zone the ATTENDEE is in at any given moment.
+ This means that two ATTENDEEs, in different time zones, receiving the
+ same event definition as a floating time, may be participating in the
+ event at different actual times. Floating time SHOULD only be used
+ where that is the reasonable behavior.
+
+ In most cases, a fixed time is desired. To properly communicate a
+ fixed time in a property value, either UTC time or local time with
+ time zone reference MUST be specified.
+
+ The use of local time in a DATE-TIME value without the TZID property
+ parameter is to be interpreted as floating time, regardless of the
+ existence of "VTIMEZONE" calendar components in the iCalendar object.
+
+ FORM #2: DATE WITH UTC TIME
+
+ The date with UTC time, or absolute time, is identified by a LATIN
+ CAPITAL LETTER Z suffix character (US-ASCII decimal 90), the UTC
+ designator, appended to the time value. For example, the following
+ represents January 19, 1998, at 0700 UTC:
+
+ DTSTART:19980119T070000Z
+
+ The TZID property parameter MUST NOT be applied to DATE-TIME
+ properties whose time values are specified in UTC.
+
+ FORM #3: DATE WITH LOCAL TIME AND TIME ZONE REFERENCE
+
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 36]</span>
+</pre><pre class="newpage"><a name="page-37" id="page-37" href="#page-37" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ The date and local time with reference to time zone information is
+ identified by the use the TZID property parameter to reference the
+ appropriate time zone definition. TZID is discussed in detail in the
+ section on Time Zone. For example, the following represents 2 AM in
+ New York on Janurary 19, 1998:
+
+ DTSTART;TZID=US-Eastern:19980119T020000
+
+ Example: The following represents July 14, 1997, at 1:30 PM in New
+ York City in each of the three time formats, using the "DTSTART"
+ property.
+
+ DTSTART:19970714T133000 ;Local time
+ DTSTART:19970714T173000Z ;UTC time
+ DTSTART;TZID=US-Eastern:19970714T133000 ;Local time and time
+ ; zone reference
+
+ A time value MUST ONLY specify 60 seconds when specifying the
+ periodic "leap second" in the time value. For example:
+
+ COMPLETED:19970630T235960Z
+
+<span class="h4"><h4><a name="section-4.3.6">4.3.6</a> Duration</h4></span>
+
+ Value Name: DURATION
+
+ Purpose: This value type is used to identify properties that contain
+ a duration of time.
+
+ Formal Definition: The value type is defined by the following
+ notation:
+
+ dur-value = (["+"] / "-") "P" (dur-date / dur-time / dur-week)
+
+ dur-date = dur-day [<a href="#ref-dur-time">dur-time</a>]
+ dur-time = "T" (dur-hour / dur-minute / dur-second)
+ dur-week = 1*DIGIT "W"
+ dur-hour = 1*DIGIT "H" [<a href="#ref-dur-minute">dur-minute</a>]
+ dur-minute = 1*DIGIT "M" [<a href="#ref-dur-second">dur-second</a>]
+ dur-second = 1*DIGIT "S"
+ dur-day = 1*DIGIT "D"
+
+ Description: If the property permits, multiple "duration" values are
+ specified by a COMMA character (US-ASCII decimal 44) separated list
+ of values. The format is expressed as the [ISO 8601] basic format for
+ the duration of time. The format can represent durations in terms of
+ weeks, days, hours, minutes, and seconds.
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 37]</span>
+</pre><pre class="newpage"><a name="page-38" id="page-38" href="#page-38" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ No additional content value encoding (i.e., BACKSLASH character
+ encoding) are defined for this value type.
+
+ Example: A duration of 15 days, 5 hours and 20 seconds would be:
+
+ P15DT5H0M20S
+
+ A duration of 7 weeks would be:
+
+ P7W
+
+<span class="h4"><h4><a name="section-4.3.7">4.3.7</a> Float</h4></span>
+
+ Value Name: FLOAT
+
+ Purpose: This value type is used to identify properties that contain
+ a real number value.
+
+ Formal Definition: The value type is defined by the following
+ notation:
+
+ float = (["+"] / "-") 1*DIGIT ["." 1*DIGIT]
+
+ Description: If the property permits, multiple "float" values are
+ specified by a COMMA character (US-ASCII decimal 44) separated list
+ of values.
+
+ No additional content value encoding (i.e., BACKSLASH character
+ encoding) is defined for this value type.
+
+ Example:
+
+ 1000000.0000001
+ 1.333
+ -3.14
+
+<span class="h4"><h4><a name="section-4.3.8">4.3.8</a> Integer</h4></span>
+
+ Value Name:INTEGER
+
+ Purpose: This value type is used to identify properties that contain
+ a signed integer value.
+
+ Formal Definition: The value type is defined by the following
+ notation:
+
+ integer = (["+"] / "-") 1*DIGIT
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 38]</span>
+</pre><pre class="newpage"><a name="page-39" id="page-39" href="#page-39" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ Description: If the property permits, multiple "integer" values are
+ specified by a COMMA character (US-ASCII decimal 44) separated list
+ of values. The valid range for "integer" is -2147483648 to
+ 2147483647. If the sign is not specified, then the value is assumed
+ to be positive.
+
+ No additional content value encoding (i.e., BACKSLASH character
+ encoding) is defined for this value type.
+
+ Example:
+
+ 1234567890
+ -1234567890
+ +1234567890
+ 432109876
+
+<span class="h4"><h4><a name="section-4.3.9">4.3.9</a> Period of Time</h4></span>
+
+ Value Name: PERIOD
+
+ Purpose: This value type is used to identify values that contain a
+ precise period of time.
+
+ Formal Definition: The data type is defined by the following
+ notation:
+
+ period = period-explicit / period-start
+
+ period-explicit = date-time "/" date-time
+ ; [ISO 8601] complete representation basic format for a period of
+ ; time consisting of a start and end. The start MUST be before the
+ ; end.
+
+ period-start = date-time "/" dur-value
+ ; [ISO 8601] complete representation basic format for a period of
+ ; time consisting of a start and positive duration of time.
+
+ Description: If the property permits, multiple "period" values are
+ specified by a COMMA character (US-ASCII decimal 44) separated list
+ of values. There are two forms of a period of time. First, a period
+ of time is identified by its start and its end. This format is
+ expressed as the [ISO 8601] complete representation, basic format for
+ "DATE-TIME" start of the period, followed by a SOLIDUS character
+ (US-ASCII decimal 47), followed by the "DATE-TIME" of the end of the
+ period. The start of the period MUST be before the end of the period.
+ Second, a period of time can also be defined by a start and a
+ positive duration of time. The format is expressed as the [ISO 8601]
+ complete representation, basic format for the "DATE-TIME" start of
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 39]</span>
+</pre><pre class="newpage"><a name="page-40" id="page-40" href="#page-40" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ the period, followed by a SOLIDUS character (US-ASCII decimal 47),
+ followed by the [ISO 8601] basic format for "DURATION" of the period.
+
+ Example: The period starting at 18:00:00 UTC, on January 1, 1997 and
+ ending at 07:00:00 UTC on January 2, 1997 would be:
+
+ 19970101T180000Z/19970102T070000Z
+
+ The period start at 18:00:00 on January 1, 1997 and lasting 5 hours
+ and 30 minutes would be:
+
+ 19970101T180000Z/PT5H30M
+
+ No additional content value encoding (i.e., BACKSLASH character
+ encoding) is defined for this value type.
+
+<span class="h4"><h4><a name="section-4.3.10">4.3.10</a> Recurrence Rule</h4></span>
+
+ Value Name: RECUR
+
+ Purpose: This value type is used to identify properties that contain
+ a recurrence rule specification.
+
+ Formal Definition: The value type is defined by the following
+ notation:
+
+ recur = "FREQ"=freq *(
+
+ ; either UNTIL or COUNT may appear in a 'recur',
+ ; but UNTIL and COUNT MUST NOT occur in the same 'recur'
+
+ ( ";" "UNTIL" "=" enddate ) /
+ ( ";" "COUNT" "=" 1*DIGIT ) /
+
+ ; the rest of these keywords are optional,
+ ; but MUST NOT occur more than once
+
+ ( ";" "INTERVAL" "=" 1*DIGIT ) /
+ ( ";" "BYSECOND" "=" byseclist ) /
+ ( ";" "BYMINUTE" "=" byminlist ) /
+ ( ";" "BYHOUR" "=" byhrlist ) /
+ ( ";" "BYDAY" "=" bywdaylist ) /
+ ( ";" "BYMONTHDAY" "=" bymodaylist ) /
+ ( ";" "BYYEARDAY" "=" byyrdaylist ) /
+ ( ";" "BYWEEKNO" "=" bywknolist ) /
+ ( ";" "BYMONTH" "=" bymolist ) /
+ ( ";" "BYSETPOS" "=" bysplist ) /
+ ( ";" "WKST" "=" weekday ) /
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 40]</span>
+</pre><pre class="newpage"><a name="page-41" id="page-41" href="#page-41" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ ( ";" x-name "=" text )
+ )
+
+ freq = "SECONDLY" / "MINUTELY" / "HOURLY" / "DAILY"
+ / "WEEKLY" / "MONTHLY" / "YEARLY"
+
+ enddate = date
+ enddate =/ date-time ;An UTC value
+
+ byseclist = seconds / ( seconds *("," seconds) )
+
+ seconds = 1DIGIT / 2DIGIT ;0 to 59
+
+ byminlist = minutes / ( minutes *("," minutes) )
+
+ minutes = 1DIGIT / 2DIGIT ;0 to 59
+
+ byhrlist = hour / ( hour *("," hour) )
+
+ hour = 1DIGIT / 2DIGIT ;0 to 23
+
+ bywdaylist = weekdaynum / ( weekdaynum *("," weekdaynum) )
+
+ weekdaynum = [([<a href="#ref-plus">plus</a>] ordwk / minus ordwk)] weekday
+
+ plus = "+"
+
+ minus = "-"
+
+ ordwk = 1DIGIT / 2DIGIT ;1 to 53
+
+ weekday = "SU" / "MO" / "TU" / "WE" / "TH" / "FR" / "SA"
+ ;Corresponding to SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY,
+ ;FRIDAY, SATURDAY and SUNDAY days of the week.
+
+ bymodaylist = monthdaynum / ( monthdaynum *("," monthdaynum) )
+
+ monthdaynum = ([<a href="#ref-plus">plus</a>] ordmoday) / (minus ordmoday)
+
+ ordmoday = 1DIGIT / 2DIGIT ;1 to 31
+
+ byyrdaylist = yeardaynum / ( yeardaynum *("," yeardaynum) )
+
+ yeardaynum = ([<a href="#ref-plus">plus</a>] ordyrday) / (minus ordyrday)
+
+ ordyrday = 1DIGIT / 2DIGIT / 3DIGIT ;1 to 366
+
+ bywknolist = weeknum / ( weeknum *("," weeknum) )
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 41]</span>
+</pre><pre class="newpage"><a name="page-42" id="page-42" href="#page-42" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ weeknum = ([<a href="#ref-plus">plus</a>] ordwk) / (minus ordwk)
+
+ bymolist = monthnum / ( monthnum *("," monthnum) )
+
+ monthnum = 1DIGIT / 2DIGIT ;1 to 12
+
+ bysplist = setposday / ( setposday *("," setposday) )
+
+ setposday = yeardaynum
+
+ Description: If the property permits, multiple "recur" values are
+ specified by a COMMA character (US-ASCII decimal 44) separated list
+ of values. The value type is a structured value consisting of a list
+ of one or more recurrence grammar parts. Each rule part is defined by
+ a NAME=VALUE pair. The rule parts are separated from each other by
+ the SEMICOLON character (US-ASCII decimal 59). The rule parts are not
+ ordered in any particular sequence. Individual rule parts MUST only
+ be specified once.
+
+ The FREQ rule part identifies the type of recurrence rule. This rule
+ part MUST be specified in the recurrence rule. Valid values include
+ SECONDLY, to specify repeating events based on an interval of a
+ second or more; MINUTELY, to specify repeating events based on an
+ interval of a minute or more; HOURLY, to specify repeating events
+ based on an interval of an hour or more; DAILY, to specify repeating
+ events based on an interval of a day or more; WEEKLY, to specify
+ repeating events based on an interval of a week or more; MONTHLY, to
+ specify repeating events based on an interval of a month or more; and
+ YEARLY, to specify repeating events based on an interval of a year or
+ more.
+
+ The INTERVAL rule part contains a positive integer representing how
+ often the recurrence rule repeats. The default value is "1", meaning
+ every second for a SECONDLY rule, or every minute for a MINUTELY
+ rule, every hour for an HOURLY rule, every day for a DAILY rule,
+ every week for a WEEKLY rule, every month for a MONTHLY rule and
+ every year for a YEARLY rule.
+
+ The UNTIL rule part defines a date-time value which bounds the
+ recurrence rule in an inclusive manner. If the value specified by
+ UNTIL is synchronized with the specified recurrence, this date or
+ date-time becomes the last instance of the recurrence. If specified
+ as a date-time value, then it MUST be specified in an UTC time
+ format. If not present, and the COUNT rule part is also not present,
+ the RRULE is considered to repeat forever.
+
+ The COUNT rule part defines the number of occurrences at which to
+ range-bound the recurrence. The "DTSTART" property value, if
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 42]</span>
+</pre><pre class="newpage"><a name="page-43" id="page-43" href="#page-43" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ specified, counts as the first occurrence.
+
+ The BYSECOND rule part specifies a COMMA character (US-ASCII decimal
+ 44) separated list of seconds within a minute. Valid values are 0 to
+ 59. The BYMINUTE rule part specifies a COMMA character (US-ASCII
+ decimal 44) separated list of minutes within an hour. Valid values
+ are 0 to 59. The BYHOUR rule part specifies a COMMA character (US-
+ ASCII decimal 44) separated list of hours of the day. Valid values
+ are 0 to 23.
+
+ The BYDAY rule part specifies a COMMA character (US-ASCII decimal 44)
+ separated list of days of the week; MO indicates Monday; TU indicates
+ Tuesday; WE indicates Wednesday; TH indicates Thursday; FR indicates
+ Friday; SA indicates Saturday; SU indicates Sunday.
+
+ Each BYDAY value can also be preceded by a positive (+n) or negative
+ (-n) integer. If present, this indicates the nth occurrence of the
+ specific day within the MONTHLY or YEARLY RRULE. For example, within
+ a MONTHLY rule, +1MO (or simply 1MO) represents the first Monday
+ within the month, whereas -1MO represents the last Monday of the
+ month. If an integer modifier is not present, it means all days of
+ this type within the specified frequency. For example, within a
+ MONTHLY rule, MO represents all Mondays within the month.
+
+ The BYMONTHDAY rule part specifies a COMMA character (ASCII decimal
+ 44) separated list of days of the month. Valid values are 1 to 31 or
+ -31 to -1. For example, -10 represents the tenth to the last day of
+ the month.
+
+ The BYYEARDAY rule part specifies a COMMA character (US-ASCII decimal
+ 44) separated list of days of the year. Valid values are 1 to 366 or
+ -366 to -1. For example, -1 represents the last day of the year
+ (December 31st) and -306 represents the 306th to the last day of the
+ year (March 1st).
+
+ The BYWEEKNO rule part specifies a COMMA character (US-ASCII decimal
+ 44) separated list of ordinals specifying weeks of the year. Valid
+ values are 1 to 53 or -53 to -1. This corresponds to weeks according
+ to week numbering as defined in [ISO 8601]. A week is defined as a
+ seven day period, starting on the day of the week defined to be the
+ week start (see WKST). Week number one of the calendar year is the
+ first week which contains at least four (4) days in that calendar
+ year. This rule part is only valid for YEARLY rules. For example, 3
+ represents the third week of the year.
+
+ Note: Assuming a Monday week start, week 53 can only occur when
+ Thursday is January 1 or if it is a leap year and Wednesday is
+ January 1.
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 43]</span>
+</pre><pre class="newpage"><a name="page-44" id="page-44" href="#page-44" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ The BYMONTH rule part specifies a COMMA character (US-ASCII decimal
+ 44) separated list of months of the year. Valid values are 1 to 12.
+
+ The WKST rule part specifies the day on which the workweek starts.
+ Valid values are MO, TU, WE, TH, FR, SA and SU. This is significant
+ when a WEEKLY RRULE has an interval greater than 1, and a BYDAY rule
+ part is specified. This is also significant when in a YEARLY RRULE
+ when a BYWEEKNO rule part is specified. The default value is MO.
+
+ The BYSETPOS rule part specifies a COMMA character (US-ASCII decimal
+ 44) separated list of values which corresponds to the nth occurrence
+ within the set of events specified by the rule. Valid values are 1 to
+ 366 or -366 to -1. It MUST only be used in conjunction with another
+ BYxxx rule part. For example "the last work day of the month" could
+ be represented as:
+
+ RRULE:FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1
+
+ Each BYSETPOS value can include a positive (+n) or negative (-n)
+ integer. If present, this indicates the nth occurrence of the
+ specific occurrence within the set of events specified by the rule.
+
+ If BYxxx rule part values are found which are beyond the available
+ scope (ie, BYMONTHDAY=30 in February), they are simply ignored.
+
+ Information, not contained in the rule, necessary to determine the
+ various recurrence instance start time and dates are derived from the
+ Start Time (DTSTART) entry attribute. For example,
+ "FREQ=YEARLY;BYMONTH=1" doesn't specify a specific day within the
+ month or a time. This information would be the same as what is
+ specified for DTSTART.
+
+ BYxxx rule parts modify the recurrence in some manner. BYxxx rule
+ parts for a period of time which is the same or greater than the
+ frequency generally reduce or limit the number of occurrences of the
+ recurrence generated. For example, "FREQ=DAILY;BYMONTH=1" reduces the
+ number of recurrence instances from all days (if BYMONTH tag is not
+ present) to all days in January. BYxxx rule parts for a period of
+ time less than the frequency generally increase or expand the number
+ of occurrences of the recurrence. For example,
+ "FREQ=YEARLY;BYMONTH=1,2" increases the number of days within the
+ yearly recurrence set from 1 (if BYMONTH tag is not present) to 2.
+
+ If multiple BYxxx rule parts are specified, then after evaluating the
+ specified FREQ and INTERVAL rule parts, the BYxxx rule parts are
+ applied to the current set of evaluated occurrences in the following
+ order: BYMONTH, BYWEEKNO, BYYEARDAY, BYMONTHDAY, BYDAY, BYHOUR,
+ BYMINUTE, BYSECOND and BYSETPOS; then COUNT and UNTIL are evaluated.
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 44]</span>
+</pre><pre class="newpage"><a name="page-45" id="page-45" href="#page-45" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ Here is an example of evaluating multiple BYxxx rule parts.
+
+ DTSTART;TZID=US-Eastern:19970105T083000
+ RRULE:FREQ=YEARLY;INTERVAL=2;BYMONTH=1;BYDAY=SU;BYHOUR=8,9;
+ BYMINUTE=30
+
+ First, the "INTERVAL=2" would be applied to "FREQ=YEARLY" to arrive
+ at "every other year". Then, "BYMONTH=1" would be applied to arrive
+ at "every January, every other year". Then, "BYDAY=SU" would be
+ applied to arrive at "every Sunday in January, every other year".
+ Then, "BYHOUR=8,9" would be applied to arrive at "every Sunday in
+ January at 8 AM and 9 AM, every other year". Then, "BYMINUTE=30"
+ would be applied to arrive at "every Sunday in January at 8:30 AM and
+ 9:30 AM, every other year". Then, lacking information from RRULE, the
+ second is derived from DTSTART, to end up in "every Sunday in January
+ at 8:30:00 AM and 9:30:00 AM, every other year". Similarly, if the
+ BYMINUTE, BYHOUR, BYDAY, BYMONTHDAY or BYMONTH rule part were
+ missing, the appropriate minute, hour, day or month would have been
+ retrieved from the "DTSTART" property.
+
+ No additional content value encoding (i.e., BACKSLASH character
+ encoding) is defined for this value type.
+
+ Example: The following is a rule which specifies 10 meetings which
+ occur every other day:
+
+ FREQ=DAILY;COUNT=10;INTERVAL=2
+
+ There are other examples specified in the "RRULE" specification.
+
+<span class="h4"><h4><a name="section-4.3.11">4.3.11</a> Text</h4></span>
+
+ Value Name: TEXT
+
+ Purpose This value type is used to identify values that contain human
+ readable text.
+
+ Formal Definition: The character sets supported by this revision of
+ iCalendar are UTF-8 and US ASCII thereof. The applicability to other
+ character sets is for future work. The value type is defined by the
+ following notation.
+
+ text = *(TSAFE-CHAR / ":" / DQUOTE / ESCAPED-CHAR)
+ ; Folded according to description above
+
+ ESCAPED-CHAR = "\\" / "\;" / "\," / "\N" / "\n")
+ ; \\ encodes \, \N or \n encodes newline
+ ; \; encodes ;, \, encodes ,
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 45]</span>
+</pre><pre class="newpage"><a name="page-46" id="page-46" href="#page-46" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ TSAFE-CHAR = %x20-21 / %x23-2B / %x2D-39 / %x3C-5B
+ %x5D-7E / NON-US-ASCII
+ ; Any character except CTLs not needed by the current
+ ; character set, DQUOTE, ";", ":", "\", ","
+
+ Note: Certain other character sets may require modification of the
+ above definitions, but this is beyond the scope of this document.
+
+ Description: If the property permits, multiple "text" values are
+ specified by a COMMA character (US-ASCII decimal 44) separated list
+ of values.
+
+ The language in which the text is represented can be controlled by
+ the "LANGUAGE" property parameter.
+
+ An intentional formatted text line break MUST only be included in a
+ "TEXT" property value by representing the line break with the
+ character sequence of BACKSLASH (US-ASCII decimal 92), followed by a
+ LATIN SMALL LETTER N (US-ASCII decimal 110) or a LATIN CAPITAL LETTER
+ N (US-ASCII decimal 78), that is "\n" or "\N".
+
+ The "TEXT" property values may also contain special characters that
+ are used to signify delimiters, such as a COMMA character for lists
+ of values or a SEMICOLON character for structured values. In order to
+ support the inclusion of these special characters in "TEXT" property
+ values, they MUST be escaped with a BACKSLASH character. A BACKSLASH
+ character (US-ASCII decimal 92) in a "TEXT" property value MUST be
+ escaped with another BACKSLASH character. A COMMA character in a
+ "TEXT" property value MUST be escaped with a BACKSLASH character
+ (US-ASCII decimal 92). A SEMICOLON character in a "TEXT" property
+ value MUST be escaped with a BACKSLASH character (US-ASCII decimal
+ 92). However, a COLON character in a "TEXT" property value SHALL NOT
+ be escaped with a BACKSLASH character.Example: A multiple line value
+ of:
+
+ Project XYZ Final Review
+ Conference Room - 3B
+ Come Prepared.
+
+ would be represented as:
+
+ Project XYZ Final Review\nConference Room - 3B\nCome Prepared.
+
+
+
+
+
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 46]</span>
+</pre><pre class="newpage"><a name="page-47" id="page-47" href="#page-47" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+<span class="h4"><h4><a name="section-4.3.12">4.3.12</a> Time</h4></span>
+
+ Value Name: TIME
+
+ Purpose: This value type is used to identify values that contain a
+ time of day.
+
+ Formal Definition: The data type is defined by the following
+ notation:
+
+ time = time-hour time-minute time-second [<a href="#ref-time-utc">time-utc</a>]
+
+ time-hour = 2DIGIT ;00-23
+ time-minute = 2DIGIT ;00-59
+ time-second = 2DIGIT ;00-60
+ ;The "60" value is used to account for "leap" seconds.
+
+ time-utc = "Z"
+
+ Description: If the property permits, multiple "time" values are
+ specified by a COMMA character (US-ASCII decimal 44) separated list
+ of values. No additional content value encoding (i.e., BACKSLASH
+ character encoding) is defined for this value type.
+
+ The "TIME" data type is used to identify values that contain a time
+ of day. The format is based on the [ISO 8601] complete
+ representation, basic format for a time of day. The text format
+ consists of a two-digit 24-hour of the day (i.e., values 0-23), two-
+ digit minute in the hour (i.e., values 0-59), and two-digit seconds
+ in the minute (i.e., values 0-60). The seconds value of 60 MUST only
+ to be used to account for "leap" seconds. Fractions of a second are
+ not supported by this format.
+
+ In parallel to the "DATE-TIME" definition above, the "TIME" data type
+ expresses time values in three forms:
+
+ The form of time with UTC offset MUST NOT be used. For example, the
+ following is NOT VALID for a time value:
+
+ 230000-0800 ;Invalid time format
+
+ FORM #1 LOCAL TIME
+
+ The local time form is simply a time value that does not contain the
+ UTC designator nor does it reference a time zone. For example, 11:00
+ PM:
+
+ 230000
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 47]</span>
+</pre><pre class="newpage"><a name="page-48" id="page-48" href="#page-48" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ Time values of this type are said to be "floating" and are not bound
+ to any time zone in particular. They are used to represent the same
+ hour, minute, and second value regardless of which time zone is
+ currently being observed. For example, an event can be defined that
+ indicates that an individual will be busy from 11:00 AM to 1:00 PM
+ every day, no matter which time zone the person is in. In these
+ cases, a local time can be specified. The recipient of an iCalendar
+ object with a property value consisting of a local time, without any
+ relative time zone information, SHOULD interpret the value as being
+ fixed to whatever time zone the ATTENDEE is in at any given moment.
+ This means that two ATTENDEEs may participate in the same event at
+ different UTC times; floating time SHOULD only be used where that is
+ reasonable behavior.
+
+ In most cases, a fixed time is desired. To properly communicate a
+ fixed time in a property value, either UTC time or local time with
+ time zone reference MUST be specified.
+
+ The use of local time in a TIME value without the TZID property
+ parameter is to be interpreted as a local time value, regardless of
+ the existence of "VTIMEZONE" calendar components in the iCalendar
+ object.
+
+ FORM #2: UTC TIME
+
+ UTC time, or absolute time, is identified by a LATIN CAPITAL LETTER Z
+ suffix character (US-ASCII decimal 90), the UTC designator, appended
+ to the time value. For example, the following represents 07:00 AM
+ UTC:
+
+ 070000Z
+
+ The TZID property parameter MUST NOT be applied to TIME properties
+ whose time values are specified in UTC.
+
+ FORM #3: LOCAL TIME AND TIME ZONE REFERENCE
+
+ The local time with reference to time zone information form is
+ identified by the use the TZID property parameter to reference the
+ appropriate time zone definition. TZID is discussed in detail in the
+ section on Time Zone.
+
+ Example: The following represents 8:30 AM in New York in Winter, five
+ hours behind UTC, in each of the three formats using the "X-
+ TIMEOFDAY" non-standard property:
+
+
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 48]</span>
+</pre><pre class="newpage"><a name="page-49" id="page-49" href="#page-49" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ X-TIMEOFDAY:083000
+
+ X-TIMEOFDAY:133000Z
+
+ X-TIMEOFDAY;TZID=US-Eastern:083000
+
+<span class="h4"><h4><a name="section-4.3.13">4.3.13</a> URI</h4></span>
+
+ Value Name: URI
+
+ Purpose: This value type is used to identify values that contain a
+ uniform resource identifier (URI) type of reference to the property
+ value.
+
+ Formal Definition: The data type is defined by the following
+ notation:
+
+ uri = <As defined by any IETF RFC>
+
+ Description: This data type might be used to reference binary
+ information, for values that are large, or otherwise undesirable to
+ include directly in the iCalendar object.
+
+ The URI value formats in <a href="http://tools.ietf.org/html/rfc1738">RFC 1738</a>, <a href="http://tools.ietf.org/html/rfc2111">RFC 2111</a> and any other IETF
+ registered value format can be specified.
+
+ Any IANA registered URI format can be used. These include, but are
+ not limited to, those defined in <a href="http://tools.ietf.org/html/rfc1738">RFC 1738</a> and <a href="http://tools.ietf.org/html/rfc2111">RFC 2111</a>.
+
+ When a property parameter value is a URI value type, the URI MUST be
+ specified as a quoted-string value.
+
+ No additional content value encoding (i.e., BACKSLASH character
+ encoding) is defined for this value type.
+
+ Example: The following is a URI for a network file:
+
+ <a href="http://host1.com/my-report.txt">http://host1.com/my-report.txt</a>
+
+<span class="h4"><h4><a name="section-4.3.14">4.3.14</a> UTC Offset</h4></span>
+
+ Value Name: UTC-OFFSET
+
+ Purpose: This value type is used to identify properties that contain
+ an offset from UTC to local time.
+
+ Formal Definition: The data type is defined by the following
+ notation:
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 49]</span>
+</pre><pre class="newpage"><a name="page-50" id="page-50" href="#page-50" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ utc-offset = time-numzone ;As defined above in time data type
+
+ time-numzone = ("+" / "-") time-hour time-minute [time-
+ second]
+
+ Description: The PLUS SIGN character MUST be specified for positive
+ UTC offsets (i.e., ahead of UTC). The value of "-0000" and "-000000"
+ are not allowed. The time-second, if present, may not be 60; if
+ absent, it defaults to zero.
+
+ No additional content value encoding (i.e., BACKSLASH character
+ encoding) is defined for this value type.
+
+ Example: The following UTC offsets are given for standard time for
+ New York (five hours behind UTC) and Geneva (one hour ahead of UTC):
+
+ -0500
+
+ +0100
+
+<span class="h3"><h3><a name="section-4.4">4.4</a> iCalendar Object</h3></span>
+
+ The Calendaring and Scheduling Core Object is a collection of
+ calendaring and scheduling information. Typically, this information
+ will consist of a single iCalendar object. However, multiple
+ iCalendar objects can be sequentially grouped together. The first
+ line and last line of the iCalendar object MUST contain a pair of
+ iCalendar object delimiter strings. The syntax for an iCalendar
+ object is as follows:
+
+ icalobject = 1*("BEGIN" ":" "VCALENDAR" CRLF
+ icalbody
+ "END" ":" "VCALENDAR" CRLF)
+
+ The following is a simple example of an iCalendar object:
+
+ BEGIN:VCALENDAR
+ VERSION:2.0
+ PRODID:-//hacksw/handcal//NONSGML v1.0//EN
+ BEGIN:VEVENT
+ DTSTART:19970714T170000Z
+ DTEND:19970715T035959Z
+ SUMMARY:Bastille Day Party
+ END:VEVENT
+ END:VCALENDAR
+
+
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 50]</span>
+</pre><pre class="newpage"><a name="page-51" id="page-51" href="#page-51" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+<span class="h3"><h3><a name="section-4.5">4.5</a> Property</h3></span>
+
+ A property is the definition of an individual attribute describing a
+ calendar or a calendar component. A property takes the form defined
+ by the "contentline" notation defined in <a href="#section-4.1.1">section 4.1.1</a>.
+
+ The following is an example of a property:
+
+ DTSTART:19960415T133000Z
+
+ This memo imposes no ordering of properties within an iCalendar
+ object.
+
+ Property names, parameter names and enumerated parameter values are
+ case insensitive. For example, the property name "DUE" is the same as
+ "due" and "Due", DTSTART;TZID=US-Eastern:19980714T120000 is the same
+ as DtStart;TzID=US-Eastern:19980714T120000.
+
+<span class="h3"><h3><a name="section-4.6">4.6</a> Calendar Components</h3></span>
+
+ 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 to-do, a journal entry, time zone information, or
+ free/busy time information, or an alarm.
+
+ The body of the iCalendar object is defined by the following
+ notation:
+
+ icalbody = calprops component
+
+ calprops = 2*(
+
+ ; 'prodid' and 'version' are both REQUIRED,
+ ; but MUST NOT occur more than once
+
+ prodid /version /
+
+ ; 'calscale' and 'method' are optional,
+ ; but MUST NOT occur more than once
+
+ calscale /
+ method /
+
+ x-prop
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 51]</span>
+</pre><pre class="newpage"><a name="page-52" id="page-52" href="#page-52" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ )
+
+ component = 1*(eventc / todoc / journalc / freebusyc /
+ / timezonec / iana-comp / x-comp)
+
+ iana-comp = "BEGIN" ":" iana-token CRLF
+
+ 1*contentline
+
+ "END" ":" iana-token CRLF
+
+ x-comp = "BEGIN" ":" x-name CRLF
+
+ 1*contentline
+
+ "END" ":" x-name CRLF
+
+ An iCalendar object MUST include the "PRODID" and "VERSION" calendar
+ properties. In addition, it MUST include at least one calendar
+ component. Special forms of iCalendar objects are possible to publish
+ just busy time (i.e., only a "VFREEBUSY" calendar component) or time
+ zone (i.e., only a "VTIMEZONE" calendar component) information. In
+ addition, a complex iCalendar object is possible that is used to
+ capture a complete snapshot of the contents of a calendar (e.g.,
+ composite of many different calendar components). More commonly, an
+ iCalendar object will consist of just a single "VEVENT", "VTODO" or
+ "VJOURNAL" calendar component.
+
+<span class="h4"><h4><a name="section-4.6.1">4.6.1</a> Event Component</h4></span>
+
+ Component Name: "VEVENT"
+
+ Purpose: Provide a grouping of component properties that describe an
+ event.
+
+ Format Definition: A "VEVENT" calendar component is defined by the
+ following notation:
+
+ eventc = "BEGIN" ":" "VEVENT" CRLF
+ eventprop *alarmc
+ "END" ":" "VEVENT" CRLF
+
+ eventprop = *(
+
+ ; the following are optional,
+ ; but MUST NOT occur more than once
+
+ class / created / description / dtstart / geo /
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 52]</span>
+</pre><pre class="newpage"><a name="page-53" id="page-53" href="#page-53" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ last-mod / location / organizer / priority /
+ dtstamp / seq / status / summary / transp /
+ uid / url / recurid /
+
+ ; either 'dtend' or 'duration' may appear in
+ ; a 'eventprop', but 'dtend' and 'duration'
+ ; MUST NOT occur in the same 'eventprop'
+
+ dtend / duration /
+
+ ; the following are optional,
+ ; and MAY occur more than once
+
+ attach / attendee / categories / comment /
+ contact / exdate / exrule / rstatus / related /
+ resources / rdate / rrule / x-prop
+
+ )
+
+ Description: A "VEVENT" calendar component is a grouping of component
+ properties, and possibly including "VALARM" 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. Hence, the event will appear as an opaque
+ interval in a search for busy time. Alternately, the event can have
+ its Time Transparency set to "TRANSPARENT" in order to prevent
+ blocking of the event in searches for busy time.
+
+ The "VEVENT" is also the calendar component used to specify an
+ anniversary or daily reminder within a calendar. These events have a
+ DATE value type for the "DTSTART" property instead of the default
+ data type of DATE-TIME. If such a "VEVENT" has a "DTEND" property, it
+ MUST be specified as a DATE value also. The anniversary type of
+ "VEVENT" can span more than one date (i.e, "DTEND" property value is
+ set to a calendar date after the "DTSTART" property value).
+
+ The "DTSTART" property for a "VEVENT" specifies the inclusive start
+ of the event. For recurring events, it also specifies the very first
+ instance in the recurrence set. The "DTEND" property for a "VEVENT"
+ calendar component specifies the non-inclusive end of the event. For
+ cases where a "VEVENT" calendar component specifies a "DTSTART"
+ property with a DATE data type but no "DTEND" property, the events
+ non-inclusive end is the end of the calendar date specified by the
+ "DTSTART" property. For cases where a "VEVENT" calendar component
+ specifies a "DTSTART" property with a DATE-TIME data type but no
+ "DTEND" property, the event ends on the same calendar date and time
+ of day specified by the "DTSTART" property.
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 53]</span>
+</pre><pre class="newpage"><a name="page-54" id="page-54" href="#page-54" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ The "VEVENT" calendar component cannot be nested within another
+ calendar component. However, "VEVENT" calendar components can be
+ related to each other or to a "VTODO" or to a "VJOURNAL" calendar
+ component with the "RELATED-TO" property.
+
+ Example: The following is an example of the "VEVENT" calendar
+ component used to represent a meeting that will also be opaque to
+ searches for busy time:
+
+ BEGIN:VEVENT
+ UID:19970901T130000Z-123401@host.com
+ DTSTAMP:19970901T1300Z
+ DTSTART:19970903T163000Z
+ DTEND:19970903T190000Z
+ SUMMARY:Annual Employee Review
+ CLASS:PRIVATE
+ CATEGORIES:BUSINESS,HUMAN RESOURCES
+ END:VEVENT
+
+ The following is an example of the "VEVENT" calendar component used
+ to represent a reminder that will not be opaque, but rather
+ transparent, to searches for busy time:
+
+ BEGIN:VEVENT
+ UID:19970901T130000Z-123402@host.com
+ DTSTAMP:19970901T1300Z
+ DTSTART:19970401T163000Z
+ DTEND:19970402T010000Z
+ SUMMARY:Laurel is in sensitivity awareness class.
+ CLASS:PUBLIC
+ CATEGORIES:BUSINESS,HUMAN RESOURCES
+ TRANSP:TRANSPARENT
+ END:VEVENT
+
+ The following is an example of the "VEVENT" calendar component used
+ to represent an anniversary that will occur annually. Since it takes
+ up no time, it will not appear as opaque in a search for busy time;
+ no matter what the value of the "TRANSP" property indicates:
+
+ BEGIN:VEVENT
+ UID:19970901T130000Z-123403@host.com
+ DTSTAMP:19970901T1300Z
+ DTSTART:19971102
+ SUMMARY:Our Blissful Anniversary
+ CLASS:CONFIDENTIAL
+ CATEGORIES:ANNIVERSARY,PERSONAL,SPECIAL OCCASION
+ RRULE:FREQ=YEARLY
+ END:VEVENT
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 54]</span>
+</pre><pre class="newpage"><a name="page-55" id="page-55" href="#page-55" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+<span class="h4"><h4><a name="section-4.6.2">4.6.2</a> To-do Component</h4></span>
+
+ Component Name: VTODO
+
+ Purpose: Provide a grouping of calendar properties that describe a
+ to-do.
+
+ Formal Definition: A "VTODO" calendar component is defined by the
+ following notation:
+
+ todoc = "BEGIN" ":" "VTODO" CRLF
+ todoprop *alarmc
+ "END" ":" "VTODO" CRLF
+
+ todoprop = *(
+
+ ; the following are optional,
+ ; but MUST NOT occur more than once
+
+ class / completed / created / description / dtstamp /
+ dtstart / geo / last-mod / location / organizer /
+ percent / priority / recurid / seq / status /
+ summary / uid / url /
+
+ ; either 'due' or 'duration' may appear in
+ ; a 'todoprop', but 'due' and 'duration'
+ ; MUST NOT occur in the same 'todoprop'
+
+ due / duration /
+
+ ; the following are optional,
+ ; and MAY occur more than once
+ attach / attendee / categories / comment / contact /
+ exdate / exrule / rstatus / related / resources /
+ rdate / rrule / x-prop
+
+ )
+
+ Description: A "VTODO" calendar component is a grouping of component
+ properties and possibly "VALARM" calendar components that represent
+ an action-item or assignment. For example, it can be used to
+ represent an item of work assigned to an individual; such as "turn in
+ travel expense today".
+
+ The "VTODO" calendar component cannot be nested within another
+ calendar component. However, "VTODO" calendar components can be
+ related to each other or to a "VTODO" or to a "VJOURNAL" calendar
+ component with the "RELATED-TO" property.
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 55]</span>
+</pre><pre class="newpage"><a name="page-56" id="page-56" href="#page-56" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ A "VTODO" calendar component without the "DTSTART" and "DUE" (or
+ "DURATION") properties specifies a to-do that will be associated with
+ each successive calendar date, until it is completed.
+
+ Example: The following is an example of a "VTODO" calendar component:
+
+ BEGIN:VTODO
+ UID:19970901T130000Z-123404@host.com
+ DTSTAMP:19970901T1300Z
+ DTSTART:19970415T133000Z
+ DUE:19970416T045959Z
+ SUMMARY:1996 Income Tax Preparation
+ CLASS:CONFIDENTIAL
+ CATEGORIES:FAMILY,FINANCE
+ PRIORITY:1
+ STATUS:NEEDS-ACTION
+ END:VTODO
+
+<span class="h4"><h4><a name="section-4.6.3">4.6.3</a> Journal Component</h4></span>
+
+ Component Name: VJOURNAL
+
+ Purpose: Provide a grouping of component properties that describe a
+ journal entry.
+
+ Formal Definition: A "VJOURNAL" calendar component is defined by the
+ following notation:
+
+ journalc = "BEGIN" ":" "VJOURNAL" CRLF
+ jourprop
+ "END" ":" "VJOURNAL" CRLF
+
+ jourprop = *(
+
+ ; the following are optional,
+ ; but MUST NOT occur more than once
+
+ class / created / description / dtstart / dtstamp /
+ last-mod / organizer / recurid / seq / status /
+ summary / uid / url /
+
+ ; the following are optional,
+ ; and MAY occur more than once
+
+ attach / attendee / categories / comment /
+ contact / exdate / exrule / related / rdate /
+ rrule / rstatus / x-prop
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 56]</span>
+</pre><pre class="newpage"><a name="page-57" id="page-57" href="#page-57" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ )
+
+ Description: A "VJOURNAL" 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 "VJOURNAL"
+ calendar component can also be used to associate a document with a
+ calendar date.
+
+ The "VJOURNAL" calendar component does not take up time on a
+ calendar. Hence, it does not play a role in free or busy time
+ searches - - it is as though it has a time transparency value of
+ TRANSPARENT. It is transparent to any such searches.
+
+ The "VJOURNAL" calendar component cannot be nested within another
+ calendar component. However, "VJOURNAL" calendar components can be
+ related to each other or to a "VEVENT" or to a "VTODO" calendar
+ component, with the "RELATED-TO" property.
+
+ Example: The following is an example of the "VJOURNAL" calendar
+ component:
+
+ BEGIN:VJOURNAL
+ UID:19970901T130000Z-123405@host.com
+ DTSTAMP:19970901T1300Z
+ DTSTART;VALUE=DATE:19970317
+ SUMMARY:Staff meeting minutes
+ DESCRIPTION:1. Staff meeting: Participants include Joe\, Lisa
+ and Bob. Aurora project plans were reviewed. There is currently
+ no budget reserves for this project. Lisa will escalate to
+ management. Next meeting on Tuesday.\n
+ 2. Telephone Conference: ABC Corp. sales representative called
+ to discuss new printer. Promised to get us a demo by Friday.\n
+ 3. Henry Miller (Handsoff Insurance): Car was totaled by tree.
+ Is looking into a loaner car. 654-2323 (tel).
+ END:VJOURNAL
+
+
+
+
+
+
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 57]</span>
+</pre><pre class="newpage"><a name="page-58" id="page-58" href="#page-58" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+<span class="h4"><h4><a name="section-4.6.4">4.6.4</a> Free/Busy Component</h4></span>
+
+ Component Name: VFREEBUSY
+
+ Purpose: Provide a grouping of component properties that describe
+ either a request for free/busy time, describe a response to a request
+ for free/busy time or describe a published set of busy time.
+
+ Formal Definition: A "VFREEBUSY" calendar component is defined by the
+ following notation:
+
+ freebusyc = "BEGIN" ":" "VFREEBUSY" CRLF
+ fbprop
+ "END" ":" "VFREEBUSY" CRLF
+
+ fbprop = *(
+
+ ; the following are optional,
+ ; but MUST NOT occur more than once
+
+ contact / dtstart / dtend / duration / dtstamp /
+ organizer / uid / url /
+
+ ; the following are optional,
+ ; and MAY occur more than once
+
+ attendee / comment / freebusy / rstatus / x-prop
+
+ )
+
+ Description: A "VFREEBUSY" 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.
+
+ When used to request free/busy time information, the "ATTENDEE"
+ property specifies the calendar users whose free/busy time is being
+ requested; the "ORGANIZER" property specifies the calendar user who
+ is requesting the free/busy time; the "DTSTART" and "DTEND"
+ properties specify the window of time for which the free/busy time is
+ being requested; the "UID" and "DTSTAMP" properties are specified to
+ assist in proper sequencing of multiple free/busy time requests.
+
+ When used to reply to a request for free/busy time, the "ATTENDEE"
+ property specifies the calendar user responding to the free/busy time
+ request; the "ORGANIZER" property specifies the calendar user that
+ originally requested the free/busy time; the "FREEBUSY" property
+ specifies the free/busy time information (if it exists); and the
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 58]</span>
+</pre><pre class="newpage"><a name="page-59" id="page-59" href="#page-59" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ "UID" and "DTSTAMP" properties are specified to assist in proper
+ sequencing of multiple free/busy time replies.
+
+ When used to publish busy time, the "ORGANIZER" property specifies
+ the calendar user associated with the published busy time; the
+ "DTSTART" and "DTEND" properties specify an inclusive time window
+ that surrounds the busy time information; the "FREEBUSY" property
+ specifies the published busy time information; and the "DTSTAMP"
+ property specifies the date/time that iCalendar object was created.
+
+ The "VFREEBUSY" calendar component cannot be nested within another
+ calendar component. Multiple "VFREEBUSY" calendar components can be
+ specified within an iCalendar object. This permits the grouping of
+ Free/Busy information into logical collections, such as monthly
+ groups of busy time information.
+
+ The "VFREEBUSY" calendar component is intended for use in iCalendar
+ object methods involving requests for free time, requests for busy
+ time, requests for both free and busy, and the associated replies.
+
+ Free/Busy information is represented with the "FREEBUSY" property.
+ This property provides a terse representation of time periods. One or
+ more "FREEBUSY" properties can be specified in the "VFREEBUSY"
+ calendar component.
+
+ When present in a "VFREEBUSY" calendar component, the "DTSTART" and
+ "DTEND" properties SHOULD be specified prior to any "FREEBUSY"
+ properties. In a free time request, these properties can be used in
+ combination with the "DURATION" property to represent a request for a
+ duration of free time within a specified window of time.
+
+ The recurrence properties ("RRULE", "EXRULE", "RDATE", "EXDATE") are
+ not permitted within a "VFREEBUSY" calendar component. Any recurring
+ events are resolved into their individual busy time periods using the
+ "FREEBUSY" property.
+
+ Example: The following is an example of a "VFREEBUSY" calendar
+ component used to request free or busy time information:
+
+ BEGIN:VFREEBUSY
+ ORGANIZER:MAILTO:jane_doe@host1.com
+ ATTENDEE:MAILTO:john_public@host2.com
+ DTSTART:19971015T050000Z
+ DTEND:19971016T050000Z
+ DTSTAMP:19970901T083000Z
+ END:VFREEBUSY
+
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 59]</span>
+</pre><pre class="newpage"><a name="page-60" id="page-60" href="#page-60" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ The following is an example of a "VFREEBUSY" calendar component used
+ to reply to the request with busy time information:
+
+ BEGIN:VFREEBUSY
+ ORGANIZER:MAILTO:jane_doe@host1.com
+ ATTENDEE:MAILTO:john_public@host2.com
+ DTSTAMP:19970901T100000Z
+ FREEBUSY;VALUE=PERIOD:19971015T050000Z/PT8H30M,
+ 19971015T160000Z/PT5H30M,19971015T223000Z/PT6H30M
+ URL:http://host2.com/pub/busy/jpublic-01.ifb
+ COMMENT:This iCalendar file contains busy time information for
+ the next three months.
+ END:VFREEBUSY
+
+ The following is an example of a "VFREEBUSY" calendar component used
+ to publish busy time information.
+
+ BEGIN:VFREEBUSY
+ ORGANIZER:jsmith@host.com
+ DTSTART:19980313T141711Z
+ DTEND:19980410T141711Z
+ FREEBUSY:19980314T233000Z/19980315T003000Z
+ FREEBUSY:19980316T153000Z/19980316T163000Z
+ FREEBUSY:19980318T030000Z/19980318T040000Z
+ URL:http://www.host.com/calendar/busytime/jsmith.ifb
+ END:VFREEBUSY
+
+<span class="h4"><h4><a name="section-4.6.5">4.6.5</a> Time Zone Component</h4></span>
+
+ Component Name: VTIMEZONE
+
+ Purpose: Provide a grouping of component properties that defines a
+ time zone.
+
+ Formal Definition: A "VTIMEZONE" calendar component is defined by the
+ following notation:
+
+ timezonec = "BEGIN" ":" "VTIMEZONE" CRLF
+
+ 2*(
+
+ ; 'tzid' is required, but MUST NOT occur more
+ ; than once
+
+ tzid /
+
+ ; 'last-mod' and 'tzurl' are optional,
+ but MUST NOT occur more than once
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 60]</span>
+</pre><pre class="newpage"><a name="page-61" id="page-61" href="#page-61" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ last-mod / tzurl /
+
+ ; one of 'standardc' or 'daylightc' MUST occur
+ ..; and each MAY occur more than once.
+
+ standardc / daylightc /
+
+ ; the following is optional,
+ ; and MAY occur more than once
+
+ x-prop
+
+ )
+
+ "END" ":" "VTIMEZONE" CRLF
+
+ standardc = "BEGIN" ":" "STANDARD" CRLF
+
+ tzprop
+
+ "END" ":" "STANDARD" CRLF
+
+ daylightc = "BEGIN" ":" "DAYLIGHT" CRLF
+
+ tzprop
+
+ "END" ":" "DAYLIGHT" CRLF
+
+ tzprop = 3*(
+
+ ; the following are each REQUIRED,
+ ; but MUST NOT occur more than once
+
+ dtstart / tzoffsetto / tzoffsetfrom /
+
+ ; the following are optional,
+ ; and MAY occur more than once
+
+ comment / rdate / rrule / tzname / x-prop
+
+ )
+
+ Description: A time zone 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
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 61]</span>
+</pre><pre class="newpage"><a name="page-62" id="page-62" href="#page-62" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ 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.
+
+ Effective Observance Rule
+
+ Date (Date/Time) Offset Abbreviation
+
+ 1967-* last Sun in Oct, 02:00 -0500 EST
+
+ 1967-1973 last Sun in Apr, 02:00 -0400 EDT
+
+ 1974-1974 Jan 6, 02:00 -0400 EDT
+
+ 1975-1975 Feb 23, 02:00 -0400 EDT
+
+ 1976-1986 last Sun in Apr, 02:00 -0400 EDT
+
+ 1987-* first Sun in Apr, 02:00 -0400 EDT
+
+ Note: The specification of a global time zone registry is not
+ addressed by this document and is left for future study.
+ However, implementers may find the Olson time zone database [<a href="#ref-TZ" title=""ftp://elsie.nci.nih.gov/pub/"">TZ</a>]
+ a useful reference. It is an informal, public-domain collection
+ of time zone information, which is currently being maintained by
+ volunteer Internet participants, and is used in several
+ operating systems. This database contains current and historical
+ time zone information for a wide variety of locations around the
+ globe; it provides a time zone identifier for every unique time
+ zone rule set in actual use since 1970, with historical data
+ going back to the introduction of standard time.
+
+ Interoperability between two calendaring and scheduling applications,
+ especially for recurring events, to-dos or journal entries, is
+ dependent on the ability to capture and convey date and time
+ information in an unambiguous format. The specification of current
+ time zone information is integral to this behavior.
+
+ If present, the "VTIMEZONE" calendar component defines the set of
+ Standard Time and Daylight Saving Time observances (or rules) for a
+ particular time zone for a given interval of time. The "VTIMEZONE"
+ calendar component cannot be nested within other calendar components.
+ Multiple "VTIMEZONE" calendar components can exist in an iCalendar
+ object. In this situation, each "VTIMEZONE" MUST represent a unique
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 62]</span>
+</pre><pre class="newpage"><a name="page-63" id="page-63" href="#page-63" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ time zone definition. This is necessary for some classes of events,
+ such as airline flights, that start in one time zone and end in
+ another.
+
+ The "VTIMEZONE" calendar component MUST be present if the iCalendar
+ object contains an RRULE that generates dates on both sides of a time
+ zone shift (e.g. both in Standard Time and Daylight Saving Time)
+ unless the iCalendar object intends to convey a floating time (See
+ the section "4.1.10.11 Time" for proper interpretation of floating
+ time). It can be present if the iCalendar object does not contain
+ such a RRULE. In addition, if a RRULE is present, there MUST be valid
+ time zone information for all recurrence instances.
+
+ The "VTIMEZONE" calendar component MUST include the "TZID" property
+ and at least one definition of a standard or daylight component. The
+ standard or daylight component MUST include the "DTSTART",
+ "TZOFFSETFROM" and "TZOFFSETTO" properties.
+
+ An individual "VTIMEZONE" calendar component MUST be specified for
+ each unique "TZID" parameter value specified in the iCalendar object.
+
+ Each "VTIMEZONE" calendar component consists of a collection of one
+ or more sub-components that describe the rule for a particular
+ observance (either a Standard Time or a Daylight Saving Time
+ observance). The "STANDARD" sub-component consists of a collection of
+ properties that describe Standard Time. The "DAYLIGHT" sub-component
+ consists of a collection of properties that describe Daylight Saving
+ Time. In general this collection of properties consists of:
+
+ - the first onset date-time for the observance
+
+ - the last onset date-time for the observance, if a last onset
+ is known.
+
+ - the offset to be applied for the observance
+
+ - a rule that describes the day and time when the observance
+ takes effect
+
+ - an optional name for the observance
+
+ For a given time zone, there may be multiple unique definitions of
+ the observances over a period of time. Each observance is described
+ using either a "STANDARD" or "DAYLIGHT" sub-component. The collection
+ of these sub-components is used to describe the time zone for a given
+ period of time. The offset to apply at any given time is found by
+ locating the observance that has the last onset date and time before
+ the time in question, and using the offset value from that
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 63]</span>
+</pre><pre class="newpage"><a name="page-64" id="page-64" href="#page-64" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ observance.
+
+ The top-level properties in a "VTIMEZONE" calendar component are:
+
+ The mandatory "TZID" property is a text value that uniquely
+ identifies the VTIMZONE calendar component within the scope of an
+ iCalendar object.
+
+ The optional "LAST-MODIFIED" property is a UTC value that specifies
+ the date and time that this time zone definition was last updated.
+
+ The optional "TZURL" property is url value that points to a published
+ VTIMEZONE definition. TZURL SHOULD refer to a resource that is
+ accessible by anyone who might need to interpret the object. This
+ SHOULD NOT normally be a file: URL or other URL that is not widely-
+ accessible.
+
+ The collection of properties that are used to define the STANDARD and
+ DAYLIGHT sub-components include:
+
+ The mandatory "DTSTART" property gives the effective onset date and
+ local time for the time zone sub-component definition. "DTSTART" in
+ this usage MUST be specified as a local DATE-TIME value.
+
+ The mandatory "TZOFFSETFROM" property gives the UTC offset which is
+ in use when the onset of this time zone observance begins.
+ "TZOFFSETFROM" is combined with "DTSTART" to define the effective
+ onset for the time zone sub-component definition. For example, the
+ following represents the time at which the observance of Standard
+ Time took effect in Fall 1967 for New York City:
+
+ DTSTART:19671029T020000
+
+ TZOFFSETFROM:-0400
+
+ The mandatory "TZOFFSETTO " property gives the UTC offset for the
+ time zone sub-component (Standard Time or Daylight Saving Time) when
+ this observance is in use.
+
+ The optional "TZNAME" property is the customary name for the time
+ zone. It may be specified multiple times, to allow for specifying
+ multiple language variants of the time zone names. This could be used
+ for displaying dates.
+
+ If specified, the onset for the observance defined by the time zone
+ sub-component is defined by either the "RRULE" or "RDATE" property.
+ If neither is specified, only one sub-component can be specified in
+ the "VTIMEZONE" calendar component and it is assumed that the single
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 64]</span>
+</pre><pre class="newpage"><a name="page-65" id="page-65" href="#page-65" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ observance specified is always in effect.
+
+ The "RRULE" property defines the recurrence rule for the onset of the
+ observance defined by this time zone sub-component. Some specific
+ requirements for the usage of RRULE for this purpose include:
+
+ - If observance is known to have an effective end date, the
+ "UNTIL" recurrence rule parameter MUST be used to specify the
+ last valid onset of this observance (i.e., the UNTIL date-time
+ will be equal to the last instance generated by the recurrence
+ pattern). It MUST be specified in UTC time.
+
+ - The "DTSTART" and the "TZOFFSETTO" properties MUST be used
+ when generating the onset date-time values (instances) from the
+ RRULE.
+
+ Alternatively, the "RDATE" property can be used to define the onset
+ of the observance by giving the individual onset date and times.
+ "RDATE" in this usage MUST be specified as a local DATE-TIME value in
+ UTC time.
+
+ The optional "COMMENT" property is also allowed for descriptive
+ explanatory text.
+
+ Example: The following are examples of the "VTIMEZONE" calendar
+ component:
+
+ This is an example showing time zone information for the Eastern
+ United States using "RDATE" property. Note that this is only suitable
+ for a recurring event that starts on or later than April 6, 1997 at
+ 03:00:00 EDT (i.e., the earliest effective transition date and time)
+ and ends no later than April 7, 1998 02:00:00 EST (i.e., latest valid
+ date and time for EST in this scenario). For example, this can be
+ used for a recurring event that occurs every Friday, 8am-9:00 AM,
+ starting June 1, 1997, ending December 31, 1997.
+
+ BEGIN:VTIMEZONE
+ TZID:US-Eastern
+ LAST-MODIFIED:19870101T000000Z
+ BEGIN:STANDARD
+ DTSTART:19971026T020000
+ RDATE:19971026T020000
+ TZOFFSETFROM:-0400
+ TZOFFSETTO:-0500
+ TZNAME:EST
+ END:STANDARD
+ BEGIN:DAYLIGHT
+ DTSTART:19971026T020000
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 65]</span>
+</pre><pre class="newpage"><a name="page-66" id="page-66" href="#page-66" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ RDATE:19970406T020000
+ TZOFFSETFROM:-0500
+ TZOFFSETTO:-0400
+ TZNAME:EDT
+ END:DAYLIGHT
+ END:VTIMEZONE
+
+ This is a simple example showing the current time zone rules for the
+ Eastern United States using a RRULE recurrence pattern. Note that
+ there is no effective end date to either of the Standard Time or
+ Daylight Time rules. This information would be valid for a recurring
+ event starting today and continuing indefinitely.
+
+ BEGIN:VTIMEZONE
+ TZID:US-Eastern
+ LAST-MODIFIED:19870101T000000Z
+ TZURL:http://zones.stds_r_us.net/tz/US-Eastern
+ BEGIN:STANDARD
+ DTSTART:19671029T020000
+ RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+ TZOFFSETFROM:-0400
+ TZOFFSETTO:-0500
+ TZNAME:EST
+ END:STANDARD
+ BEGIN:DAYLIGHT
+ DTSTART:19870405T020000
+ RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+ TZOFFSETFROM:-0500
+ TZOFFSETTO:-0400
+ TZNAME:EDT
+ END:DAYLIGHT
+ END:VTIMEZONE
+
+ This is an example showing a fictitious set of rules for the Eastern
+ United States, where the Daylight Time rule has an effective end date
+ (i.e., after that date, Daylight Time is no longer observed).
+
+ BEGIN:VTIMEZONE
+ TZID:US--Fictitious-Eastern
+ LAST-MODIFIED:19870101T000000Z
+ BEGIN:STANDARD
+ DTSTART:19671029T020000
+ RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+ TZOFFSETFROM:-0400
+ TZOFFSETTO:-0500
+ TZNAME:EST
+ END:STANDARD
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 66]</span>
+</pre><pre class="newpage"><a name="page-67" id="page-67" href="#page-67" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ BEGIN:DAYLIGHT
+ DTSTART:19870405T020000
+ RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4;UNTIL=19980404T070000Z
+ TZOFFSETFROM:-0500
+ TZOFFSETTO:-0400
+ TZNAME:EDT
+ END:DAYLIGHT
+ END:VTIMEZONE
+
+ This is an example showing a fictitious set of rules for the Eastern
+ United States, where the first Daylight Time rule has an effective
+ end date. There is a second Daylight Time rule that picks up where
+ the other left off.
+
+ BEGIN:VTIMEZONE
+ TZID:US--Fictitious-Eastern
+ LAST-MODIFIED:19870101T000000Z
+ BEGIN:STANDARD
+ DTSTART:19671029T020000
+ RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+ TZOFFSETFROM:-0400
+ TZOFFSETTO:-0500
+ TZNAME:EST
+ END:STANDARD
+ BEGIN:DAYLIGHT
+ DTSTART:19870405T020000
+ RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4;UNTIL=19980404T070000Z
+ TZOFFSETFROM:-0500
+ TZOFFSETTO:-0400
+ TZNAME:EDT
+ END:DAYLIGHT
+ BEGIN:DAYLIGHT
+ DTSTART:19990424T020000
+ RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=4
+ TZOFFSETFROM:-0500
+ TZOFFSETTO:-0400
+ TZNAME:EDT
+ END:DAYLIGHT
+ END:VTIMEZONE
+
+<span class="h4"><h4><a name="section-4.6.6">4.6.6</a> Alarm Component</h4></span>
+
+ Component Name: VALARM
+
+ Purpose: Provide a grouping of component properties that define an
+ alarm.
+
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 67]</span>
+</pre><pre class="newpage"><a name="page-68" id="page-68" href="#page-68" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ Formal Definition: A "VALARM" calendar component is defined by the
+ following notation:
+
+ alarmc = "BEGIN" ":" "VALARM" CRLF
+ (audioprop / dispprop / emailprop / procprop)
+ "END" ":" "VALARM" CRLF
+
+ audioprop = 2*(
+
+ ; 'action' and 'trigger' are both REQUIRED,
+ ; but MUST NOT occur more than once
+
+ action / trigger /
+
+ ; 'duration' and 'repeat' are both optional,
+ ; and MUST NOT occur more than once each,
+ ; but if one occurs, so MUST the other
+
+ duration / repeat /
+
+ ; the following is optional,
+ ; but MUST NOT occur more than once
+
+ attach /
+
+ ; the following is optional,
+ ; and MAY occur more than once
+
+ x-prop
+
+ )
+
+
+
+ dispprop = 3*(
+
+ ; the following are all REQUIRED,
+ ; but MUST NOT occur more than once
+
+ action / description / trigger /
+
+ ; 'duration' and 'repeat' are both optional,
+ ; and MUST NOT occur more than once each,
+ ; but if one occurs, so MUST the other
+
+ duration / repeat /
+
+ ; the following is optional,
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 68]</span>
+</pre><pre class="newpage"><a name="page-69" id="page-69" href="#page-69" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ ; and MAY occur more than once
+
+ *x-prop
+
+ )
+
+
+
+ emailprop = 5*(
+
+ ; the following are all REQUIRED,
+ ; but MUST NOT occur more than once
+
+ action / description / trigger / summary
+
+ ; the following is REQUIRED,
+ ; and MAY occur more than once
+
+ attendee /
+
+ ; 'duration' and 'repeat' are both optional,
+ ; and MUST NOT occur more than once each,
+ ; but if one occurs, so MUST the other
+
+ duration / repeat /
+
+ ; the following are optional,
+ ; and MAY occur more than once
+
+ attach / x-prop
+
+ )
+
+
+
+ procprop = 3*(
+
+ ; the following are all REQUIRED,
+ ; but MUST NOT occur more than once
+
+ action / attach / trigger /
+
+ ; 'duration' and 'repeat' are both optional,
+ ; and MUST NOT occur more than once each,
+ ; but if one occurs, so MUST the other
+
+ duration / repeat /
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 69]</span>
+</pre><pre class="newpage"><a name="page-70" id="page-70" href="#page-70" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ ; 'description' is optional,
+ ; and MUST NOT occur more than once
+
+ description /
+
+ ; the following is optional,
+ ; and MAY occur more than once
+
+ x-prop
+
+ )
+
+ Description: A "VALARM" 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 to-do.
+
+ The "VALARM" calendar component MUST include the "ACTION" and
+ "TRIGGER" properties. The "ACTION" property further constrains the
+ "VALARM" calendar component in the following ways:
+
+ When the action is "AUDIO", the alarm can also include one and only
+ one "ATTACH" property, which MUST point to a sound resource, which is
+ rendered when the alarm is triggered.
+
+ When the action is "DISPLAY", the alarm MUST also include a
+ "DESCRIPTION" property, which contains the text to be displayed when
+ the alarm is triggered.
+
+ When the action is "EMAIL", the alarm MUST include a "DESCRIPTION"
+ property, which contains the text to be used as the message body, a
+ "SUMMARY" property, which contains the text to be used as the message
+ subject, and one or more "ATTENDEE" properties, which contain the
+ email address of attendees to receive the message. It can also
+ include one or more "ATTACH" properties, which are intended to be
+ sent as message attachments. When the alarm is triggered, the email
+ message is sent.
+
+ When the action is "PROCEDURE", the alarm MUST include one and only
+ one "ATTACH" property, which MUST point to a procedure resource,
+ which is invoked when the alarm is triggered.
+
+ The "VALARM" calendar component MUST only appear within either a
+ "VEVENT" or "VTODO" calendar component. "VALARM" calendar components
+ cannot be nested. Multiple mutually independent "VALARM" calendar
+ components can be specified for a single "VEVENT" or "VTODO" calendar
+ component.
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 70]</span>
+</pre><pre class="newpage"><a name="page-71" id="page-71" href="#page-71" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ The "TRIGGER" property specifies when the alarm will be triggered.
+ The "TRIGGER" property specifies a duration prior to the start of an
+ event or a to-do. The "TRIGGER" edge may be explicitly set to be
+ relative to the "START" or "END" of the event or to-do with the
+ "RELATED" parameter of the "TRIGGER" property. The "TRIGGER" property
+ value type can alternatively be set to an absolute calendar date and
+ time of day value.
+
+ In an alarm set to trigger on the "START" of an event or to-do, the
+ "DTSTART" property MUST be present in the associated event or to-do.
+ In an alarm in a "VEVENT" calendar component set to trigger on the
+ "END" of the event, either the "DTEND" property MUST be present, or
+ the "DTSTART" and "DURATION" properties MUST both be present. In an
+ alarm in a "VTODO" calendar component set to trigger on the "END" of
+ the to-do, either the "DUE" property MUST be present, or the
+ "DTSTART" and "DURATION" properties MUST both be present.
+
+ The alarm can be defined such that it triggers repeatedly. A
+ definition of an alarm with a repeating trigger MUST include both the
+ "DURATION" and "REPEAT" properties. The "DURATION" property specifies
+ the delay period, after which the alarm will repeat. The "REPEAT"
+ property specifies the number of additional repetitions that the
+ alarm will triggered. This repitition count is in addition to the
+ initial triggering of the alarm. Both of these properties MUST be
+ present in order to specify a repeating alarm. If one of these two
+ properties is absent, then the alarm will not repeat beyond the
+ initial trigger.
+
+ The "ACTION" property is used within the "VALARM" calendar component
+ to specify the type of action invoked when the alarm is triggered.
+ The "VALARM" properties provide enough information for a specific
+ action to be invoked. It is typically the responsibility of a
+ "Calendar User Agent" (CUA) to deliver the alarm in the specified
+ fashion. An "ACTION" property value of AUDIO specifies an alarm that
+ causes a sound to be played to alert the user; DISPLAY specifies an
+ alarm that causes a text message to be displayed to the user; EMAIL
+ specifies an alarm that causes an electronic email message to be
+ delivered to one or more email addresses; and PROCEDURE specifies an
+ alarm that causes a procedure to be executed. The "ACTION" property
+ MUST specify one and only one of these values.
+
+ In an AUDIO alarm, if the optional "ATTACH" property is included, it
+ MUST specify an audio sound resource. The intention is that the sound
+ will be played as the alarm effect. If an "ATTACH" property is
+ specified that does not refer to a sound resource, or if the
+ specified sound resource cannot be rendered (because its format is
+ unsupported, or because it cannot be retrieved), then the CUA or
+ other entity responsible for playing the sound may choose a fallback
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 71]</span>
+</pre><pre class="newpage"><a name="page-72" id="page-72" href="#page-72" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ action, such as playing a built-in default sound, or playing no sound
+ at all.
+
+ In a DISPLAY alarm, the intended alarm effect is for the text value
+ of the "DESCRIPTION" property to be displayed to the user.
+
+ In an EMAIL alarm, the intended alarm effect is for an email message
+ to be composed and delivered to all the addresses specified by the
+ "ATTENDEE" properties in the "VALARM" calendar component. The
+ "DESCRIPTION" property of the "VALARM" calendar component MUST be
+ used as the body text of the message, and the "SUMMARY" property MUST
+ be used as the subject text. Any "ATTACH" properties in the "VALARM"
+ calendar component SHOULD be sent as attachments to the message.
+
+ In a PROCEDURE alarm, the "ATTACH" property in the "VALARM" calendar
+ component MUST specify a procedure or program that is intended to be
+ invoked as the alarm effect. If the procedure or program is in a
+ format that cannot be rendered, then no procedure alarm will be
+ invoked. If the "DESCRIPTION" property is present, its value
+ specifies the argument string to be passed to the procedure or
+ program. "Calendar User Agents" that receive an iCalendar object with
+ this category of alarm, can disable or allow the "Calendar User" to
+ disable, or otherwise ignore this type of alarm. While a very useful
+ alarm capability, the PROCEDURE type of alarm SHOULD be treated by
+ the "Calendar User Agent" as a potential security risk.
+
+ Example: The following example is for a "VALARM" calendar component
+ that specifies an audio alarm that will sound at a precise time and
+ repeat 4 more times at 15 minute intervals:
+
+ BEGIN:VALARM
+ TRIGGER;VALUE=DATE-TIME:19970317T133000Z
+ REPEAT:4
+ DURATION:PT15M
+ ACTION:AUDIO
+ ATTACH;FMTTYPE=audio/basic:ftp://host.com/pub/sounds/bell-01.aud
+ END:VALARM
+
+ The following example is for a "VALARM" calendar component that
+ specifies a display alarm that will trigger 30 minutes before the
+ scheduled start of the event or the due date/time of the to-do it is
+ associated with and will repeat 2 more times at 15 minute intervals:
+
+ BEGIN:VALARM
+ TRIGGER:-PT30M
+ REPEAT:2
+ DURATION:PT15M
+ ACTION:DISPLAY
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 72]</span>
+</pre><pre class="newpage"><a name="page-73" id="page-73" href="#page-73" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ DESCRIPTION:Breakfast meeting with executive\n
+ team at 8:30 AM EST.
+ END:VALARM
+
+ The following example is for a "VALARM" calendar component that
+ specifies an email alarm that will trigger 2 days before the
+ scheduled due date/time of a to-do it is associated with. It does not
+ repeat. The email has a subject, body and attachment link.
+
+ BEGIN:VALARM
+ TRIGGER:-P2D
+ ACTION:EMAIL
+ ATTENDEE:MAILTO:john_doe@host.com
+ SUMMARY:*** REMINDER: SEND AGENDA FOR WEEKLY STAFF MEETING ***
+ DESCRIPTION:A draft agenda needs to be sent out to the attendees
+ to the weekly managers meeting (MGR-LIST). Attached is a
+ pointer the document template for the agenda file.
+ ATTACH;FMTTYPE=application/binary:http://host.com/templates/agen
+ da.doc
+ END:VALARM
+
+ The following example is for a "VALARM" calendar component that
+ specifies a procedural alarm that will trigger at a precise date/time
+ and will repeat 23 more times at one hour intervals. The alarm will
+ invoke a procedure file.
+
+ BEGIN:VALARM
+ TRIGGER;VALUE=DATE-TIME:19980101T050000Z
+ REPEAT:23
+ DURATION:PT1H
+ ACTION:PROCEDURE
+ ATTACH;FMTTYPE=application/binary:ftp://host.com/novo-
+ procs/felizano.exe
+ END:VALARM
+
+<span class="h3"><h3><a name="section-4.7">4.7</a> Calendar Properties</h3></span>
+
+ The Calendar Properties are attributes that apply to the iCalendar
+ object, as a whole. These properties do not appear within a calendar
+ component. They SHOULD be specified after the "BEGIN:VCALENDAR"
+ property and prior to any calendar component.
+
+<span class="h4"><h4><a name="section-4.7.1">4.7.1</a> Calendar Scale</h4></span>
+
+ Property Name: CALSCALE
+
+ Purpose: This property defines the calendar scale used for the
+ calendar information specified in the iCalendar object.
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 73]</span>
+</pre><pre class="newpage"><a name="page-74" id="page-74" href="#page-74" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ Value Type: TEXT
+
+ Property Parameters: Non-standard property parameters can be
+ specified on this property.
+
+ Conformance: Property can be specified in an iCalendar object. The
+ default value is "GREGORIAN".
+
+ Description: This memo is based on the Gregorian calendar scale. The
+ Gregorian calendar scale is assumed if this property is not specified
+ in the iCalendar object. It is expected that other calendar scales
+ will be defined in other specifications or by future versions of this
+ memo.
+
+ Format Definition: The property is defined by the following notation:
+
+ calscale = "CALSCALE" calparam ":" calvalue CRLF
+
+ calparam = *(";" xparam)
+
+ calvalue = "GREGORIAN" / iana-token
+
+ Example: The following is an example of this property:
+
+ CALSCALE:GREGORIAN
+
+<span class="h4"><h4><a name="section-4.7.2">4.7.2</a> Method</h4></span>
+
+ Property Name: METHOD
+
+ Purpose: This property defines the iCalendar object method associated
+ with the calendar object.
+
+ Value Type: TEXT
+
+ Property Parameters: Non-standard property parameters can be
+ specified on this property.
+
+ Conformance: The property can be specified in an iCalendar object.
+
+ Description: When used in a MIME message entity, the value of this
+ property MUST be the same as the Content-Type "method" parameter
+ value. This property can only appear once within the iCalendar
+ object. If either the "METHOD" property or the Content-Type "method"
+ parameter is specified, then the other MUST also be specified.
+
+ No methods are defined by this specification. This is the subject of
+ other specifications, such as the iCalendar Transport-independent
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 74]</span>
+</pre><pre class="newpage"><a name="page-75" id="page-75" href="#page-75" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ Interoperability Protocol (iTIP) defined by [<a href="#ref-ITIP" title=""iCalendar Transport-Independent Interoperability Protocol (iTIP) : Scheduling Events, Busy Time, To-dos and Journal Entries"">ITIP</a>].
+
+ If this property is not present in the iCalendar object, then a
+ scheduling transaction MUST NOT be assumed. In such cases, the
+ iCalendar object is merely being used to transport a snapshot of some
+ calendar information; without the intention of conveying a scheduling
+ semantic.
+
+ Format Definition: The property is defined by the following notation:
+
+ method = "METHOD" metparam ":" metvalue CRLF
+
+ metparam = *(";" xparam)
+
+ metvalue = iana-token
+
+ Example: The following is a hypothetical example of this property to
+ convey that the iCalendar object is a request for a meeting:
+
+ METHOD:REQUEST
+
+<span class="h4"><h4><a name="section-4.7.3">4.7.3</a> Product Identifier</h4></span>
+
+ Property Name: PRODID
+
+ Purpose: This property specifies the identifier for the product that
+ created the iCalendar object.
+
+ Value Type: TEXT
+
+ Property Parameters: Non-standard property parameters can be
+ specified on this property.
+
+ Conformance: The property MUST be specified once in an iCalendar
+ object.
+
+ Description: The vendor of the implementation SHOULD assure that this
+ is a globally unique identifier; using some technique such as an FPI
+ value, as defined in [ISO 9070].
+
+ This property SHOULD not be used to alter the interpretation of an
+ iCalendar object beyond the semantics specified in this memo. For
+ example, it is not to be used to further the understanding of non-
+ standard properties.
+
+ Format Definition: The property is defined by the following notation:
+
+ prodid = "PRODID" pidparam ":" pidvalue CRLF
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 75]</span>
+</pre><pre class="newpage"><a name="page-76" id="page-76" href="#page-76" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ pidparam = *(";" xparam)
+
+ pidvalue = text
+ ;Any text that describes the product and version
+ ;and that is generally assured of being unique.
+
+ Example: The following is an example of this property. It does not
+ imply that English is the default language.
+
+ PRODID:-//ABC Corporation//NONSGML My Product//EN
+
+<span class="h4"><h4><a name="section-4.7.4">4.7.4</a> Version</h4></span>
+
+ Property Name: VERSION
+
+ Purpose: This property specifies the identifier corresponding to the
+ highest version number or the minimum and maximum range of the
+ iCalendar specification that is required in order to interpret the
+ iCalendar object.
+
+ Value Type: TEXT
+
+ Property Parameters: Non-standard property parameters can be
+ specified on this property.
+
+ Conformance: This property MUST be specified by an iCalendar object,
+ but MUST only be specified once.
+
+ Description: A value of "2.0" corresponds to this memo.
+
+ Format Definition: The property is defined by the following notation:
+
+ version = "VERSION" verparam ":" vervalue CRLF
+
+ verparam = *(";" xparam)
+
+ vervalue = "2.0" ;This memo
+ / maxver
+ / (minver ";" maxver)
+
+ minver = <A IANA registered iCalendar version identifier>
+ ;Minimum iCalendar version needed to parse the iCalendar object
+
+ maxver = <A IANA registered iCalendar version identifier>
+ ;Maximum iCalendar version needed to parse the iCalendar object
+
+ Example: The following is an example of this property:
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 76]</span>
+</pre><pre class="newpage"><a name="page-77" id="page-77" href="#page-77" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ VERSION:2.0
+
+<span class="h3"><h3><a name="section-4.8">4.8</a> Component Properties</h3></span>
+
+ The following properties can appear within calendar components, as
+ specified by each component property definition.
+
+<span class="h4"><h4><a name="section-4.8.1">4.8.1</a> Descriptive Component Properties</h4></span>
+
+ The following properties specify descriptive information about
+ calendar components.
+
+<span class="h5"><h5><a name="section-4.8.1.1">4.8.1.1</a> Attachment</h5></span>
+
+ Property Name: ATTACH
+
+ Purpose: The property provides the capability to associate a document
+ object with a calendar component.
+
+ Value Type: The default value type for this property is URI. The
+ value type can also be set to BINARY to indicate inline binary
+ encoded content information.
+
+ Property Parameters: Non-standard, inline encoding, format type and
+ value data type property parameters can be specified on this
+ property.
+
+ Conformance: The property can be specified in a "VEVENT", "VTODO",
+ "VJOURNAL" or "VALARM" calendar components.
+
+ Description: The property can be specified within "VEVENT", "VTODO",
+ "VJOURNAL", or "VALARM" calendar components. This property can be
+ specified multiple times within an iCalendar object.
+
+ Format Definition: The property is defined by the following notation:
+
+ attach = "ATTACH" attparam ":" uri CRLF
+
+ attach =/ "ATTACH" attparam ";" "ENCODING" "=" "BASE64"
+ ";" "VALUE" "=" "BINARY" ":" binary
+
+ attparam = *(
+
+ ; the following is optional,
+ ; but MUST NOT occur more than once
+
+ (";" fmttypeparam) /
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 77]</span>
+</pre><pre class="newpage"><a name="page-78" id="page-78" href="#page-78" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ ; the following is optional,
+ ; and MAY occur more than once
+
+ (";" xparam)
+
+ )
+
+ Example: The following are examples of this property:
+
+ ATTACH:CID:jsmith.part3.960817T083000.xyzMail@host1.com
+
+ ATTACH;FMTTYPE=application/postscript:ftp://xyzCorp.com/pub/
+ reports/r-960812.ps
+
+<span class="h5"><h5><a name="section-4.8.1.2">4.8.1.2</a> Categories</h5></span>
+
+ Property Name: CATEGORIES
+
+ Purpose: This property defines the categories for a calendar
+ component.
+
+ Value Type: TEXT
+
+ Property Parameters: Non-standard and language property parameters
+ can be specified on this property.
+
+ Conformance: The property can be specified within "VEVENT", "VTODO"
+ or "VJOURNAL" calendar components.
+
+ Description: This property is used to specify categories or subtypes
+ of the calendar component. The categories are useful in searching for
+ a calendar component of a particular type and category. Within the
+ "VEVENT", "VTODO" or "VJOURNAL" calendar components, more than one
+ category can be specified as a list of categories separated by the
+ COMMA character (US-ASCII decimal 44).
+
+ Format Definition: The property is defined by the following notation:
+
+ categories = "CATEGORIES" catparam ":" text *("," text)
+ CRLF
+
+ catparam = *(
+
+ ; the following is optional,
+ ; but MUST NOT occur more than once
+
+ (";" languageparam ) /
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 78]</span>
+</pre><pre class="newpage"><a name="page-79" id="page-79" href="#page-79" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ ; the following is optional,
+ ; and MAY occur more than once
+
+ (";" xparam)
+
+ )
+
+ Example: The following are examples of this property:
+
+ CATEGORIES:APPOINTMENT,EDUCATION
+
+ CATEGORIES:MEETING
+
+<span class="h5"><h5><a name="section-4.8.1.3">4.8.1.3</a> Classification</h5></span>
+
+ Property Name: CLASS
+
+ Purpose: This property defines the access classification for a
+ calendar component.
+
+ Value Type: TEXT
+
+ Property Parameters: Non-standard property parameters can be
+ specified on this property.
+
+ Conformance: The property can be specified once in a "VEVENT",
+ "VTODO" or "VJOURNAL" calendar components.
+
+ Description: An access classification is only one component of the
+ general security system within a calendar application. It provides a
+ method of capturing the scope of the access the calendar owner
+ intends for information within an individual calendar entry. The
+ access classification of an individual iCalendar component is useful
+ when measured along with the other security components of a calendar
+ system (e.g., calendar user authentication, authorization, access
+ rights, access role, etc.). Hence, the semantics of the individual
+ access classifications cannot be completely defined by this memo
+ alone. Additionally, due to the "blind" nature of most exchange
+ processes using this memo, these access classifications cannot serve
+ as an enforcement statement for a system receiving an iCalendar
+ object. Rather, they provide a method for capturing the intention of
+ the calendar owner for the access to the calendar component.
+
+ Format Definition: The property is defined by the following notation:
+
+ class = "CLASS" classparam ":" classvalue CRLF
+
+ classparam = *(";" xparam)
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 79]</span>
+</pre><pre class="newpage"><a name="page-80" id="page-80" href="#page-80" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ classvalue = "PUBLIC" / "PRIVATE" / "CONFIDENTIAL" / iana-token
+ / x-name
+ ;Default is PUBLIC
+
+ Example: The following is an example of this property:
+
+ CLASS:PUBLIC
+
+<span class="h5"><h5><a name="section-4.8.1.4">4.8.1.4</a> Comment</h5></span>
+
+ Property Name: COMMENT
+
+ Purpose: This property specifies non-processing information intended
+ to provide a comment to the calendar user.
+
+ Value Type: TEXT
+
+ Property Parameters: Non-standard, alternate text representation and
+ language property parameters can be specified on this property.
+
+ Conformance: This property can be specified in "VEVENT", "VTODO",
+ "VJOURNAL", "VTIMEZONE" or "VFREEBUSY" calendar components.
+
+ Description: The property can be specified multiple times.
+
+ Format Definition: The property is defined by the following notation:
+
+ comment = "COMMENT" commparam ":" text CRLF
+
+ commparam = *(
+
+ ; the following are optional,
+ ; but MUST NOT occur more than once
+
+ (";" altrepparam) / (";" languageparam) /
+
+ ; the following is optional,
+ ; and MAY occur more than once
+
+ (";" xparam)
+
+ )
+
+ Example: The following is an example of this property:
+
+ COMMENT:The meeting really needs to include both ourselves
+ and the customer. We can't hold this meeting without them.
+ As a matter of fact\, the venue for the meeting ought to be at
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 80]</span>
+</pre><pre class="newpage"><a name="page-81" id="page-81" href="#page-81" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ their site. - - John
+
+ The data type for this property is TEXT.
+
+<span class="h5"><h5><a name="section-4.8.1.5">4.8.1.5</a> Description</h5></span>
+
+ Property Name: DESCRIPTION
+
+ Purpose: This property provides a more complete description of the
+ calendar component, than that provided by the "SUMMARY" property.
+
+ Value Type: TEXT
+
+ Property Parameters: Non-standard, alternate text representation and
+ language property parameters can be specified on this property.
+
+ Conformance: The property can be specified in the "VEVENT", "VTODO",
+ "VJOURNAL" or "VALARM" calendar components. The property can be
+ specified multiple times only within a "VJOURNAL" calendar component.
+
+ Description: This property is used in the "VEVENT" and "VTODO" to
+ capture lengthy textual decriptions associated with the activity.
+
+ This property is used in the "VJOURNAL" calendar component to capture
+ one more textual journal entries.
+
+ This property is used in the "VALARM" calendar component to capture
+ the display text for a DISPLAY category of alarm, to capture the body
+ text for an EMAIL category of alarm and to capture the argument
+ string for a PROCEDURE category of alarm.
+
+ Format Definition: The property is defined by the following notation:
+
+ description = "DESCRIPTION" descparam ":" text CRLF
+
+ descparam = *(
+
+ ; the following are optional,
+ ; but MUST NOT occur more than once
+
+ (";" altrepparam) / (";" languageparam) /
+
+ ; the following is optional,
+ ; and MAY occur more than once
+
+ (";" xparam)
+
+ )
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 81]</span>
+</pre><pre class="newpage"><a name="page-82" id="page-82" href="#page-82" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ Example: The following is an example of the property with formatted
+ line breaks in the property value:
+
+ DESCRIPTION:Meeting to provide technical review for "Phoenix"
+ design.\n Happy Face Conference Room. Phoenix design team
+ MUST attend this meeting.\n RSVP to team leader.
+
+ The following is an example of the property with folding of long
+ lines:
+
+ DESCRIPTION:Last draft of the new novel is to be completed
+ for the editor's proof today.
+
+<span class="h5"><h5><a name="section-4.8.1.6">4.8.1.6</a> Geographic Position</h5></span>
+
+ Property Name: GEO
+
+ Purpose: This property specifies information related to the global
+ position for the activity specified by a calendar component.
+
+ Value Type: FLOAT. The value MUST be two SEMICOLON separated FLOAT
+ values.
+
+ Property Parameters: Non-standard property parameters can be
+ specified on this property.
+
+ Conformance: This property can be specified in "VEVENT" or "VTODO"
+ calendar components.
+
+ Description: The property value specifies latitude and longitude, in
+ that order (i.e., "LAT LON" ordering). The longitude represents the
+ location east or west of the prime meridian as a positive or negative
+ real number, respectively. The longitude and latitude values MAY be
+ specified up to six decimal places, which will allow for accuracy to
+ within one meter of geographical position. Receiving applications
+ MUST accept values of this precision and MAY truncate values of
+ greater precision.
+
+ Values for latitude and longitude shall be expressed as decimal
+ fractions of degrees. Whole degrees of latitude shall be represented
+ by a two-digit decimal number ranging from 0 through 90. Whole
+ degrees of longitude shall be represented by a decimal number ranging
+ from 0 through 180. When a decimal fraction of a degree is specified,
+ it shall be separated from the whole number of degrees by a decimal
+ point.
+
+
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 82]</span>
+</pre><pre class="newpage"><a name="page-83" id="page-83" href="#page-83" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ Latitudes north of the equator shall be specified by a plus sign (+),
+ or by the absence of a minus sign (-), preceding the digits
+ designating degrees. Latitudes south of the Equator shall be
+ designated by a minus sign (-) preceding the digits designating
+ degrees. A point on the Equator shall be assigned to the Northern
+ Hemisphere.
+
+ Longitudes east of the prime meridian shall be specified by a plus
+ sign (+), or by the absence of a minus sign (-), preceding the digits
+ designating degrees. Longitudes west of the meridian shall be
+ designated by minus sign (-) preceding the digits designating
+ degrees. A point on the prime meridian shall be assigned to the
+ Eastern Hemisphere. A point on the 180th meridian shall be assigned
+ to the Western Hemisphere. One exception to this last convention is
+ permitted. For the special condition of describing a band of latitude
+ around the earth, the East Bounding Coordinate data element shall be
+ assigned the value +180 (180) degrees.
+
+ Any spatial address with a latitude of +90 (90) or -90 degrees will
+ specify the position at the North or South Pole, respectively. The
+ component for longitude may have any legal value.
+
+ With the exception of the special condition described above, this
+ form is specified in Department of Commerce, 1986, Representation of
+ geographic point locations for information interchange (Federal
+ Information Processing Standard 70-1): Washington, Department of
+ Commerce, National Institute of Standards and Technology.
+
+ The simple formula for converting degrees-minutes-seconds into
+ decimal degrees is:
+
+ decimal = degrees + minutes/60 + seconds/3600.
+
+ Format Definition: The property is defined by the following notation:
+
+ geo = "GEO" geoparam ":" geovalue CRLF
+
+ geoparam = *(";" xparam)
+
+ geovalue = float ";" float
+ ;Latitude and Longitude components
+
+ Example: The following is an example of this property:
+
+ GEO:37.386013;-122.082932
+
+
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 83]</span>
+</pre><pre class="newpage"><a name="page-84" id="page-84" href="#page-84" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+<span class="h5"><h5><a name="section-4.8.1.7">4.8.1.7</a> Location</h5></span>
+
+ Property Name: LOCATION
+
+ Purpose: The property defines the intended venue for the activity
+ defined by a calendar component.
+
+ Value Type: TEXT
+
+ Property Parameters: Non-standard, alternate text representation and
+ language property parameters can be specified on this property.
+
+ Conformance: This property can be specified in "VEVENT" or "VTODO"
+ calendar component.
+
+ Description: Specific venues such as conference or meeting rooms may
+ be explicitly specified using this property. An alternate
+ representation may be specified that is a URI that points to
+ directory information with more structured specification of the
+ location. For example, the alternate representation may specify
+ either an LDAP URI pointing to an LDAP server entry or a CID URI
+ pointing to a MIME body part containing a vCard [<a href="http://tools.ietf.org/html/rfc2426" title=""vCard MIME Directory Profile"">RFC 2426</a>] for the
+ location.
+
+ Format Definition: The property is defined by the following notation:
+
+ location = "LOCATION locparam ":" text CRLF
+
+ locparam = *(
+
+ ; the following are optional,
+ ; but MUST NOT occur more than once
+
+ (";" altrepparam) / (";" languageparam) /
+
+ ; the following is optional,
+ ; and MAY occur more than once
+
+ (";" xparam)
+
+ )
+
+ Example: The following are some examples of this property:
+
+ LOCATION:Conference Room - F123, Bldg. 002
+
+ LOCATION;ALTREP="http://xyzcorp.com/conf-rooms/f123.vcf":
+ Conference Room - F123, Bldg. 002
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 84]</span>
+</pre><pre class="newpage"><a name="page-85" id="page-85" href="#page-85" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+<span class="h5"><h5><a name="section-4.8.1.8">4.8.1.8</a> Percent Complete</h5></span>
+
+ Property Name: PERCENT-COMPLETE
+
+ Purpose: This property is used by an assignee or delegatee of a to-do
+ to convey the percent completion of a to-do to the Organizer.
+
+ Value Type: INTEGER
+
+ Property Parameters: Non-standard property parameters can be
+ specified on this property.
+
+ Conformance: This property can be specified in a "VTODO" calendar
+ component.
+
+ Description: The property value is a positive integer between zero
+ and one hundred. A value of "0" indicates the to-do has not yet been
+ started. A value of "100" indicates that the to-do has been
+ completed. Integer values in between indicate the percent partially
+ complete.
+
+ When a to-do is assigned to multiple individuals, the property value
+ indicates the percent complete for that portion of the to-do assigned
+ to the assignee or delegatee. For example, if a to-do is assigned to
+ both individuals "A" and "B". A reply from "A" with a percent
+ complete of "70" indicates that "A" has completed 70% of the to-do
+ assigned to them. A reply from "B" with a percent complete of "50"
+ indicates "B" has completed 50% of the to-do assigned to them.
+
+ Format Definition: The property is defined by the following notation:
+
+ percent = "PERCENT-COMPLETE" pctparam ":" integer CRLF
+
+ pctparam = *(";" xparam)
+
+ Example: The following is an example of this property to show 39%
+ completion:
+
+ PERCENT-COMPLETE:39
+
+<span class="h5"><h5><a name="section-4.8.1.9">4.8.1.9</a> Priority</h5></span>
+
+ Property Name: PRIORITY
+
+ Purpose: The property defines the relative priority for a calendar
+ component.
+
+ Value Type: INTEGER
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 85]</span>
+</pre><pre class="newpage"><a name="page-86" id="page-86" href="#page-86" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ Property Parameters: Non-standard property parameters can be
+ specified on this property.
+
+ Conformance: The property can be specified in a "VEVENT" or "VTODO"
+ calendar component.
+
+ Description: The priority is specified as an integer in the range
+ zero to nine. A value of zero (US-ASCII decimal 48) specifies an
+ undefined priority. A value of one (US-ASCII decimal 49) is the
+ highest priority. A value of two (US-ASCII decimal 50) is the second
+ highest priority. Subsequent numbers specify a decreasing ordinal
+ priority. A value of nine (US-ASCII decimal 58) is the lowest
+ priority.
+
+ A CUA with a three-level priority scheme of "HIGH", "MEDIUM" and
+ "LOW" is mapped into this property such that a property value in the
+ range of one (US-ASCII decimal 49) to four (US-ASCII decimal 52)
+ specifies "HIGH" priority. A value of five (US-ASCII decimal 53) is
+ the normal or "MEDIUM" priority. A value in the range of six (US-
+ ASCII decimal 54) to nine (US-ASCII decimal 58) is "LOW" priority.
+
+ A CUA with a priority schema of "A1", "A2", "A3", "B1", "B2", ...,
+ "C3" is mapped into this property such that a property value of one
+ (US-ASCII decimal 49) specifies "A1", a property value of two (US-
+ ASCII decimal 50) specifies "A2", a property value of three (US-ASCII
+ decimal 51) specifies "A3", and so forth up to a property value of 9
+ (US-ASCII decimal 58) specifies "C3".
+
+ Other integer values are reserved for future use.
+
+ Within a "VEVENT" calendar component, this property specifies a
+ priority for the event. This property may be useful when more than
+ one event is scheduled for a given time period.
+
+ Within a "VTODO" calendar component, this property specified a
+ priority for the to-do. This property is useful in prioritizing
+ multiple action items for a given time period.
+
+ Format Definition: The property is specified by the following
+ notation:
+
+ priority = "PRIORITY" prioparam ":" privalue CRLF
+ ;Default is zero
+
+ prioparam = *(";" xparam)
+
+ privalue = integer ;Must be in the range [<a href="#ref-0..9">0..9</a>]
+ ; All other values are reserved for future use
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 86]</span>
+</pre><pre class="newpage"><a name="page-87" id="page-87" href="#page-87" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ The following is an example of a property with the highest priority:
+
+ PRIORITY:1
+
+ The following is an example of a property with a next highest
+ priority:
+
+ PRIORITY:2
+
+ Example: The following is an example of a property with no priority.
+ This is equivalent to not specifying the "PRIORITY" property:
+
+ PRIORITY:0
+
+<span class="h5"><h5><a name="section-4.8.1.10">4.8.1.10</a> Resources</h5></span>
+
+ Property Name: RESOURCES
+
+ Purpose: This property defines the equipment or resources anticipated
+ for an activity specified by a calendar entity..
+
+ Value Type: TEXT
+
+ Property Parameters: Non-standard, alternate text representation and
+ language property parameters can be specified on this property.
+
+ Conformance: This property can be specified in "VEVENT" or "VTODO"
+ calendar component.
+
+ Description: The property value is an arbitrary text. More than one
+ resource can be specified as a list of resources separated by the
+ COMMA character (US-ASCII decimal 44).
+
+ Format Definition: The property is defined by the following notation:
+
+ resources = "RESOURCES" resrcparam ":" text *("," text) CRLF
+
+ resrcparam = *(
+
+ ; the following are optional,
+ ; but MUST NOT occur more than once
+
+ (";" altrepparam) / (";" languageparam) /
+
+ ; the following is optional,
+ ; and MAY occur more than once
+
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 87]</span>
+</pre><pre class="newpage"><a name="page-88" id="page-88" href="#page-88" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ (";" xparam)
+
+ )
+
+ Example: The following is an example of this property:
+
+ RESOURCES:EASEL,PROJECTOR,VCR
+
+ RESOURCES;LANGUAGE=fr:1 raton-laveur
+
+<span class="h5"><h5><a name="section-4.8.1.11">4.8.1.11</a> Status</h5></span>
+
+ Property Name: STATUS
+
+ Purpose: This property defines the overall status or confirmation for
+ the calendar component.
+
+ Value Type: TEXT
+
+ Property Parameters: Non-standard property parameters can be
+ specified on this property.
+
+ Conformance: This property can be specified in "VEVENT", "VTODO" or
+ "VJOURNAL" calendar components.
+
+ Description: In a group scheduled calendar component, the property is
+ used by the "Organizer" to provide a confirmation of the event to the
+ "Attendees". For example in a "VEVENT" calendar component, the
+ "Organizer" can indicate that a meeting is tentative, confirmed or
+ cancelled. In a "VTODO" calendar component, the "Organizer" can
+ indicate that an action item needs action, is completed, is in
+ process or being worked on, or has been cancelled. In a "VJOURNAL"
+ calendar component, the "Organizer" can indicate that a journal entry
+ is draft, final or has been cancelled or removed.
+
+ Format Definition: The property is defined by the following notation:
+
+ status = "STATUS" statparam] ":" statvalue CRLF
+
+ statparam = *(";" xparam)
+
+ statvalue = "TENTATIVE" ;Indicates event is
+ ;tentative.
+ / "CONFIRMED" ;Indicates event is
+ ;definite.
+ / "CANCELLED" ;Indicates event was
+ ;cancelled.
+ ;Status values for a "VEVENT"
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 88]</span>
+</pre><pre class="newpage"><a name="page-89" id="page-89" href="#page-89" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ statvalue =/ "NEEDS-ACTION" ;Indicates to-do needs action.
+ / "COMPLETED" ;Indicates to-do completed.
+ / "IN-PROCESS" ;Indicates to-do in process of
+ / "CANCELLED" ;Indicates to-do was cancelled.
+ ;Status values for "VTODO".
+
+ statvalue =/ "DRAFT" ;Indicates journal is draft.
+ / "FINAL" ;Indicates journal is final.
+ / "CANCELLED" ;Indicates journal is removed.
+ ;Status values for "VJOURNAL".
+
+ Example: The following is an example of this property for a "VEVENT"
+ calendar component:
+
+ STATUS:TENTATIVE
+
+ The following is an example of this property for a "VTODO" calendar
+ component:
+
+ STATUS:NEEDS-ACTION
+
+ The following is an example of this property for a "VJOURNAL"
+ calendar component:
+
+ STATUS:DRAFT
+
+<span class="h5"><h5><a name="section-4.8.1.12">4.8.1.12</a> Summary</h5></span>
+
+ Property Name: SUMMARY
+
+ Purpose: This property defines a short summary or subject for the
+ calendar component.
+
+ Value Type: TEXT
+
+ Property Parameters: Non-standard, alternate text representation and
+ language property parameters can be specified on this property.
+
+ Conformance: The property can be specified in "VEVENT", "VTODO",
+ "VJOURNAL" or "VALARM" calendar components.
+
+ Description: This property is used in the "VEVENT", "VTODO" and
+ "VJOURNAL" calendar components to capture a short, one line summary
+ about the activity or journal entry.
+
+ This property is used in the "VALARM" calendar component to capture
+ the subject of an EMAIL category of alarm.
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 89]</span>
+</pre><pre class="newpage"><a name="page-90" id="page-90" href="#page-90" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ Format Definition: The property is defined by the following notation:
+
+ summary = "SUMMARY" summparam ":" text CRLF
+
+ summparam = *(
+
+ ; the following are optional,
+ ; but MUST NOT occur more than once
+
+ (";" altrepparam) / (";" languageparam) /
+
+ ; the following is optional,
+ ; and MAY occur more than once
+
+ (";" xparam)
+
+ )
+
+ Example: The following is an example of this property:
+
+ SUMMARY:Department Party
+
+<span class="h4"><h4><a name="section-4.8.2">4.8.2</a> Date and Time Component Properties</h4></span>
+
+ The following properties specify date and time related information in
+ calendar components.
+
+<span class="h5"><h5><a name="section-4.8.2.1">4.8.2.1</a> Date/Time Completed</h5></span>
+
+ Property Name: COMPLETED
+
+ Purpose: This property defines the date and time that a to-do was
+ actually completed.
+
+ Value Type: DATE-TIME
+
+ Property Parameters: Non-standard property parameters can be
+ specified on this property.
+
+ Conformance: The property can be specified in a "VTODO" calendar
+ component.
+
+ Description: The date and time MUST be in a UTC format.
+
+ Format Definition: The property is defined by the following notation:
+
+ completed = "COMPLETED" compparam ":" date-time CRLF
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 90]</span>
+</pre><pre class="newpage"><a name="page-91" id="page-91" href="#page-91" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ compparam = *(";" xparam)
+
+ Example: The following is an example of this property:
+
+ COMPLETED:19960401T235959Z
+
+<span class="h5"><h5><a name="section-4.8.2.2">4.8.2.2</a> Date/Time End</h5></span>
+
+ Property Name: DTEND
+
+ Purpose: This property specifies the date and time that a calendar
+ component ends.
+
+ Value Type: The default value type is DATE-TIME. The value type can
+ be set to a DATE value type.
+
+ Property Parameters: Non-standard, value data type, time zone
+ identifier property parameters can be specified on this property.
+
+ Conformance: This property can be specified in "VEVENT" or
+ "VFREEBUSY" calendar components.
+
+ Description: Within the "VEVENT" calendar component, this property
+ defines the date and time by which the event ends. The value MUST be
+ later in time than the value of the "DTSTART" property.
+
+ Within the "VFREEBUSY" calendar component, this property defines the
+ end date and time for the free or busy time information. The time
+ MUST be specified in the UTC time format. The value MUST be later in
+ time than the value of the "DTSTART" property.
+
+ Format Definition: The property is defined by the following notation:
+
+ dtend = "DTEND" dtendparam":" dtendval CRLF
+
+ dtendparam = *(
+
+ ; the following are optional,
+ ; but MUST NOT occur more than once
+
+ (";" "VALUE" "=" ("DATE-TIME" / "DATE")) /
+ (";" tzidparam) /
+
+ ; the following is optional,
+ ; and MAY occur more than once
+
+
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 91]</span>
+</pre><pre class="newpage"><a name="page-92" id="page-92" href="#page-92" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ (";" xparam)
+
+ )
+
+
+
+ dtendval = date-time / date
+ ;Value MUST match value type
+
+ Example: The following is an example of this property:
+
+ DTEND:19960401T235959Z
+
+ DTEND;VALUE=DATE:19980704
+
+<span class="h5"><h5><a name="section-4.8.2.3">4.8.2.3</a> Date/Time Due</h5></span>
+
+ Property Name: DUE
+
+ Purpose: This property defines the date and time that a to-do is
+ expected to be completed.
+
+ Value Type: The default value type is DATE-TIME. The value type can
+ be set to a DATE value type.
+
+ Property Parameters: Non-standard, value data type, time zone
+ identifier property parameters can be specified on this property.
+
+ Conformance: The property can be specified once in a "VTODO" calendar
+ component.
+
+ Description: The value MUST be a date/time equal to or after the
+ DTSTART value, if specified.
+
+ Format Definition: The property is defined by the following notation:
+
+ due = "DUE" dueparam":" dueval CRLF
+
+ dueparam = *(
+ ; the following are optional,
+ ; but MUST NOT occur more than once
+
+ (";" "VALUE" "=" ("DATE-TIME" / "DATE")) /
+ (";" tzidparam) /
+
+ ; the following is optional,
+ ; and MAY occur more than once
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 92]</span>
+</pre><pre class="newpage"><a name="page-93" id="page-93" href="#page-93" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ *(";" xparam)
+
+ )
+
+
+
+ dueval = date-time / date
+ ;Value MUST match value type
+
+ Example: The following is an example of this property:
+
+ DUE:19980430T235959Z
+
+<span class="h5"><h5><a name="section-4.8.2.4">4.8.2.4</a> Date/Time Start</h5></span>
+
+ Property Name: DTSTART
+
+ Purpose: This property specifies when the calendar component begins.
+
+ Value Type: The default value type is DATE-TIME. The time value MUST
+ be one of the forms defined for the DATE-TIME value type. The value
+ type can be set to a DATE value type.
+
+ Property Parameters: Non-standard, value data type, time zone
+ identifier property parameters can be specified on this property.
+
+ Conformance: This property can be specified in the "VEVENT", "VTODO",
+ "VFREEBUSY", or "VTIMEZONE" calendar components.
+
+ Description: Within the "VEVENT" calendar component, this property
+ defines the start date and time for the event. The property is
+ REQUIRED in "VEVENT" calendar components. Events can have a start
+ date/time but no end date/time. In that case, the event does not take
+ up any time.
+
+ Within the "VFREEBUSY" calendar component, this property defines the
+ start date and time for the free or busy time information. The time
+ MUST be specified in UTC time.
+
+ Within the "VTIMEZONE" calendar component, this property defines the
+ effective start date and time for a time zone specification. This
+ property is REQUIRED within each STANDARD and DAYLIGHT part included
+ in "VTIMEZONE" calendar components and MUST be specified as a local
+ DATE-TIME without the "TZID" property parameter.
+
+ Format Definition: The property is defined by the following notation:
+
+ dtstart = "DTSTART" dtstparam ":" dtstval CRLF
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 93]</span>
+</pre><pre class="newpage"><a name="page-94" id="page-94" href="#page-94" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ dtstparam = *(
+
+ ; the following are optional,
+ ; but MUST NOT occur more than once
+
+ (";" "VALUE" "=" ("DATE-TIME" / "DATE")) /
+ (";" tzidparam) /
+
+ ; the following is optional,
+ ; and MAY occur more than once
+
+ *(";" xparam)
+
+ )
+
+
+
+ dtstval = date-time / date
+ ;Value MUST match value type
+
+ Example: The following is an example of this property:
+
+ DTSTART:19980118T073000Z
+
+<span class="h5"><h5><a name="section-4.8.2.5">4.8.2.5</a> Duration</h5></span>
+
+ Property Name: DURATION
+
+ Purpose: The property specifies a positive duration of time.
+
+ Value Type: DURATION
+
+ Property Parameters: Non-standard property parameters can be
+ specified on this property.
+
+ Conformance: The property can be specified in "VEVENT", "VTODO",
+ "VFREEBUSY" or "VALARM" calendar components.
+
+ Description: In a "VEVENT" calendar component the property may be
+ used to specify a duration of the event, instead of an explicit end
+ date/time. In a "VTODO" calendar component the property may be used
+ to specify a duration for the to-do, instead of an explicit due
+ date/time. In a "VFREEBUSY" calendar component the property may be
+ used to specify the interval of free time being requested. In a
+ "VALARM" calendar component the property may be used to specify the
+ delay period prior to repeating an alarm.
+
+ Format Definition: The property is defined by the following notation:
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 94]</span>
+</pre><pre class="newpage"><a name="page-95" id="page-95" href="#page-95" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ duration = "DURATION" durparam ":" dur-value CRLF
+ ;consisting of a positive duration of time.
+
+ durparam = *(";" xparam)
+
+ Example: The following is an example of this property that specifies
+ an interval of time of 1 hour and zero minutes and zero seconds:
+
+ DURATION:PT1H0M0S
+
+ The following is an example of this property that specifies an
+ interval of time of 15 minutes.
+
+ DURATION:PT15M
+
+<span class="h5"><h5><a name="section-4.8.2.6">4.8.2.6</a> Free/Busy Time</h5></span>
+
+ Property Name: FREEBUSY
+
+ Purpose: The property defines one or more free or busy time
+ intervals.
+
+ Value Type: PERIOD. The date and time values MUST be in an UTC time
+ format.
+
+ Property Parameters: Non-standard or free/busy time type property
+ parameters can be specified on this property.
+
+ Conformance: The property can be specified in a "VFREEBUSY" calendar
+ component.
+
+ Property Parameter: "FBTYPE" and non-standard parameters can be
+ specified on this property.
+
+ Description: These time periods can be specified as either a start
+ and end date-time or a start date-time and duration. The date and
+ time MUST be a UTC time format.
+
+ "FREEBUSY" properties within the "VFREEBUSY" calendar component
+ SHOULD be sorted in ascending order, based on start time and then end
+ time, with the earliest periods first.
+
+ The "FREEBUSY" property can specify more than one value, separated by
+ the COMMA character (US-ASCII decimal 44). In such cases, the
+ "FREEBUSY" property values SHOULD all be of the same "FBTYPE"
+ property parameter type (e.g., all values of a particular "FBTYPE"
+ listed together in a single property).
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 95]</span>
+</pre><pre class="newpage"><a name="page-96" id="page-96" href="#page-96" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ Format Definition: The property is defined by the following notation:
+
+ freebusy = "FREEBUSY" fbparam ":" fbvalue
+ CRLF
+
+ fbparam = *(
+ ; the following is optional,
+ ; but MUST NOT occur more than once
+
+ (";" fbtypeparam) /
+
+ ; the following is optional,
+ ; and MAY occur more than once
+
+ (";" xparam)
+
+ )
+
+ fbvalue = period *["," period]
+ ;Time value MUST be in the UTC time format.
+
+ Example: The following are some examples of this property:
+
+ FREEBUSY;FBTYPE=BUSY-UNAVAILABLE:19970308T160000Z/PT8H30M
+
+ FREEBUSY;FBTYPE=FREE:19970308T160000Z/PT3H,19970308T200000Z/PT1H
+
+ FREEBUSY;FBTYPE=FREE:19970308T160000Z/PT3H,19970308T200000Z/PT1H,
+ 19970308T230000Z/19970309T000000Z
+
+<span class="h5"><h5><a name="section-4.8.2.7">4.8.2.7</a> Time Transparency</h5></span>
+
+ Property Name: TRANSP
+
+ Purpose: This property defines whether an event is transparent or not
+ to busy time searches.
+
+ Value Type: TEXT
+
+ Property Parameters: Non-standard property parameters can be
+ specified on this property.
+
+ Conformance: This property can be specified once in a "VEVENT"
+ calendar component.
+
+ Description: Time Transparency is the characteristic of an event that
+ determines whether it appears to consume time on a calendar. Events
+ that consume actual time for the individual or resource associated
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 96]</span>
+</pre><pre class="newpage"><a name="page-97" id="page-97" href="#page-97" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ with the calendar SHOULD be recorded as OPAQUE, allowing them to be
+ detected by free-busy time searches. Other events, which do not take
+ up the individual's (or resource's) time SHOULD be recorded as
+ TRANSPARENT, making them invisible to free-busy time searches.
+
+ Format Definition: The property is specified by the following
+ notation:
+
+ transp = "TRANSP" tranparam ":" transvalue CRLF
+
+ tranparam = *(";" xparam)
+
+ transvalue = "OPAQUE" ;Blocks or opaque on busy time searches.
+ / "TRANSPARENT" ;Transparent on busy time searches.
+ ;Default value is OPAQUE
+
+ Example: The following is an example of this property for an event
+ that is transparent or does not block on free/busy time searches:
+
+ TRANSP:TRANSPARENT
+
+ The following is an example of this property for an event that is
+ opaque or blocks on free/busy time searches:
+
+ TRANSP:OPAQUE
+
+<span class="h4"><h4><a name="section-4.8.3">4.8.3</a> Time Zone Component Properties</h4></span>
+
+ The following properties specify time zone information in calendar
+ components.
+
+<span class="h5"><h5><a name="section-4.8.3.1">4.8.3.1</a> Time Zone Identifier</h5></span>
+
+ Property Name: TZID
+
+ Purpose: This property specifies the text value that uniquely
+ identifies the "VTIMEZONE" calendar component.
+
+ Value Type: TEXT
+
+ Property Parameters: Non-standard property parameters can be
+ specified on this property.
+
+ Conformance: This property MUST be specified in a "VTIMEZONE"
+ calendar component.
+
+
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 97]</span>
+</pre><pre class="newpage"><a name="page-98" id="page-98" href="#page-98" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ Description: This is the label by which a time zone calendar
+ component is referenced by any iCalendar properties whose data type
+ is either DATE-TIME or TIME and not intended to specify a UTC or a
+ "floating" time. The presence of the SOLIDUS character (US-ASCII
+ decimal 47) as a prefix, indicates that this TZID represents an
+ unique ID in a globally defined time zone registry (when such
+ registry is defined).
+
+ Note: This document does not define a naming convention for time
+ zone identifiers. Implementers may want to use the naming
+ conventions defined in existing time zone specifications such as
+ the public-domain Olson database [<a href="#ref-TZ" title=""ftp://elsie.nci.nih.gov/pub/"">TZ</a>]. The specification of
+ globally unique time zone identifiers is not addressed by this
+ document and is left for future study.
+
+ Format Definition: This property is defined by the following
+ notation:
+
+ tzid = "TZID" tzidpropparam ":" [<a href="#ref-tzidprefix">tzidprefix</a>] text CRLF
+
+ tzidpropparam = *(";" xparam)
+
+ ;tzidprefix = "/"
+ ; Defined previously. Just listed here for reader convenience.
+
+ Example: The following are examples of non-globally unique time zone
+ identifiers:
+
+ TZID:US-Eastern
+
+ TZID:California-Los_Angeles
+
+ The following is an example of a fictitious globally unique time zone
+ identifier:
+
+ TZID:/US-New_York-New_York
+
+<span class="h5"><h5><a name="section-4.8.3.2">4.8.3.2</a> Time Zone Name</h5></span>
+
+ Property Name: TZNAME
+
+ Purpose: This property specifies the customary designation for a time
+ zone description.
+
+ Value Type: TEXT
+
+ Property Parameters: Non-standard and language property parameters
+ can be specified on this property.
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 98]</span>
+</pre><pre class="newpage"><a name="page-99" id="page-99" href="#page-99" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ Conformance: This property can be specified in a "VTIMEZONE" calendar
+ component.
+
+ Description: This property may be specified in multiple languages; in
+ order to provide for different language requirements.
+
+ Format Definition: This property is defined by the following
+ notation:
+
+ tzname = "TZNAME" tznparam ":" text CRLF
+
+ tznparam = *(
+
+ ; the following is optional,
+ ; but MUST NOT occur more than once
+
+ (";" languageparam) /
+
+ ; the following is optional,
+ ; and MAY occur more than once
+
+ (";" xparam)
+
+ )
+
+ Example: The following are example of this property:
+
+ TZNAME:EST
+
+ The following is an example of this property when two different
+ languages for the time zone name are specified:
+
+ TZNAME;LANGUAGE=en:EST
+ TZNAME;LANGUAGE=fr-CA:HNE
+
+<span class="h5"><h5><a name="section-4.8.3.3">4.8.3.3</a> Time Zone Offset From</h5></span>
+
+ Property Name: TZOFFSETFROM
+
+ Purpose: This property specifies the offset which is in use prior to
+ this time zone observance.
+
+ Value Type: UTC-OFFSET
+
+ Property Parameters: Non-standard property parameters can be
+ specified on this property.
+
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 99]</span>
+</pre><pre class="newpage"><a name="page-100" id="page-100" href="#page-100" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ Conformance: This property MUST be specified in a "VTIMEZONE"
+ calendar component.
+
+ Description: This property specifies the offset which is in use prior
+ to this time observance. It is used to calculate the absolute time at
+ which the transition to a given observance takes place. This property
+ MUST only be specified in a "VTIMEZONE" calendar component. A
+ "VTIMEZONE" calendar component MUST include this property. The
+ property value is a signed numeric indicating the number of hours and
+ possibly minutes from UTC. Positive numbers represent time zones east
+ of the prime meridian, or ahead of UTC. Negative numbers represent
+ time zones west of the prime meridian, or behind UTC.
+
+ Format Definition: The property is defined by the following notation:
+
+ tzoffsetfrom = "TZOFFSETFROM" frmparam ":" utc-offset
+ CRLF
+
+ frmparam = *(";" xparam)
+
+ Example: The following are examples of this property:
+
+ TZOFFSETFROM:-0500
+
+ TZOFFSETFROM:+1345
+
+<span class="h5"><h5><a name="section-4.8.3.4">4.8.3.4</a> Time Zone Offset To</h5></span>
+
+ Property Name: TZOFFSETTO
+
+ Purpose: This property specifies the offset which is in use in this
+ time zone observance.
+
+ Value Type: UTC-OFFSET
+
+ Property Parameters: Non-standard property parameters can be
+ specified on this property.
+
+ Conformance: This property MUST be specified in a "VTIMEZONE"
+ calendar component.
+
+ Description: This property specifies the offset which is in use in
+ this time zone observance. It is used to calculate the absolute time
+ for the new observance. The property value is a signed numeric
+ indicating the number of hours and possibly minutes from UTC.
+ Positive numbers represent time zones east of the prime meridian, or
+ ahead of UTC. Negative numbers represent time zones west of the prime
+ meridian, or behind UTC.
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 100]</span>
+</pre><pre class="newpage"><a name="page-101" id="page-101" href="#page-101" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ Format Definition: The property is defined by the following notation:
+
+ tzoffsetto = "TZOFFSETTO" toparam ":" utc-offset CRLF
+
+ toparam = *(";" xparam)
+
+ Example: The following are examples of this property:
+
+ TZOFFSETTO:-0400
+
+ TZOFFSETTO:+1245
+
+<span class="h5"><h5><a name="section-4.8.3.5">4.8.3.5</a> Time Zone URL</h5></span>
+
+ Property Name: TZURL
+
+ Purpose: The TZURL provides a means for a VTIMEZONE component to
+ point to a network location that can be used to retrieve an up-to-
+ date version of itself.
+
+ Value Type: URI
+
+ Property Parameters: Non-standard property parameters can be
+ specified on this property.
+
+ Conformance: This property can be specified in a "VTIMEZONE" calendar
+ component.
+
+ Description: The TZURL provides a means for a VTIMEZONE component to
+ point to a network location that can be used to retrieve an up-to-
+ date version of itself. This provides a hook to handle changes
+ government bodies impose upon time zone definitions. Retrieval of
+ this resource results in an iCalendar object containing a single
+ VTIMEZONE component and a METHOD property set to PUBLISH.
+
+ Format Definition: The property is defined by the following notation:
+
+ tzurl = "TZURL" tzurlparam ":" uri CRLF
+
+ tzurlparam = *(";" xparam)
+
+ Example: The following is an example of this property:
+
+ TZURL:http://timezones.r.us.net/tz/US-California-Los_Angeles
+
+
+
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 101]</span>
+</pre><pre class="newpage"><a name="page-102" id="page-102" href="#page-102" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+<span class="h4"><h4><a name="section-4.8.4">4.8.4</a> Relationship Component Properties</h4></span>
+
+ The following properties specify relationship information in calendar
+ components.
+
+<span class="h5"><h5><a name="section-4.8.4.1">4.8.4.1</a> Attendee</h5></span>
+
+ Property Name: ATTENDEE
+
+ Purpose: The property defines an "Attendee" within a calendar
+ component.
+
+ Value Type: CAL-ADDRESS
+
+ Property Parameters: Non-standard, language, calendar user type,
+ group or list membership, participation role, participation status,
+ RSVP expectation, delegatee, delegator, sent by, common name or
+ directory entry reference property parameters can be specified on
+ this property.
+
+ Conformance: This property MUST be specified in an iCalendar object
+ that specifies a group scheduled calendar entity. This property MUST
+ NOT be specified in an iCalendar object when publishing the calendar
+ information (e.g., NOT in an iCalendar object that specifies the
+ publication of a calendar user's busy time, event, to-do or journal).
+ This property is not specified in an iCalendar object that specifies
+ only a time zone definition or that defines calendar entities that
+ are not group scheduled entities, but are entities only on a single
+ user's calendar.
+
+ Description: The property MUST only be specified within calendar
+ components to specify participants, non-participants and the chair of
+ a group scheduled calendar entity. The property is specified within
+ an "EMAIL" category of the "VALARM" calendar component to specify an
+ email address that is to receive the email type of iCalendar alarm.
+
+ The property parameter CN is for the common or displayable name
+ associated with the calendar address; ROLE, for the intended role
+ that the attendee will have in the calendar component; PARTSTAT, for
+ the status of the attendee's participation; RSVP, for indicating
+ whether the favor of a reply is requested; CUTYPE, to indicate the
+ type of calendar user; MEMBER, to indicate the groups that the
+ attendee belongs to; DELEGATED-TO, to indicate the calendar users
+ that the original request was delegated to; and DELEGATED-FROM, to
+ indicate whom the request was delegated from; SENT-BY, to indicate
+ whom is acting on behalf of the ATTENDEE; and DIR, to indicate the
+ URI that points to the directory information corresponding to the
+ attendee. These property parameters can be specified on an "ATTENDEE"
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 102]</span>
+</pre><pre class="newpage"><a name="page-103" id="page-103" href="#page-103" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ property in either a "VEVENT", "VTODO" or "VJOURNAL" calendar
+ component. They MUST not be specified in an "ATTENDEE" property in a
+ "VFREEBUSY" or "VALARM" calendar component. If the LANGUAGE property
+ parameter is specified, the identified language applies to the CN
+ parameter.
+
+ A recipient delegated a request MUST inherit the RSVP and ROLE values
+ from the attendee that delegated the request to them.
+
+ Multiple attendees can be specified by including multiple "ATTENDEE"
+ properties within the calendar component.
+
+ Format Definition: The property is defined by the following notation:
+
+ attendee = "ATTENDEE" attparam ":" cal-address CRLF
+
+ attparam = *(
+
+ ; the following are optional,
+ ; but MUST NOT occur more than once
+
+ (";" cutypeparam) / (";"memberparam) /
+ (";" roleparam) / (";" partstatparam) /
+ (";" rsvpparam) / (";" deltoparam) /
+ (";" delfromparam) / (";" sentbyparam) /
+ (";"cnparam) / (";" dirparam) /
+ (";" languageparam) /
+
+ ; the following is optional,
+ ; and MAY occur more than once
+
+ (";" xparam)
+
+ )
+
+ Example: The following are examples of this property's use for a to-
+ do:
+
+ ORGANIZER:MAILTO:jsmith@host1.com
+ ATTENDEE;MEMBER="MAILTO:DEV-GROUP@host2.com":
+ MAILTO:joecool@host2.com
+ ATTENDEE;DELEGATED-FROM="MAILTO:immud@host3.com":
+ MAILTO:ildoit@host1.com
+
+ The following is an example of this property used for specifying
+ multiple attendees to an event:
+
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 103]</span>
+</pre><pre class="newpage"><a name="page-104" id="page-104" href="#page-104" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ ORGANIZER:MAILTO:jsmith@host1.com
+ ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=TENTATIVE;CN=Henry Cabot
+ :MAILTO:hcabot@host2.com
+ ATTENDEE;ROLE=REQ-PARTICIPANT;DELEGATED-FROM="MAILTO:bob@host.com"
+ ;PARTSTAT=ACCEPTED;CN=Jane Doe:MAILTO:jdoe@host1.com
+
+ The following is an example of this property with a URI to the
+ directory information associated with the attendee:
+
+ ATTENDEE;CN=John Smith;DIR="ldap://host.com:6666/o=eDABC%
+ 20Industries,c=3DUS??(cn=3DBJim%20Dolittle)":MAILTO:jimdo@
+ host1.com
+
+ The following is an example of this property with "delegatee" and
+ "delegator" information for an event:
+
+ ORGANIZER;CN=John Smith:MAILTO:jsmith@host.com
+ ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=TENTATIVE;DELEGATED-FROM=
+ "MAILTO:iamboss@host2.com";CN=Henry Cabot:MAILTO:hcabot@
+ host2.com
+ ATTENDEE;ROLE=NON-PARTICIPANT;PARTSTAT=DELEGATED;DELEGATED-TO=
+ "MAILTO:hcabot@host2.com";CN=The Big Cheese:MAILTO:iamboss
+ @host2.com
+ ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;CN=Jane Doe
+ :MAILTO:jdoe@host1.com
+
+ Example: The following is an example of this property's use when
+ another calendar user is acting on behalf of the "Attendee":
+
+ ATTENDEE;SENT-BY=MAILTO:jan_doe@host1.com;CN=John Smith:MAILTO:
+ jsmith@host1.com
+
+<span class="h5"><h5><a name="section-4.8.4.2">4.8.4.2</a> Contact</h5></span>
+
+ Property Name: CONTACT
+
+ Purpose: The property is used to represent contact information or
+ alternately a reference to contact information associated with the
+ calendar component.
+
+ Value Type: TEXT
+
+ Property Parameters: Non-standard, alternate text representation and
+ language property parameters can be specified on this property.
+
+ Conformance: The property can be specified in a "VEVENT", "VTODO",
+ "VJOURNAL" or "VFREEBUSY" calendar component.
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 104]</span>
+</pre><pre class="newpage"><a name="page-105" id="page-105" href="#page-105" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ Description: The property value consists of textual contact
+ information. An alternative representation for the property value can
+ also be specified that refers to a URI pointing to an alternate form,
+ such as a vCard [<a href="http://tools.ietf.org/html/rfc2426" title=""vCard MIME Directory Profile"">RFC 2426</a>], for the contact information.
+
+ Format Definition: The property is defined by the following notation:
+
+ contact = "CONTACT" contparam ":" text CRLF
+
+ contparam = *(
+ ; the following are optional,
+ ; but MUST NOT occur more than once
+
+ (";" altrepparam) / (";" languageparam) /
+
+ ; the following is optional,
+ ; and MAY occur more than once
+
+ (";" xparam)
+
+ )
+
+ Example: The following is an example of this property referencing
+ textual contact information:
+
+ CONTACT:Jim Dolittle\, ABC Industries\, +1-919-555-1234
+
+ The following is an example of this property with an alternate
+ representation of a LDAP URI to a directory entry containing the
+ contact information:
+
+ CONTACT;ALTREP="ldap://host.com:6666/o=3DABC%20Industries\,
+ c=3DUS??(cn=3DBJim%20Dolittle)":Jim Dolittle\, ABC Industries\,
+ +1-919-555-1234
+
+ The following is an example of this property with an alternate
+ representation of a MIME body part containing the contact
+ information, such as a vCard [<a href="http://tools.ietf.org/html/rfc2426" title=""vCard MIME Directory Profile"">RFC 2426</a>] embedded in a [<a href="#ref-MIME-DIR">MIME-DIR</a>]
+ content-type:
+
+ CONTACT;ALTREP="CID=<part3.msg970930T083000SILVER@host.com>":Jim
+ Dolittle\, ABC Industries\, +1-919-555-1234
+
+ The following is an example of this property referencing a network
+ resource, such as a vCard [<a href="http://tools.ietf.org/html/rfc2426" title=""vCard MIME Directory Profile"">RFC 2426</a>] object containing the contact
+ information:
+
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 105]</span>
+</pre><pre class="newpage"><a name="page-106" id="page-106" href="#page-106" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ CONTACT;ALTREP="http://host.com/pdi/jdoe.vcf":Jim
+ Dolittle\, ABC Industries\, +1-919-555-1234
+
+<span class="h5"><h5><a name="section-4.8.4.3">4.8.4.3</a> Organizer</h5></span>
+
+ Property Name: ORGANIZER
+
+ Purpose: The property defines the organizer for a calendar component.
+
+ Value Type: CAL-ADDRESS
+
+ Property Parameters: Non-standard, language, common name, directory
+ entry reference, sent by property parameters can be specified on this
+ property.
+
+ Conformance: This property MUST be specified in an iCalendar object
+ that specifies a group scheduled calendar entity. This property MUST
+ be specified in an iCalendar object that specifies the publication of
+ a calendar user's busy time. This property MUST NOT be specified in
+ an iCalendar object that specifies only a time zone definition or
+ that defines calendar entities that are not group scheduled entities,
+ but are entities only on a single user's calendar.
+
+ Description: The property is specified within the "VEVENT", "VTODO",
+ "VJOURNAL calendar components to specify the organizer of a group
+ scheduled calendar entity. The property is specified within the
+ "VFREEBUSY" calendar component to specify the calendar user
+ requesting the free or busy time. When publishing a "VFREEBUSY"
+ calendar component, the property is used to specify the calendar that
+ the published busy time came from.
+
+ The property has the property parameters CN, for specifying the
+ common or display name associated with the "Organizer", DIR, for
+ specifying a pointer to the directory information associated with the
+ "Organizer", SENT-BY, for specifying another calendar user that is
+ acting on behalf of the "Organizer". The non-standard parameters may
+ also be specified on this property. If the LANGUAGE property
+ parameter is specified, the identified language applies to the CN
+ parameter value.
+
+ Format Definition: The property is defined by the following notation:
+
+ organizer = "ORGANIZER" orgparam ":"
+ cal-address CRLF
+
+ orgparam = *(
+
+ ; the following are optional,
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 106]</span>
+</pre><pre class="newpage"><a name="page-107" id="page-107" href="#page-107" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ ; but MUST NOT occur more than once
+
+ (";" cnparam) / (";" dirparam) / (";" sentbyparam) /
+ (";" languageparam) /
+
+ ; the following is optional,
+ ; and MAY occur more than once
+
+ (";" xparam)
+
+ )
+
+ Example: The following is an example of this property:
+
+ ORGANIZER;CN=John Smith:MAILTO:jsmith@host1.com
+
+ The following is an example of this property with a pointer to the
+ directory information associated with the organizer:
+
+ ORGANIZER;CN=JohnSmith;DIR="ldap://host.com:6666/o=3DDC%20Associ
+ ates,c=3DUS??(cn=3DJohn%20Smith)":MAILTO:jsmith@host1.com
+
+ The following is an example of this property used by another calendar
+ user who is acting on behalf of the organizer, with responses
+ intended to be sent back to the organizer, not the other calendar
+ user:
+
+ ORGANIZER;SENT-BY="MAILTO:jane_doe@host.com":
+ MAILTO:jsmith@host1.com
+
+<span class="h5"><h5><a name="section-4.8.4.4">4.8.4.4</a> Recurrence ID</h5></span>
+
+ Property Name: RECURRENCE-ID
+
+ Purpose: This property is used in conjunction with the "UID" and
+ "SEQUENCE" property to identify a specific instance of a recurring
+ "VEVENT", "VTODO" or "VJOURNAL" calendar component. The property
+ value is the effective value of the "DTSTART" property of the
+ recurrence instance.
+
+ Value Type: The default value type for this property is DATE-TIME.
+ The time format can be any of the valid forms defined for a DATE-TIME
+ value type. See DATE-TIME value type definition for specific
+ interpretations of the various forms. The value type can be set to
+ DATE.
+
+
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 107]</span>
+</pre><pre class="newpage"><a name="page-108" id="page-108" href="#page-108" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ Property Parameters: Non-standard property, value data type, time
+ zone identifier and recurrence identifier range parameters can be
+ specified on this property.
+
+ Conformance: This property can be specified in an iCalendar object
+ containing a recurring calendar component.
+
+ Description: The full range of calendar components specified by a
+ recurrence set is referenced by referring to just the "UID" property
+ value corresponding to the calendar component. The "RECURRENCE-ID"
+ property allows the reference to an individual instance within the
+ recurrence set.
+
+ If the value of the "DTSTART" property is a DATE type value, then the
+ value MUST be the calendar date for the recurrence instance.
+
+ The date/time value is set to the time when the original recurrence
+ instance would occur; meaning that if the intent is to change a
+ Friday meeting to Thursday, the date/time is still set to the
+ original Friday meeting.
+
+ The "RECURRENCE-ID" property is used in conjunction with the "UID"
+ and "SEQUENCE" property to identify a particular instance of a
+ recurring event, to-do or journal. For a given pair of "UID" and
+ "SEQUENCE" property values, the "RECURRENCE-ID" value for a
+ recurrence instance is fixed. When the definition of the recurrence
+ set for a calendar component changes, and hence the "SEQUENCE"
+ property value changes, the "RECURRENCE-ID" for a given recurrence
+ instance might also change.The "RANGE" parameter is used to specify
+ the effective range of recurrence instances from the instance
+ specified by the "RECURRENCE-ID" property value. The default value
+ for the range parameter is the single recurrence instance only. The
+ value can also be "THISANDPRIOR" to indicate a range defined by the
+ given recurrence instance and all prior instances or the value can be
+ "THISANDFUTURE" to indicate a range defined by the given recurrence
+ instance and all subsequent instances.
+
+ Format Definition: The property is defined by the following notation:
+
+ recurid = "RECURRENCE-ID" ridparam ":" ridval CRLF
+
+ ridparam = *(
+
+ ; the following are optional,
+ ; but MUST NOT occur more than once
+
+ (";" "VALUE" "=" ("DATE-TIME" / "DATE)) /
+ (";" tzidparam) / (";" rangeparam) /
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 108]</span>
+</pre><pre class="newpage"><a name="page-109" id="page-109" href="#page-109" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ ; the following is optional,
+ ; and MAY occur more than once
+
+ (";" xparam)
+
+ )
+
+ ridval = date-time / date
+ ;Value MUST match value type
+
+ Example: The following are examples of this property:
+
+ RECURRENCE-ID;VALUE=DATE:19960401
+
+ RECURRENCE-ID;RANGE=THISANDFUTURE:19960120T120000Z
+
+<span class="h5"><h5><a name="section-4.8.4.5">4.8.4.5</a> Related To</h5></span>
+
+ Property Name: RELATED-TO
+
+ Purpose: The property is used to represent a relationship or
+ reference between one calendar component and another.
+
+ Value Type: TEXT
+
+ Property Parameters: Non-standard and relationship type property
+ parameters can be specified on this property.
+
+ Conformance: The property can be specified one or more times in the
+ "VEVENT", "VTODO" or "VJOURNAL" calendar components.
+
+ Description: The property value consists of the persistent, globally
+ unique identifier of another calendar component. This value would be
+ represented in a calendar component by the "UID" property.
+
+ By default, the property value points to another calendar component
+ that has a PARENT relationship to the referencing object. The
+ "RELTYPE" property parameter is used to either explicitly state the
+ default PARENT relationship type to the referenced calendar component
+ or to override the default PARENT relationship type and specify
+ either a CHILD or SIBLING relationship. The PARENT relationship
+ indicates that the calendar component is a subordinate of the
+ referenced calendar component. The CHILD relationship indicates that
+ the calendar component is a superior of the referenced calendar
+ component. The SIBLING relationship indicates that the calendar
+ component is a peer of the referenced calendar component.
+
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 109]</span>
+</pre><pre class="newpage"><a name="page-110" id="page-110" href="#page-110" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ Changes to a calendar component referenced by this property can have
+ an implicit impact on the related calendar component. For example, if
+ a group event changes its start or end date or time, then the
+ related, dependent events will need to have their start and end dates
+ changed in a corresponding way. Similarly, if a PARENT calendar
+ component is canceled or deleted, then there is an implied impact to
+ the related CHILD calendar components. This property is intended only
+ to provide information on the relationship of calendar components. It
+ is up to the target calendar system to maintain any property
+ implications of this relationship.
+
+ Format Definition: The property is defined by the following notation:
+
+ related = "RELATED-TO" [<a href="#ref-relparam">relparam</a>] ":" text CRLF
+
+ relparam = *(
+
+ ; the following is optional,
+ ; but MUST NOT occur more than once
+
+ (";" reltypeparam) /
+
+ ; the following is optional,
+ ; and MAY occur more than once
+
+ (";" xparm)
+
+ )
+
+ The following is an example of this property:
+
+ RELATED-TO:<jsmith.part7.19960817T083000.xyzMail@host3.com>
+
+ RELATED-TO:<19960401-080045-4000F192713-0052@host1.com>
+
+<span class="h5"><h5><a name="section-4.8.4.6">4.8.4.6</a> Uniform Resource Locator</h5></span>
+
+ Property Name: URL
+
+ Purpose: This property defines a Uniform Resource Locator (URL)
+ associated with the iCalendar object.
+
+ Value Type: URI
+
+ Property Parameters: Non-standard property parameters can be
+ specified on this property.
+
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 110]</span>
+</pre><pre class="newpage"><a name="page-111" id="page-111" href="#page-111" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ Conformance: This property can be specified once in the "VEVENT",
+ "VTODO", "VJOURNAL" or "VFREEBUSY" calendar components.
+
+ Description: This property may be used in a calendar component to
+ convey a location where a more dynamic rendition of the calendar
+ information associated with the calendar component can be found. This
+ memo does not attempt to standardize the form of the URI, nor the
+ format of the resource pointed to by the property value. If the URL
+ property and Content-Location MIME header are both specified, they
+ MUST point to the same resource.
+
+ Format Definition: The property is defined by the following notation:
+
+ url = "URL" urlparam ":" uri CRLF
+
+ urlparam = *(";" xparam)
+
+ Example: The following is an example of this property:
+
+ URL:http://abc.com/pub/calendars/jsmith/mytime.ics
+
+<span class="h5"><h5><a name="section-4.8.4.7">4.8.4.7</a> Unique Identifier</h5></span>
+
+ Property Name: UID
+
+ Purpose: This property defines the persistent, globally unique
+ identifier for the calendar component.
+
+ Value Type: TEXT
+
+ Property Parameters: Non-standard property parameters can be
+ specified on this property.
+
+ Conformance: The property MUST be specified in the "VEVENT", "VTODO",
+ "VJOURNAL" or "VFREEBUSY" calendar components.
+
+ Description: The UID itself MUST be a globally unique identifier. The
+ generator of the identifier MUST guarantee that the identifier is
+ unique. There are several algorithms that can be used to accomplish
+ this. The identifier is RECOMMENDED to be the identical syntax to the
+ [<a href="http://tools.ietf.org/html/rfc822" title=""Standard for the Format of ARPA Internet Text Messages"">RFC 822</a>] addr-spec. A good method to assure uniqueness is to put the
+ domain name or a domain literal IP address of the host on which the
+ identifier was created on the right hand side of the "@", and on the
+ left hand side, put a combination of the current calendar date and
+ time of day (i.e., formatted in as a DATE-TIME value) along with some
+ other currently unique (perhaps sequential) identifier available on
+ the system (for example, a process id number). Using a date/time
+ value on the left hand side and a domain name or domain literal on
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 111]</span>
+</pre><pre class="newpage"><a name="page-112" id="page-112" href="#page-112" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ the right hand side makes it possible to guarantee uniqueness since
+ no two hosts should be using the same domain name or IP address at
+ the same time. Though other algorithms will work, it is RECOMMENDED
+ that the right hand side contain some domain identifier (either of
+ the host itself or otherwise) such that the generator of the message
+ identifier can guarantee the uniqueness of the left hand side within
+ the scope of that domain.
+
+ This is the method for correlating scheduling messages with the
+ referenced "VEVENT", "VTODO", or "VJOURNAL" calendar component.
+
+ The full range of calendar components specified by a recurrence set
+ is referenced by referring to just the "UID" property value
+ corresponding to the calendar component. The "RECURRENCE-ID" property
+ allows the reference to an individual instance within the recurrence
+ set.
+
+ This property is an important method for group scheduling
+ applications to match requests with later replies, modifications or
+ deletion requests. Calendaring and scheduling applications MUST
+ generate this property in "VEVENT", "VTODO" and "VJOURNAL" calendar
+ components to assure interoperability with other group scheduling
+ applications. This identifier is created by the calendar system that
+ generates an iCalendar object.
+
+ Implementations MUST be able to receive and persist values of at
+ least 255 characters for this property.
+
+ Format Definition: The property is defined by the following notation:
+
+ uid = "UID" uidparam ":" text CRLF
+
+ uidparam = *(";" xparam)
+
+ Example: The following is an example of this property:
+
+ UID:19960401T080045Z-4000F192713-0052@host1.com
+
+<span class="h4"><h4><a name="section-4.8.5">4.8.5</a> Recurrence Component Properties</h4></span>
+
+ The following properties specify recurrence information in calendar
+ components.
+
+<span class="h5"><h5><a name="section-4.8.5.1">4.8.5.1</a> Exception Date/Times</h5></span>
+
+ Property Name: EXDATE
+
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 112]</span>
+</pre><pre class="newpage"><a name="page-113" id="page-113" href="#page-113" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ Purpose: This property defines the list of date/time exceptions for a
+ recurring calendar component.
+
+ Value Type: The default value type for this property is DATE-TIME.
+ The value type can be set to DATE.
+
+ Property Parameters: Non-standard, value data type and time zone
+ identifier property parameters can be specified on this property.
+
+ Conformance: This property can be specified in an iCalendar object
+ that includes a recurring calendar component.
+
+ Description: The exception dates, if specified, are used in computing
+ the recurrence set. The recurrence set is the complete set of
+ recurrence instances for a calendar component. The recurrence set is
+ generated by considering the initial "DTSTART" property along with
+ the "RRULE", "RDATE", "EXDATE" and "EXRULE" properties contained
+ within the iCalendar object. The "DTSTART" property defines the first
+ instance in the recurrence set. Multiple instances of the "RRULE" and
+ "EXRULE" properties can also be specified to define more
+ sophisticated recurrence sets. The final recurrence set is generated
+ by gathering all of the start date-times generated by any of the
+ specified "RRULE" and "RDATE" properties, and then excluding any
+ start date and times which fall within the union of start date and
+ times generated by any specified "EXRULE" and "EXDATE" properties.
+ This implies that start date and times within exclusion related
+ properties (i.e., "EXDATE" and "EXRULE") take precedence over those
+ specified by inclusion properties (i.e., "RDATE" and "RRULE"). Where
+ duplicate instances are generated by the "RRULE" and "RDATE"
+ properties, only one recurrence is considered. Duplicate instances
+ are ignored.
+
+ The "EXDATE" property can be used to exclude the value specified in
+ "DTSTART". However, in such cases the original "DTSTART" date MUST
+ still be maintained by the calendaring and scheduling system because
+ the original "DTSTART" value has inherent usage dependencies by other
+ properties such as the "RECURRENCE-ID".
+
+ Format Definition: The property is defined by the following notation:
+
+ exdate = "EXDATE" exdtparam ":" exdtval *("," exdtval) CRLF
+
+ exdtparam = *(
+
+ ; the following are optional,
+ ; but MUST NOT occur more than once
+
+ (";" "VALUE" "=" ("DATE-TIME" / "DATE")) /
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 113]</span>
+</pre><pre class="newpage"><a name="page-114" id="page-114" href="#page-114" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ (";" tzidparam) /
+
+ ; the following is optional,
+ ; and MAY occur more than once
+
+ (";" xparam)
+
+ )
+
+ exdtval = date-time / date
+ ;Value MUST match value type
+
+ Example: The following is an example of this property:
+
+ EXDATE:19960402T010000Z,19960403T010000Z,19960404T010000Z
+
+<span class="h5"><h5><a name="section-4.8.5.2">4.8.5.2</a> Exception Rule</h5></span>
+
+ Property Name: EXRULE
+
+ Purpose: This property defines a rule or repeating pattern for an
+ exception to a recurrence set.
+
+ Value Type: RECUR
+
+ Property Parameters: Non-standard property parameters can be
+ specified on this property.
+
+ Conformance: This property can be specified in "VEVENT", "VTODO" or
+ "VJOURNAL" calendar components.
+
+ Description: The exception rule, if specified, is used in computing
+ the recurrence set. The recurrence set is the complete set of
+ recurrence instances for a calendar component. The recurrence set is
+ generated by considering the initial "DTSTART" property along with
+ the "RRULE", "RDATE", "EXDATE" and "EXRULE" properties contained
+ within the iCalendar object. The "DTSTART" defines the first instance
+ in the recurrence set. Multiple instances of the "RRULE" and "EXRULE"
+ properties can also be specified to define more sophisticated
+ recurrence sets. The final recurrence set is generated by gathering
+ all of the start date-times generated by any of the specified "RRULE"
+ and "RDATE" properties, and excluding any start date and times which
+ fall within the union of start date and times generated by any
+ specified "EXRULE" and "EXDATE" properties. This implies that start
+ date and times within exclusion related properties (i.e., "EXDATE"
+ and "EXRULE") take precedence over those specified by inclusion
+
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 114]</span>
+</pre><pre class="newpage"><a name="page-115" id="page-115" href="#page-115" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ properties (i.e., "RDATE" and "RRULE"). Where duplicate instances are
+ generated by the "RRULE" and "RDATE" properties, only one recurrence
+ is considered. Duplicate instances are ignored.
+
+ The "EXRULE" property can be used to exclude the value specified in
+ "DTSTART". However, in such cases the original "DTSTART" date MUST
+ still be maintained by the calendaring and scheduling system because
+ the original "DTSTART" value has inherent usage dependencies by other
+ properties such as the "RECURRENCE-ID".
+
+ Format Definition: The property is defined by the following notation:
+
+ exrule = "EXRULE" exrparam ":" recur CRLF
+
+ exrparam = *(";" xparam)
+
+ Example: The following are examples of this property. Except every
+ other week, on Tuesday and Thursday for 4 occurrences:
+
+ EXRULE:FREQ=WEEKLY;COUNT=4;INTERVAL=2;BYDAY=TU,TH
+
+ Except daily for 10 occurrences:
+
+ EXRULE:FREQ=DAILY;COUNT=10
+
+ Except yearly in June and July for 8 occurrences:
+
+ EXRULE:FREQ=YEARLY;COUNT=8;BYMONTH=6,7
+
+<span class="h5"><h5><a name="section-4.8.5.3">4.8.5.3</a> Recurrence Date/Times</h5></span>
+
+ Property Name: RDATE
+
+ Purpose: This property defines the list of date/times for a
+ recurrence set.
+
+ Value Type: The default value type for this property is DATE-TIME.
+ The value type can be set to DATE or PERIOD.
+
+ Property Parameters: Non-standard, value data type and time zone
+ identifier property parameters can be specified on this property.
+
+ Conformance: The property can be specified in "VEVENT", "VTODO",
+ "VJOURNAL" or "VTIMEZONE" calendar components.
+
+
+
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 115]</span>
+</pre><pre class="newpage"><a name="page-116" id="page-116" href="#page-116" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ Description: This property can appear along with the "RRULE" property
+ to define an aggregate set of repeating occurrences. When they both
+ appear in an iCalendar object, the recurring events are defined by
+ the union of occurrences defined by both the "RDATE" and "RRULE".
+
+ The recurrence dates, if specified, are used in computing the
+ recurrence set. The recurrence set is the complete set of recurrence
+ instances for a calendar component. The recurrence set is generated
+ by considering the initial "DTSTART" property along with the "RRULE",
+ "RDATE", "EXDATE" and "EXRULE" properties contained within the
+ iCalendar object. The "DTSTART" property defines the first instance
+ in the recurrence set. Multiple instances of the "RRULE" and "EXRULE"
+ properties can also be specified to define more sophisticated
+ recurrence sets. The final recurrence set is generated by gathering
+ all of the start date/times generated by any of the specified "RRULE"
+ and "RDATE" properties, and excluding any start date/times which fall
+ within the union of start date/times generated by any specified
+ "EXRULE" and "EXDATE" properties. This implies that start date/times
+ within exclusion related properties (i.e., "EXDATE" and "EXRULE")
+ take precedence over those specified by inclusion properties (i.e.,
+ "RDATE" and "RRULE"). Where duplicate instances are generated by the
+ "RRULE" and "RDATE" properties, only one recurrence is considered.
+ Duplicate instances are ignored.
+
+ Format Definition: The property is defined by the following notation:
+
+ rdate = "RDATE" rdtparam ":" rdtval *("," rdtval) CRLF
+
+ rdtparam = *(
+
+ ; the following are optional,
+ ; but MUST NOT occur more than once
+
+ (";" "VALUE" "=" ("DATE-TIME" / "DATE" / "PERIOD")) /
+ (";" tzidparam) /
+
+ ; the following is optional,
+ ; and MAY occur more than once
+
+ (";" xparam)
+
+ )
+
+ rdtval = date-time / date / period
+ ;Value MUST match value type
+
+ Example: The following are examples of this property:
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 116]</span>
+</pre><pre class="newpage"><a name="page-117" id="page-117" href="#page-117" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ RDATE:19970714T123000Z
+
+ RDATE;TZID=US-EASTERN:19970714T083000
+
+ RDATE;VALUE=PERIOD:19960403T020000Z/19960403T040000Z,
+ 19960404T010000Z/PT3H
+
+ RDATE;VALUE=DATE:19970101,19970120,19970217,19970421
+ 19970526,19970704,19970901,19971014,19971128,19971129,19971225
+
+<span class="h5"><h5><a name="section-4.8.5.4">4.8.5.4</a> Recurrence Rule</h5></span>
+
+ Property Name: RRULE
+
+ Purpose: This property defines a rule or repeating pattern for
+ recurring events, to-dos, or time zone definitions.
+
+ Value Type: RECUR
+
+ Property Parameters: Non-standard property parameters can be
+ specified on this property.
+
+ Conformance: This property can be specified one or more times in
+ recurring "VEVENT", "VTODO" and "VJOURNAL" calendar components. It
+ can also be specified once in each STANDARD or DAYLIGHT sub-component
+ of the "VTIMEZONE" calendar component.
+
+ Description: The recurrence rule, if specified, is used in computing
+ the recurrence set. The recurrence set is the complete set of
+ recurrence instances for a calendar component. The recurrence set is
+ generated by considering the initial "DTSTART" property along with
+ the "RRULE", "RDATE", "EXDATE" and "EXRULE" properties contained
+ within the iCalendar object. The "DTSTART" property defines the first
+ instance in the recurrence set. Multiple instances of the "RRULE" and
+ "EXRULE" properties can also be specified to define more
+ sophisticated recurrence sets. The final recurrence set is generated
+ by gathering all of the start date/times generated by any of the
+ specified "RRULE" and "RDATE" properties, and excluding any start
+ date/times which fall within the union of start date/times generated
+ by any specified "EXRULE" and "EXDATE" properties. This implies that
+ start date/times within exclusion related properties (i.e., "EXDATE"
+ and "EXRULE") take precedence over those specified by inclusion
+ properties (i.e., "RDATE" and "RRULE"). Where duplicate instances are
+ generated by the "RRULE" and "RDATE" properties, only one recurrence
+ is considered. Duplicate instances are ignored.
+
+
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 117]</span>
+</pre><pre class="newpage"><a name="page-118" id="page-118" href="#page-118" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ The "DTSTART" and "DTEND" property pair or "DTSTART" and "DURATION"
+ property pair, specified within the iCalendar object defines the
+ first instance of the recurrence. When used with a recurrence rule,
+ the "DTSTART" and "DTEND" properties MUST be specified in local time
+ and the appropriate set of "VTIMEZONE" calendar components MUST be
+ included. For detail on the usage of the "VTIMEZONE" calendar
+ component, see the "VTIMEZONE" calendar component definition.
+
+ Any duration associated with the iCalendar object applies to all
+ members of the generated recurrence set. Any modified duration for
+ specific recurrences MUST be explicitly specified using the "RDATE"
+ property.
+
+ Format Definition: This property is defined by the following
+ notation:
+
+ rrule = "RRULE" rrulparam ":" recur CRLF
+
+ rrulparam = *(";" xparam)
+
+ Example: All examples assume the Eastern United States time zone.
+
+ Daily for 10 occurrences:
+
+ DTSTART;TZID=US-Eastern:19970902T090000
+ RRULE:FREQ=DAILY;COUNT=10
+
+ ==> (1997 9:00 AM EDT)September 2-11
+
+ Daily until December 24, 1997:
+
+ DTSTART;TZID=US-Eastern:19970902T090000
+ RRULE:FREQ=DAILY;UNTIL=19971224T000000Z
+
+ ==> (1997 9:00 AM EDT)September 2-30;October 1-25
+ (1997 9:00 AM EST)October 26-31;November 1-30;December 1-23
+
+ Every other day - forever:
+
+ DTSTART;TZID=US-Eastern:19970902T090000
+ RRULE:FREQ=DAILY;INTERVAL=2
+ ==> (1997 9:00 AM EDT)September2,4,6,8...24,26,28,30;
+ October 2,4,6...20,22,24
+ (1997 9:00 AM EST)October 26,28,30;November 1,3,5,7...25,27,29;
+ Dec 1,3,...
+
+ Every 10 days, 5 occurrences:
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 118]</span>
+</pre><pre class="newpage"><a name="page-119" id="page-119" href="#page-119" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ DTSTART;TZID=US-Eastern:19970902T090000
+ RRULE:FREQ=DAILY;INTERVAL=10;COUNT=5
+
+ ==> (1997 9:00 AM EDT)September 2,12,22;October 2,12
+
+ Everyday in January, for 3 years:
+
+ DTSTART;TZID=US-Eastern:19980101T090000
+ RRULE:FREQ=YEARLY;UNTIL=20000131T090000Z;
+ BYMONTH=1;BYDAY=SU,MO,TU,WE,TH,FR,SA
+ or
+ RRULE:FREQ=DAILY;UNTIL=20000131T090000Z;BYMONTH=1
+
+ ==> (1998 9:00 AM EDT)January 1-31
+ (1999 9:00 AM EDT)January 1-31
+ (2000 9:00 AM EDT)January 1-31
+
+ Weekly for 10 occurrences
+
+ DTSTART;TZID=US-Eastern:19970902T090000
+ RRULE:FREQ=WEEKLY;COUNT=10
+
+ ==> (1997 9:00 AM EDT)September 2,9,16,23,30;October 7,14,21
+ (1997 9:00 AM EST)October 28;November 4
+
+ Weekly until December 24, 1997
+
+ DTSTART;TZID=US-Eastern:19970902T090000
+ RRULE:FREQ=WEEKLY;UNTIL=19971224T000000Z
+
+ ==> (1997 9:00 AM EDT)September 2,9,16,23,30;October 7,14,21
+ (1997 9:00 AM EST)October 28;November 4,11,18,25;
+ December 2,9,16,23
+ Every other week - forever:
+
+ DTSTART;TZID=US-Eastern:19970902T090000
+ RRULE:FREQ=WEEKLY;INTERVAL=2;WKST=SU
+
+ ==> (1997 9:00 AM EDT)September 2,16,30;October 14
+ (1997 9:00 AM EST)October 28;November 11,25;December 9,23
+ (1998 9:00 AM EST)January 6,20;February
+ ...
+
+ Weekly on Tuesday and Thursday for 5 weeks:
+
+ DTSTART;TZID=US-Eastern:19970902T090000
+ RRULE:FREQ=WEEKLY;UNTIL=19971007T000000Z;WKST=SU;BYDAY=TU,TH
+ or
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 119]</span>
+</pre><pre class="newpage"><a name="page-120" id="page-120" href="#page-120" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ RRULE:FREQ=WEEKLY;COUNT=10;WKST=SU;BYDAY=TU,TH
+
+ ==> (1997 9:00 AM EDT)September 2,4,9,11,16,18,23,25,30;October 2
+
+ Every other week on Monday, Wednesday and Friday until December 24,
+ 1997, but starting on Tuesday, September 2, 1997:
+
+ DTSTART;TZID=US-Eastern:19970902T090000
+ RRULE:FREQ=WEEKLY;INTERVAL=2;UNTIL=19971224T000000Z;WKST=SU;
+ BYDAY=MO,WE,FR
+ ==> (1997 9:00 AM EDT)September 2,3,5,15,17,19,29;October
+ 1,3,13,15,17
+ (1997 9:00 AM EST)October 27,29,31;November 10,12,14,24,26,28;
+ December 8,10,12,22
+
+ Every other week on Tuesday and Thursday, for 8 occurrences:
+
+ DTSTART;TZID=US-Eastern:19970902T090000
+ RRULE:FREQ=WEEKLY;INTERVAL=2;COUNT=8;WKST=SU;BYDAY=TU,TH
+
+ ==> (1997 9:00 AM EDT)September 2,4,16,18,30;October 2,14,16
+
+ Monthly on the 1st Friday for ten occurrences:
+
+ DTSTART;TZID=US-Eastern:19970905T090000
+ RRULE:FREQ=MONTHLY;COUNT=10;BYDAY=1FR
+
+ ==> (1997 9:00 AM EDT)September 5;October 3
+ (1997 9:00 AM EST)November 7;Dec 5
+ (1998 9:00 AM EST)January 2;February 6;March 6;April 3
+ (1998 9:00 AM EDT)May 1;June 5
+
+ Monthly on the 1st Friday until December 24, 1997:
+
+ DTSTART;TZID=US-Eastern:19970905T090000
+ RRULE:FREQ=MONTHLY;UNTIL=19971224T000000Z;BYDAY=1FR
+
+ ==> (1997 9:00 AM EDT)September 5;October 3
+ (1997 9:00 AM EST)November 7;December 5
+
+ Every other month on the 1st and last Sunday of the month for 10
+ occurrences:
+
+ DTSTART;TZID=US-Eastern:19970907T090000
+ RRULE:FREQ=MONTHLY;INTERVAL=2;COUNT=10;BYDAY=1SU,-1SU
+
+ ==> (1997 9:00 AM EDT)September 7,28
+ (1997 9:00 AM EST)November 2,30
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 120]</span>
+</pre><pre class="newpage"><a name="page-121" id="page-121" href="#page-121" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ (1998 9:00 AM EST)January 4,25;March 1,29
+ (1998 9:00 AM EDT)May 3,31
+
+ Monthly on the second to last Monday of the month for 6 months:
+
+ DTSTART;TZID=US-Eastern:19970922T090000
+ RRULE:FREQ=MONTHLY;COUNT=6;BYDAY=-2MO
+
+ ==> (1997 9:00 AM EDT)September 22;October 20
+ (1997 9:00 AM EST)November 17;December 22
+ (1998 9:00 AM EST)January 19;February 16
+
+ Monthly on the third to the last day of the month, forever:
+
+ DTSTART;TZID=US-Eastern:19970928T090000
+ RRULE:FREQ=MONTHLY;BYMONTHDAY=-3
+
+ ==> (1997 9:00 AM EDT)September 28
+ (1997 9:00 AM EST)October 29;November 28;December 29
+ (1998 9:00 AM EST)January 29;February 26
+ ...
+
+ Monthly on the 2nd and 15th of the month for 10 occurrences:
+
+ DTSTART;TZID=US-Eastern:19970902T090000
+ RRULE:FREQ=MONTHLY;COUNT=10;BYMONTHDAY=2,15
+
+ ==> (1997 9:00 AM EDT)September 2,15;October 2,15
+ (1997 9:00 AM EST)November 2,15;December 2,15
+ (1998 9:00 AM EST)January 2,15
+
+ Monthly on the first and last day of the month for 10 occurrences:
+
+ DTSTART;TZID=US-Eastern:19970930T090000
+ RRULE:FREQ=MONTHLY;COUNT=10;BYMONTHDAY=1,-1
+
+ ==> (1997 9:00 AM EDT)September 30;October 1
+ (1997 9:00 AM EST)October 31;November 1,30;December 1,31
+ (1998 9:00 AM EST)January 1,31;February 1
+
+ Every 18 months on the 10th thru 15th of the month for 10
+ occurrences:
+
+ DTSTART;TZID=US-Eastern:19970910T090000
+ RRULE:FREQ=MONTHLY;INTERVAL=18;COUNT=10;BYMONTHDAY=10,11,12,13,14,
+ 15
+
+ ==> (1997 9:00 AM EDT)September 10,11,12,13,14,15
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 121]</span>
+</pre><pre class="newpage"><a name="page-122" id="page-122" href="#page-122" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ (1999 9:00 AM EST)March 10,11,12,13
+
+ Every Tuesday, every other month:
+
+ DTSTART;TZID=US-Eastern:19970902T090000
+ RRULE:FREQ=MONTHLY;INTERVAL=2;BYDAY=TU
+
+ ==> (1997 9:00 AM EDT)September 2,9,16,23,30
+ (1997 9:00 AM EST)November 4,11,18,25
+ (1998 9:00 AM EST)January 6,13,20,27;March 3,10,17,24,31
+ ...
+
+ Yearly in June and July for 10 occurrences:
+
+ DTSTART;TZID=US-Eastern:19970610T090000
+ RRULE:FREQ=YEARLY;COUNT=10;BYMONTH=6,7
+ ==> (1997 9:00 AM EDT)June 10;July 10
+ (1998 9:00 AM EDT)June 10;July 10
+ (1999 9:00 AM EDT)June 10;July 10
+ (2000 9:00 AM EDT)June 10;July 10
+ (2001 9:00 AM EDT)June 10;July 10
+ Note: Since none of the BYDAY, BYMONTHDAY or BYYEARDAY components
+ are specified, the day is gotten from DTSTART
+
+ Every other year on January, February, and March for 10 occurrences:
+
+ DTSTART;TZID=US-Eastern:19970310T090000
+ RRULE:FREQ=YEARLY;INTERVAL=2;COUNT=10;BYMONTH=1,2,3
+
+ ==> (1997 9:00 AM EST)March 10
+ (1999 9:00 AM EST)January 10;February 10;March 10
+ (2001 9:00 AM EST)January 10;February 10;March 10
+ (2003 9:00 AM EST)January 10;February 10;March 10
+
+ Every 3rd year on the 1st, 100th and 200th day for 10 occurrences:
+
+ DTSTART;TZID=US-Eastern:19970101T090000
+ RRULE:FREQ=YEARLY;INTERVAL=3;COUNT=10;BYYEARDAY=1,100,200
+
+ ==> (1997 9:00 AM EST)January 1
+ (1997 9:00 AM EDT)April 10;July 19
+ (2000 9:00 AM EST)January 1
+ (2000 9:00 AM EDT)April 9;July 18
+ (2003 9:00 AM EST)January 1
+ (2003 9:00 AM EDT)April 10;July 19
+ (2006 9:00 AM EST)January 1
+
+ Every 20th Monday of the year, forever:
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 122]</span>
+</pre><pre class="newpage"><a name="page-123" id="page-123" href="#page-123" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ DTSTART;TZID=US-Eastern:19970519T090000
+ RRULE:FREQ=YEARLY;BYDAY=20MO
+
+ ==> (1997 9:00 AM EDT)May 19
+ (1998 9:00 AM EDT)May 18
+ (1999 9:00 AM EDT)May 17
+ ...
+
+ Monday of week number 20 (where the default start of the week is
+ Monday), forever:
+
+ DTSTART;TZID=US-Eastern:19970512T090000
+ RRULE:FREQ=YEARLY;BYWEEKNO=20;BYDAY=MO
+
+ ==> (1997 9:00 AM EDT)May 12
+ (1998 9:00 AM EDT)May 11
+ (1999 9:00 AM EDT)May 17
+ ...
+
+ Every Thursday in March, forever:
+
+ DTSTART;TZID=US-Eastern:19970313T090000
+ RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=TH
+
+ ==> (1997 9:00 AM EST)March 13,20,27
+ (1998 9:00 AM EST)March 5,12,19,26
+ (1999 9:00 AM EST)March 4,11,18,25
+ ...
+
+ Every Thursday, but only during June, July, and August, forever:
+
+ DTSTART;TZID=US-Eastern:19970605T090000
+ RRULE:FREQ=YEARLY;BYDAY=TH;BYMONTH=6,7,8
+
+ ==> (1997 9:00 AM EDT)June 5,12,19,26;July 3,10,17,24,31;
+ August 7,14,21,28
+ (1998 9:00 AM EDT)June 4,11,18,25;July 2,9,16,23,30;
+ August 6,13,20,27
+ (1999 9:00 AM EDT)June 3,10,17,24;July 1,8,15,22,29;
+ August 5,12,19,26
+ ...
+
+ Every Friday the 13th, forever:
+
+ DTSTART;TZID=US-Eastern:19970902T090000
+ EXDATE;TZID=US-Eastern:19970902T090000
+ RRULE:FREQ=MONTHLY;BYDAY=FR;BYMONTHDAY=13
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 123]</span>
+</pre><pre class="newpage"><a name="page-124" id="page-124" href="#page-124" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ ==> (1998 9:00 AM EST)February 13;March 13;November 13
+ (1999 9:00 AM EDT)August 13
+ (2000 9:00 AM EDT)October 13
+ ...
+
+ The first Saturday that follows the first Sunday of the month,
+ forever:
+
+ DTSTART;TZID=US-Eastern:19970913T090000
+ RRULE:FREQ=MONTHLY;BYDAY=SA;BYMONTHDAY=7,8,9,10,11,12,13
+
+ ==> (1997 9:00 AM EDT)September 13;October 11
+ (1997 9:00 AM EST)November 8;December 13
+ (1998 9:00 AM EST)January 10;February 7;March 7
+ (1998 9:00 AM EDT)April 11;May 9;June 13...
+ ...
+
+ Every four years, the first Tuesday after a Monday in November,
+ forever (U.S. Presidential Election day):
+
+ DTSTART;TZID=US-Eastern:19961105T090000
+ RRULE:FREQ=YEARLY;INTERVAL=4;BYMONTH=11;BYDAY=TU;BYMONTHDAY=2,3,4,
+ 5,6,7,8
+
+ ==> (1996 9:00 AM EST)November 5
+ (2000 9:00 AM EST)November 7
+ (2004 9:00 AM EST)November 2
+ ...
+
+ The 3rd instance into the month of one of Tuesday, Wednesday or
+ Thursday, for the next 3 months:
+
+ DTSTART;TZID=US-Eastern:19970904T090000
+ RRULE:FREQ=MONTHLY;COUNT=3;BYDAY=TU,WE,TH;BYSETPOS=3
+
+ ==> (1997 9:00 AM EDT)September 4;October 7
+ (1997 9:00 AM EST)November 6
+
+ The 2nd to last weekday of the month:
+
+ DTSTART;TZID=US-Eastern:19970929T090000
+ RRULE:FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-2
+
+ ==> (1997 9:00 AM EDT)September 29
+ (1997 9:00 AM EST)October 30;November 27;December 30
+ (1998 9:00 AM EST)January 29;February 26;March 30
+ ...
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 124]</span>
+</pre><pre class="newpage"><a name="page-125" id="page-125" href="#page-125" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ Every 3 hours from 9:00 AM to 5:00 PM on a specific day:
+
+ DTSTART;TZID=US-Eastern:19970902T090000
+ RRULE:FREQ=HOURLY;INTERVAL=3;UNTIL=19970902T170000Z
+
+ ==> (September 2, 1997 EDT)09:00,12:00,15:00
+
+ Every 15 minutes for 6 occurrences:
+
+ DTSTART;TZID=US-Eastern:19970902T090000
+ RRULE:FREQ=MINUTELY;INTERVAL=15;COUNT=6
+
+ ==> (September 2, 1997 EDT)09:00,09:15,09:30,09:45,10:00,10:15
+
+ Every hour and a half for 4 occurrences:
+
+ DTSTART;TZID=US-Eastern:19970902T090000
+ RRULE:FREQ=MINUTELY;INTERVAL=90;COUNT=4
+
+ ==> (September 2, 1997 EDT)09:00,10:30;12:00;13:30
+
+ Every 20 minutes from 9:00 AM to 4:40 PM every day:
+
+ DTSTART;TZID=US-Eastern:19970902T090000
+ RRULE:FREQ=DAILY;BYHOUR=9,10,11,12,13,14,15,16;BYMINUTE=0,20,40
+ or
+ RRULE:FREQ=MINUTELY;INTERVAL=20;BYHOUR=9,10,11,12,13,14,15,16
+
+ ==> (September 2, 1997 EDT)9:00,9:20,9:40,10:00,10:20,
+ ... 16:00,16:20,16:40
+ (September 3, 1997 EDT)9:00,9:20,9:40,10:00,10:20,
+ ...16:00,16:20,16:40
+ ...
+
+ An example where the days generated makes a difference because of
+ WKST:
+
+ DTSTART;TZID=US-Eastern:19970805T090000
+ RRULE:FREQ=WEEKLY;INTERVAL=2;COUNT=4;BYDAY=TU,SU;WKST=MO
+
+ ==> (1997 EDT)Aug 5,10,19,24
+
+ changing only WKST from MO to SU, yields different results...
+
+ DTSTART;TZID=US-Eastern:19970805T090000
+ RRULE:FREQ=WEEKLY;INTERVAL=2;COUNT=4;BYDAY=TU,SU;WKST=SU
+ ==> (1997 EDT)August 5,17,19,31
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 125]</span>
+</pre><pre class="newpage"><a name="page-126" id="page-126" href="#page-126" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+<span class="h4"><h4><a name="section-4.8.6">4.8.6</a> Alarm Component Properties</h4></span>
+
+ The following properties specify alarm information in calendar
+ components.
+
+<span class="h5"><h5><a name="section-4.8.6.1">4.8.6.1</a> Action</h5></span>
+
+ Property Name: ACTION
+
+ Purpose: This property defines the action to be invoked when an alarm
+ is triggered.
+
+ Value Type: TEXT
+
+ Property Parameters: Non-standard property parameters can be
+ specified on this property.
+
+ Conformance: This property MUST be specified once in a "VALARM"
+ calendar component.
+
+ Description: Each "VALARM" calendar component has a particular type
+ of action associated with it. This property specifies the type of
+ action
+
+ Format Definition: The property is defined by the following notation:
+
+ action = "ACTION" actionparam ":" actionvalue CRLF
+
+ actionparam = *(";" xparam)
+
+ actionvalue = "AUDIO" / "DISPLAY" / "EMAIL" / "PROCEDURE"
+ / iana-token / x-name
+
+ Example: The following are examples of this property in a "VALARM"
+ calendar component:
+
+ ACTION:AUDIO
+
+ ACTION:DISPLAY
+
+ ACTION:PROCEDURE
+
+<span class="h5"><h5><a name="section-4.8.6.2">4.8.6.2</a> Repeat Count</h5></span>
+
+ Property Name: REPEAT
+
+ Purpose: This property defines the number of time the alarm should be
+ repeated, after the initial trigger.
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 126]</span>
+</pre><pre class="newpage"><a name="page-127" id="page-127" href="#page-127" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ Value Type: INTEGER
+
+ Property Parameters: Non-standard property parameters can be
+ specified on this property.
+
+ Conformance: This property can be specified in a "VALARM" calendar
+ component.
+
+ Description: If the alarm triggers more than once, then this property
+ MUST be specified along with the "DURATION" property.
+
+ Format Definition: The property is defined by the following notation:
+
+ repeatcnt = "REPEAT" repparam ":" integer CRLF
+ ;Default is "0", zero.
+
+ repparam = *(";" xparam)
+
+ Example: The following is an example of this property for an alarm
+ that repeats 4 additional times with a 5 minute delay after the
+ initial triggering of the alarm:
+
+ REPEAT:4
+ DURATION:PT5M
+
+<span class="h5"><h5><a name="section-4.8.6.3">4.8.6.3</a> Trigger</h5></span>
+
+ Property Name: TRIGGER
+
+ Purpose: This property specifies when an alarm will trigger.
+
+ Value Type: The default value type is DURATION. The value type can be
+ set to a DATE-TIME value type, in which case the value MUST specify a
+ UTC formatted DATE-TIME value.
+
+ Property Parameters: Non-standard, value data type, time zone
+ identifier or trigger relationship property parameters can be
+ specified on this property. The trigger relationship property
+ parameter MUST only be specified when the value type is DURATION.
+
+ Conformance: This property MUST be specified in the "VALARM" calendar
+ component.
+
+ Description: Within the "VALARM" calendar component, this property
+ defines when the alarm will trigger. The default value type is
+ DURATION, specifying a relative time for the trigger of the alarm.
+ The default duration is relative to the start of an event or to-do
+ that the alarm is associated with. The duration can be explicitly set
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 127]</span>
+</pre><pre class="newpage"><a name="page-128" id="page-128" href="#page-128" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ to trigger from either the end or the start of the associated event
+ or to-do with the "RELATED" parameter. A value of START will set the
+ alarm to trigger off the start of the associated event or to-do. A
+ value of END will set the alarm to trigger off the end of the
+ associated event or to-do.
+
+ Either a positive or negative duration may be specified for the
+ "TRIGGER" property. An alarm with a positive duration is triggered
+ after the associated start or end of the event or to-do. An alarm
+ with a negative duration is triggered before the associated start or
+ end of the event or to-do.
+
+ The "RELATED" property parameter is not valid if the value type of
+ the property is set to DATE-TIME (i.e., for an absolute date and time
+ alarm trigger). If a value type of DATE-TIME is specified, then the
+ property value MUST be specified in the UTC time format. If an
+ absolute trigger is specified on an alarm for a recurring event or
+ to-do, then the alarm will only trigger for the specified absolute
+ date/time, along with any specified repeating instances.
+
+ If the trigger is set relative to START, then the "DTSTART" property
+ MUST be present in the associated "VEVENT" or "VTODO" calendar
+ component. If an alarm is specified for an event with the trigger set
+ relative to the END, then the "DTEND" property or the "DSTART" and
+ "DURATION' properties MUST be present in the associated "VEVENT"
+ calendar component. If the alarm is specified for a to-do with a
+ trigger set relative to the END, then either the "DUE" property or
+ the "DSTART" and "DURATION' properties MUST be present in the
+ associated "VTODO" calendar component.
+
+ Alarms specified in an event or to-do which is defined in terms of a
+ DATE value type will be triggered relative to 00:00:00 UTC on the
+ specified date. For example, if "DTSTART:19980205, then the duration
+ trigger will be relative to19980205T000000Z.
+
+ Format Definition: The property is defined by the following notation:
+
+ trigger = "TRIGGER" (trigrel / trigabs)
+
+ trigrel = *(
+
+ ; the following are optional,
+ ; but MUST NOT occur more than once
+
+ (";" "VALUE" "=" "DURATION") /
+ (";" trigrelparam) /
+
+ ; the following is optional,
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 128]</span>
+</pre><pre class="newpage"><a name="page-129" id="page-129" href="#page-129" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ ; and MAY occur more than once
+
+ (";" xparam)
+ ) ":" dur-value
+
+ trigabs = 1*(
+
+ ; the following is REQUIRED,
+ ; but MUST NOT occur more than once
+
+ (";" "VALUE" "=" "DATE-TIME") /
+
+ ; the following is optional,
+ ; and MAY occur more than once
+
+ (";" xparam)
+
+ ) ":" date-time
+
+ Example: A trigger set 15 minutes prior to the start of the event or
+ to-do.
+
+ TRIGGER:-P15M
+
+ A trigger set 5 minutes after the end of the event or to-do.
+
+ TRIGGER;RELATED=END:P5M
+
+ A trigger set to an absolute date/time.
+
+ TRIGGER;VALUE=DATE-TIME:19980101T050000Z
+
+<span class="h4"><h4><a name="section-4.8.7">4.8.7</a> Change Management Component Properties</h4></span>
+
+ The following properties specify change management information in
+ calendar components.
+
+<span class="h5"><h5><a name="section-4.8.7.1">4.8.7.1</a> Date/Time Created</h5></span>
+
+ Property Name: CREATED
+
+ Purpose: This property specifies the date and time that the calendar
+ information was created by the calendar user agent in the calendar
+ store.
+
+ Note: This is analogous to the creation date and time for a file
+ in the file system.
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 129]</span>
+</pre><pre class="newpage"><a name="page-130" id="page-130" href="#page-130" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ Value Type: DATE-TIME
+
+ Property Parameters: Non-standard property parameters can be
+ specified on this property.
+
+ Conformance: The property can be specified once in "VEVENT", "VTODO"
+ or "VJOURNAL" calendar components.
+
+ Description: The date and time is a UTC value.
+
+ Format Definition: The property is defined by the following notation:
+
+ created = "CREATED" creaparam ":" date-time CRLF
+
+ creaparam = *(";" xparam)
+
+ Example: The following is an example of this property:
+
+ CREATED:19960329T133000Z
+
+<span class="h5"><h5><a name="section-4.8.7.2">4.8.7.2</a> Date/Time Stamp</h5></span>
+
+ Property Name: DTSTAMP
+
+ Purpose: The property indicates the date/time that the instance of
+ the iCalendar object was created.
+
+ Value Type: DATE-TIME
+
+ Property Parameters: Non-standard property parameters can be
+ specified on this property.
+
+ Conformance: This property MUST be included in the "VEVENT", "VTODO",
+ "VJOURNAL" or "VFREEBUSY" calendar components.
+
+ Description: The value MUST be specified in the UTC time format.
+
+ This property is also useful to protocols such as [<a href="#ref-IMIP" title=""iCalendar Message-based Interoperability Protocol (IMIP)"">IMIP</a>] that have
+ inherent latency issues with the delivery of content. This property
+ will assist in the proper sequencing of messages containing iCalendar
+ objects.
+
+ This property is different than the "CREATED" and "LAST-MODIFIED"
+ properties. These two properties are used to specify when the
+ particular calendar data in the calendar store was created and last
+ modified. This is different than when the iCalendar object
+ representation of the calendar service information was created or
+ last modified.
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 130]</span>
+</pre><pre class="newpage"><a name="page-131" id="page-131" href="#page-131" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ Format Definition: The property is defined by the following notation:
+
+ dtstamp = "DTSTAMP" stmparam ":" date-time CRLF
+
+ stmparam = *(";" xparam)
+
+ Example:
+
+ DTSTAMP:19971210T080000Z
+
+<span class="h5"><h5><a name="section-4.8.7.3">4.8.7.3</a> Last Modified</h5></span>
+
+ Property Name: LAST-MODIFIED
+
+ Purpose: The property specifies the date and time that the
+ information associated with the calendar component was last revised
+ in the calendar store.
+
+ Note: This is analogous to the modification date and time for a
+ file in the file system.
+
+ Value Type: DATE-TIME
+
+ Property Parameters: Non-standard property parameters can be
+ specified on this property.
+
+ Conformance: This property can be specified in the "EVENT", "VTODO",
+ "VJOURNAL" or "VTIMEZONE" calendar components.
+
+ Description: The property value MUST be specified in the UTC time
+ format.
+
+ Format Definition: The property is defined by the following notation:
+
+ last-mod = "LAST-MODIFIED" lstparam ":" date-time CRLF
+
+ lstparam = *(";" xparam)
+
+ Example: The following is are examples of this property:
+
+ LAST-MODIFIED:19960817T133000Z
+
+<span class="h5"><h5><a name="section-4.8.7.4">4.8.7.4</a> Sequence Number</h5></span>
+
+ Property Name: SEQUENCE
+
+ Purpose: This property defines the revision sequence number of the
+ calendar component within a sequence of revisions.
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 131]</span>
+</pre><pre class="newpage"><a name="page-132" id="page-132" href="#page-132" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ Value Type: integer
+
+ Property Parameters: Non-standard property parameters can be
+ specified on this property.
+
+ Conformance: The property can be specified in "VEVENT", "VTODO" or
+ "VJOURNAL" calendar component.
+
+ Description: When a calendar component is created, its sequence
+ number is zero (US-ASCII decimal 48). It is monotonically incremented
+ by the "Organizer's" CUA each time the "Organizer" makes a
+ significant revision to the calendar component. When the "Organizer"
+ makes changes to one of the following properties, the sequence number
+ MUST be incremented:
+
+ . "DTSTART"
+
+ . "DTEND"
+
+ . "DUE"
+
+ . "RDATE"
+
+ . "RRULE"
+
+ . "EXDATE"
+
+ . "EXRULE"
+
+ . "STATUS"
+
+ In addition, changes made by the "Organizer" to other properties can
+ also force the sequence number to be incremented. The "Organizer" CUA
+ MUST increment the sequence number when ever it makes changes to
+ properties in the calendar component that the "Organizer" deems will
+ jeopardize the validity of the participation status of the
+ "Attendees". For example, changing the location of a meeting from one
+ locale to another distant locale could effectively impact the
+ participation status of the "Attendees".
+
+ The "Organizer" includes this property in an iCalendar object that it
+ sends to an "Attendee" to specify the current version of the calendar
+ component.
+
+ The "Attendee" includes this property in an iCalendar object that it
+ sends to the "Organizer" to specify the version of the calendar
+ component that the "Attendee" is referring to.
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 132]</span>
+</pre><pre class="newpage"><a name="page-133" id="page-133" href="#page-133" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ A change to the sequence number is not the mechanism that an
+ "Organizer" uses to request a response from the "Attendees". The
+ "RSVP" parameter on the "ATTENDEE" property is used by the
+ "Organizer" to indicate that a response from the "Attendees" is
+ requested.
+
+ Format Definition: This property is defined by the following
+ notation:
+
+ seq = "SEQUENCE" seqparam ":" integer CRLF
+ ; Default is "0"
+
+ seqparam = *(";" xparam)
+
+ Example: The following is an example of this property for a calendar
+ component that was just created by the "Organizer".
+
+ SEQUENCE:0
+
+ The following is an example of this property for a calendar component
+ that has been revised two different times by the "Organizer".
+
+ SEQUENCE:2
+
+<span class="h4"><h4><a name="section-4.8.8">4.8.8</a> Miscellaneous Component Properties</h4></span>
+
+ The following properties specify information about a number of
+ miscellaneous features of calendar components.
+
+<span class="h5"><h5><a name="section-4.8.8.1">4.8.8.1</a> Non-standard Properties</h5></span>
+
+ Property Name: Any property name with a "X-" prefix
+
+ Purpose: This class of property provides a framework for defining
+ non-standard properties.
+
+ Value Type: TEXT
+
+ Property Parameters: Non-standard and language property parameters
+ can be specified on this property.
+
+ Conformance: This property can be specified in any calendar
+ component.
+
+ Description: The MIME Calendaring and Scheduling Content Type
+ provides a "standard mechanism for doing non-standard things". This
+ extension support is provided for implementers to "push the envelope"
+ on the existing version of the memo. Extension properties are
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 133]</span>
+</pre><pre class="newpage"><a name="page-134" id="page-134" href="#page-134" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ specified by property and/or property parameter names that have the
+ prefix text of "X-" (the two character sequence: LATIN CAPITAL LETTER
+ X character followed by the HYPEN-MINUS character). It is recommended
+ that vendors concatenate onto this sentinel another short prefix text
+ to identify the vendor. This will facilitate readability of the
+ extensions and minimize possible collision of names between different
+ vendors. User agents that support this content type are expected to
+ be able to parse the extension properties and property parameters but
+ can ignore them.
+
+ At present, there is no registration authority for names of extension
+ properties and property parameters. The data type for this property
+ is TEXT. Optionally, the data type can be any of the other valid data
+ types.
+
+ Format Definition: The property is defined by the following notation:
+
+ x-prop = x-name *(";" xparam) [";" languageparam] ":" text CRLF
+ ; Lines longer than 75 octets should be folded
+
+ Example: The following might be the ABC vendor's extension for an
+ audio-clip form of subject property:
+
+ X-ABC-MMSUBJ;X-ABC-MMSUBJTYPE=wave:http://load.noise.org/mysubj.wav
+
+<span class="h5"><h5><a name="section-4.8.8.2">4.8.8.2</a> Request Status</h5></span>
+
+ Property Name: REQUEST-STATUS
+
+ Purpose: This property defines the status code returned for a
+ scheduling request.
+
+ Value Type: TEXT
+
+ Property Parameters: Non-standard and language property parameters
+ can be specified on this property.
+
+ Conformance: The property can be specified in "VEVENT", "VTODO",
+ "VJOURNAL" or "VFREEBUSY" calendar component.
+
+ Description: This property is used to return status code information
+ related to the processing of an associated iCalendar object. The data
+ type for this property is TEXT.
+
+ The value consists of a short return status component, a longer
+ return status description component, and optionally a status-specific
+ data component. The components of the value are separated by the
+ SEMICOLON character (US-ASCII decimal 59).
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 134]</span>
+</pre><pre class="newpage"><a name="page-135" id="page-135" href="#page-135" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ The short return status is a PERIOD character (US-ASCII decimal 46)
+ separated 3-tuple of integers. For example, "3.1.1". The successive
+ levels of integers provide for a successive level of status code
+ granularity.
+
+ The following are initial classes for the return status code.
+ Individual iCalendar object methods will define specific return
+ status codes for these classes. In addition, other classes for the
+ return status code may be defined using the registration process
+ defined later in this memo.
+
+ |==============+===============================================|
+ | Short Return | Longer Return Status Description |
+ | Status Code | |
+ |==============+===============================================|
+ | 1.xx | Preliminary success. This class of status |
+ | | of status code indicates that the request has |
+ | | request has been initially processed but that |
+ | | completion is pending. |
+ |==============+===============================================|
+ | 2.xx | Successful. This class of status code |
+ | | indicates that the request was completed |
+ | | successfuly. However, the exact status code |
+ | | can indicate that a fallback has been taken. |
+ |==============+===============================================|
+ | 3.xx | Client Error. This class of status code |
+ | | indicates that the request was not successful.|
+ | | The error is the result of either a syntax or |
+ | | a semantic error in the client formatted |
+ | | request. Request should not be retried until |
+ | | the condition in the request is corrected. |
+ |==============+===============================================|
+ | 4.xx | Scheduling Error. This class of status code |
+ | | indicates that the request was not successful.|
+ | | Some sort of error occurred within the |
+ | | calendaring and scheduling service, not |
+ | | directly related to the request itself. |
+ |==============+===============================================|
+
+ Format Definition: The property is defined by the following notation:
+
+ rstatus = "REQUEST-STATUS" rstatparam ":"
+ statcode ";" statdesc [";" extdata]
+
+ rstatparam = *(
+
+ ; the following is optional,
+ ; but MUST NOT occur more than once
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 135]</span>
+</pre><pre class="newpage"><a name="page-136" id="page-136" href="#page-136" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ (";" languageparm) /
+
+ ; the following is optional,
+ ; and MAY occur more than once
+
+ (";" xparam)
+
+ )
+
+ statcode = 1*DIGIT *("." 1*DIGIT)
+ ;Hierarchical, numeric return status code
+
+ statdesc = text
+ ;Textual status description
+
+ extdata = text
+ ;Textual exception data. For example, the offending property
+ ;name and value or complete property line.
+
+ Example: The following are some possible examples of this property.
+ The COMMA and SEMICOLON separator characters in the property value
+ are BACKSLASH character escaped because they appear in a text value.
+
+ REQUEST-STATUS:2.0;Success
+
+ REQUEST-STATUS:3.1;Invalid property value;DTSTART:96-Apr-01
+
+ REQUEST-STATUS:2.8; Success\, repeating event ignored. Scheduled
+ as a single event.;RRULE:FREQ=WEEKLY\;INTERVAL=2
+
+ REQUEST-STATUS:4.1;Event conflict. Date/time is busy.
+
+ REQUEST-STATUS:3.7;Invalid calendar user;ATTENDEE:
+ MAILTO:jsmith@host.com
+
+<span class="h2"><h2><a name="section-5">5</a> iCalendar Object Examples</h2></span>
+
+ The following examples are provided as an informational source of
+ illustrative iCalendar objects consistent with this content type.
+
+ The following example specifies a three-day conference that begins at
+ 8:00 AM EDT, September 18, 1996 and end at 6:00 PM EDT, September 20,
+ 1996.
+
+ BEGIN:VCALENDAR PRODID:-//xyz Corp//NONSGML PDA Calendar Verson
+ 1.0//EN VERSION:2.0 BEGIN:VEVENT DTSTAMP:19960704T120000Z
+ UID:uid1@host.com ORGANIZER:MAILTO:jsmith@host.com
+ DTSTART:19960918T143000Z DTEND:19960920T220000Z STATUS:CONFIRMED
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 136]</span>
+</pre><pre class="newpage"><a name="page-137" id="page-137" href="#page-137" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ CATEGORIES:CONFERENCE SUMMARY:Networld+Interop Conference
+ DESCRIPTION:Networld+Interop Conference
+ and Exhibit\nAtlanta World Congress Center\n
+ Atlanta, Georgia END:VEVENT END:VCALENDAR
+
+ The following example specifies a group scheduled meeting that begin
+ at 8:30 AM EST on March 12, 1998 and end at 9:30 AM EST on March 12,
+ 1998. The "Organizer" has scheduled the meeting with one or more
+ calendar users in a group. A time zone specification for Eastern
+ United States has been specified.
+
+ BEGIN:VCALENDAR
+ PRODID:-//RDU Software//NONSGML HandCal//EN
+ VERSION:2.0
+ BEGIN:VTIMEZONE
+ TZID:US-Eastern
+ BEGIN:STANDARD
+ DTSTART:19981025T020000
+ RDATE:19981025T020000
+ TZOFFSETFROM:-0400
+ TZOFFSETTO:-0500
+ TZNAME:EST
+ END:STANDARD
+ BEGIN:DAYLIGHT
+ DTSTART:19990404T020000
+ RDATE:19990404T020000
+ TZOFFSETFROM:-0500
+ TZOFFSETTO:-0400
+ TZNAME:EDT
+ END:DAYLIGHT
+ END:VTIMEZONE
+ BEGIN:VEVENT
+ DTSTAMP:19980309T231000Z
+ UID:guid-1.host1.com
+ ORGANIZER;ROLE=CHAIR:MAILTO:mrbig@host.com
+ ATTENDEE;RSVP=TRUE;ROLE=REQ-PARTICIPANT;CUTYPE=GROUP:
+ MAILTO:employee-A@host.com
+ DESCRIPTION:Project XYZ Review Meeting
+ CATEGORIES:MEETING
+ CLASS:PUBLIC
+ CREATED:19980309T130000Z
+ SUMMARY:XYZ Project Review
+ DTSTART;TZID=US-Eastern:19980312T083000
+ DTEND;TZID=US-Eastern:19980312T093000
+ LOCATION:1CP Conference Room 4350
+ END:VEVENT
+ END:VCALENDAR
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 137]</span>
+</pre><pre class="newpage"><a name="page-138" id="page-138" href="#page-138" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ The following is an example of an iCalendar object passed in a MIME
+ message with a single body part consisting of a "text/calendar"
+ Content Type.
+
+ TO:jsmith@host1.com
+ FROM:jdoe@host1.com
+ MIME-VERSION:1.0
+ MESSAGE-ID:<id3@host1.com>
+ CONTENT-TYPE:text/calendar
+
+ BEGIN:VCALENDAR
+ METHOD:xyz
+ VERSION:2.0
+ PRODID:-//ABC Corporation//NONSGML My Product//EN
+ BEGIN:VEVENT
+ DTSTAMP:19970324T1200Z
+ SEQUENCE:0
+ UID:uid3@host1.com
+ ORGANIZER:MAILTO:jdoe@host1.com
+ ATTENDEE;RSVP=TRUE:MAILTO:jsmith@host1.com
+ DTSTART:19970324T123000Z
+ DTEND:19970324T210000Z
+ CATEGORIES:MEETING,PROJECT
+ CLASS:PUBLIC
+ SUMMARY:Calendaring Interoperability Planning Meeting
+ DESCRIPTION:Discuss how we can test c&s interoperability\n
+ using iCalendar and other IETF standards.
+ LOCATION:LDB Lobby
+ ATTACH;FMTTYPE=application/postscript:ftp://xyzCorp.com/pub/
+ conf/bkgrnd.ps
+ END:VEVENT
+ END:VCALENDAR
+
+ The following is an example of a to-do due on April 15, 1998. An
+ audio alarm has been specified to remind the calendar user at noon,
+ the day before the to-do is expected to be completed and repeat
+ hourly, four additional times. The to-do definition has been modified
+ twice since it was initially created.
+
+ BEGIN:VCALENDAR
+ VERSION:2.0
+ PRODID:-//ABC Corporation//NONSGML My Product//EN
+ BEGIN:VTODO
+ DTSTAMP:19980130T134500Z
+ SEQUENCE:2
+ UID:uid4@host1.com
+ ORGANIZER:MAILTO:unclesam@us.gov
+ ATTENDEE;PARTSTAT=ACCEPTED:MAILTO:jqpublic@host.com
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 138]</span>
+</pre><pre class="newpage"><a name="page-139" id="page-139" href="#page-139" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ DUE:19980415T235959
+ STATUS:NEEDS-ACTION
+ SUMMARY:Submit Income Taxes
+ BEGIN:VALARM
+ ACTION:AUDIO
+ TRIGGER:19980403T120000
+ ATTACH;FMTTYPE=audio/basic:http://host.com/pub/audio-
+ files/ssbanner.aud
+ REPEAT:4
+ DURATION:PT1H
+ END:VALARM
+ END:VTODO
+ END:VCALENDAR
+
+ The following is an example of a journal entry.
+
+ BEGIN:VCALENDAR
+ VERSION:2.0
+ PRODID:-//ABC Corporation//NONSGML My Product//EN
+ BEGIN:VJOURNAL
+ DTSTAMP:19970324T120000Z
+ UID:uid5@host1.com
+ ORGANIZER:MAILTO:jsmith@host.com
+ STATUS:DRAFT
+ CLASS:PUBLIC
+ CATEGORY:Project Report, XYZ, Weekly Meeting
+ DESCRIPTION:Project xyz Review Meeting Minutes\n
+ Agenda\n1. Review of project version 1.0 requirements.\n2.
+ Definition
+ of project processes.\n3. Review of project schedule.\n
+ Participants: John Smith, Jane Doe, Jim Dandy\n-It was
+ decided that the requirements need to be signed off by
+ product marketing.\n-Project processes were accepted.\n
+ -Project schedule needs to account for scheduled holidays
+ and employee vacation time. Check with HR for specific
+ dates.\n-New schedule will be distributed by Friday.\n-
+ Next weeks meeting is cancelled. No meeting until 3/23.
+ END:VJOURNAL
+ END:VCALENDAR
+
+ The following is an example of published busy time information. The
+ iCalendar object might be placed in the network resource
+ www.host.com/calendar/busytime/jsmith.ifb.
+
+ BEGIN:VCALENDAR
+ VERSION:2.0
+ PRODID:-//RDU Software//NONSGML HandCal//EN
+ BEGIN:VFREEBUSY
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 139]</span>
+</pre><pre class="newpage"><a name="page-140" id="page-140" href="#page-140" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ ORGANIZER:MAILTO:jsmith@host.com
+ DTSTART:19980313T141711Z
+ DTEND:19980410T141711Z
+ FREEBUSY:19980314T233000Z/19980315T003000Z
+ FREEBUSY:19980316T153000Z/19980316T163000Z
+ FREEBUSY:19980318T030000Z/19980318T040000Z
+ URL:http://www.host.com/calendar/busytime/jsmith.ifb
+ END:VFREEBUSY
+ END:VCALENDAR
+
+<span class="h2"><h2><a name="section-6">6</a> Recommended Practices</h2></span>
+
+ These recommended practices should be followed in order to assure
+ consistent handling of the following cases for an iCalendar object.
+
+ 1. Content lines longer than 75 octets SHOULD be folded.
+
+ 2. A calendar entry with a "DTSTART" property but no "DTEND"
+ property does not take up any time. It is intended to represent
+ an event that is associated with a given calendar date and time
+ of day, such as an anniversary. Since the event does not take up
+ any time, it MUST NOT be used to record busy time no matter what
+ the value for the "TRANSP" property.
+
+ 3. When the "DTSTART" and "DTEND", for "VEVENT", "VJOURNAL" and
+ "VFREEBUSY" calendar components, and "DTSTART" and "DUE", for
+ "VTODO" calendar components, have the same value data type (e.g.,
+ DATE-TIME), they SHOULD specify values in the same time format
+ (e.g., UTC time format).
+
+ 4. When the combination of the "RRULE" and "RDATE" properties on an
+ iCalendar object produces multiple instances having the same
+ start date/time, they should be collapsed to, and considered as,
+ a single instance.
+
+ 5. When a calendar user receives multiple requests for the same
+ calendar component (e.g., REQUEST for a "VEVENT" calendar
+ component) as a result of being on multiple mailing lists
+ specified by "ATTENDEE" properties in the request, they SHOULD
+ respond to only one of the requests. The calendar user SHOULD
+ also specify (using the "MEMBER" parameter of the "ATTENDEE"
+ property) which mailing list they are a member of.
+
+ 6. An implementation can truncate a "SUMMARY" property value to 255
+ characters.
+
+
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 140]</span>
+</pre><pre class="newpage"><a name="page-141" id="page-141" href="#page-141" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ 7. If seconds of the minute are not supported by an implementation,
+ then a value of "00" SHOULD be specified for the seconds
+ component in a time value.
+
+ 8. If the value type parameter (VALUE=) contains an unknown value
+ type, it SHOULD be treated as TEXT.
+
+ 9. TZURL values SHOULD NOT be specified as a FILE URI type. This URI
+ form can be useful within an organization, but is problematic in
+ the Internet.
+
+ 10. Some possible English values for CATEGORIES property include
+ "ANNIVERSARY", "APPOINTMENT", "BUSINESS", "EDUCATION",
+ "HOLIDAY", "MEETING", "MISCELLANEOUS", "NON-WORKING HOURS", "NOT
+ IN OFFICE", "PERSONAL", "PHONE CALL", "SICK DAY", "SPECIAL
+ OCCASION", "TRAVEL", "VACATION". Categories can be specified in
+ any registered language.
+
+ 11. Some possible English values for RESOURCES property include
+ "CATERING", "CHAIRS", "COMPUTER PROJECTOR", "EASEL", "OVERHEAD
+ PROJECTOR", "SPEAKER PHONE", "TABLE", "TV", "VCR", "VIDEO
+ PHONE", "VEHICLE". Resources can be specified in any registered
+ language.
+
+<span class="h2"><h2><a name="section-7">7</a> Registration of Content Type Elements</h2></span>
+
+ This section provides the process for registration of MIME
+ Calendaring and Scheduling Content Type iCalendar object methods and
+ new or modified properties.
+
+<span class="h3"><h3><a name="section-7.1">7.1</a> Registration of New and Modified iCalendar Object Methods</h3></span>
+
+ New MIME Calendaring and Scheduling Content Type iCalendar object
+ methods are registered by the publication of an IETF Request for
+ Comments (RFC). Changes to an iCalendar object method are registered
+ by the publication of a revision of the RFC defining the method.
+
+<span class="h3"><h3><a name="section-7.2">7.2</a> Registration of New Properties</h3></span>
+
+ This section defines procedures by which new properties or enumerated
+ property values for the MIME Calendaring and Scheduling Content Type
+ can be registered with the IANA. Non-IANA properties can be used by
+ bilateral agreement, provided the associated properties names follow
+ the "X-" convention.
+
+ The procedures defined here are designed to allow public comment and
+ review of new properties, while posing only a small impediment to the
+ definition of new properties.
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 141]</span>
+</pre><pre class="newpage"><a name="page-142" id="page-142" href="#page-142" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ Registration of a new property is accomplished by the following
+ steps.
+
+<span class="h4"><h4><a name="section-7.2.1">7.2.1</a> Define the property</h4></span>
+
+ A property is defined by completing the following template.
+
+ To: ietf-calendar@imc.org
+
+ Subject: Registration of text/calendar MIME property XXX
+
+ Property name:
+
+ Property purpose:
+
+ Property value type(s):
+
+ Property parameter (s):
+
+ Conformance:
+
+ Description:
+
+ Format definition:
+
+ Examples:
+
+ The meaning of each field in the template is as follows.
+
+ Property name: The name of the property, as it will appear in the
+ body of an text/calendar MIME Content-Type "property: value" line to
+ the left of the colon ":".
+
+ Property purpose: The purpose of the property (e.g., to indicate a
+ delegate for the event or to-do, etc.). Give a short but clear
+ description.
+
+ Property value type (s): Any of the valid value types for the
+ property value needs to be specified. The default value type also
+ needs to be specified. If a new value type is specified, it needs to
+ be declared in this section.
+
+ Property parameter (s): Any of the valid property parameters for the
+ property needs to be specified.
+
+ Conformance: The calendar components that the property can appear in
+ needs to be specified.
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 142]</span>
+</pre><pre class="newpage"><a name="page-143" id="page-143" href="#page-143" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ Description: Any special notes about the property, how it is to be
+ used, etc.
+
+ Format definition: The ABNF for the property definition needs to be
+ specified.
+
+ Examples: One or more examples of instances of the property needs to
+ be specified.
+
+<span class="h4"><h4><a name="section-7.2.2">7.2.2</a> Post the Property definition</h4></span>
+
+ The property description MUST be posted to the new property
+ discussion list, ietf-calendar@imc.org.
+
+<span class="h4"><h4><a name="section-7.2.3">7.2.3</a> Allow a comment period</h4></span>
+
+ Discussion on the new property MUST be allowed to take place on the
+ list for a minimum of two weeks. Consensus MUST be reached on the
+ property before proceeding to the next step.
+
+<span class="h4"><h4><a name="section-7.2.4">7.2.4</a> Submit the property for approval</h4></span>
+
+ Once the two-week comment period has elapsed, and the proposer is
+ convinced consensus has been reached on the property, the
+ registration application should be submitted to the Method Reviewer
+ for approval. The Method Reviewer is appointed to the Application
+ Area Directors and can either accept or reject the property
+ registration. An accepted registration should be passed on by the
+ Method Reviewer to the IANA for inclusion in the official IANA method
+ registry. The registration can be rejected for any of the following
+ reasons. 1) Insufficient comment period; 2) Consensus not reached; 3)
+ Technical deficiencies raised on the list or elsewhere have not been
+ addressed. The Method Reviewer's decision to reject a property can be
+ appealed by the proposer to the IESG, or the objections raised can be
+ addressed by the proposer and the property resubmitted.
+
+<span class="h3"><h3><a name="section-7.3">7.3</a> Property Change Control</h3></span>
+
+ Existing properties can be changed using the same process by which
+ they were registered.
+
+ 1. Define the change
+
+ 2. Post the change
+
+ 3. Allow a comment period
+
+ 4. Submit the property for approval
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 143]</span>
+</pre><pre class="newpage"><a name="page-144" id="page-144" href="#page-144" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ Note that the original author or any other interested party can
+ propose a change to an existing property, but that such changes
+ should only be proposed when there are serious omissions or errors in
+ the published memo. The Method Reviewer can object to a change if it
+ is not backward compatible, but is not required to do so.
+
+ Property definitions can never be deleted from the IANA registry, but
+ properties which are no longer believed to be useful can be declared
+ OBSOLETE by a change to their "intended use" field.
+
+<span class="h2"><h2><a name="section-8">8</a> References</h2></span>
+
+ [<a name="ref-IMIP" id="ref-IMIP">IMIP</a>] Dawson, F., Mansour, S. and S. Silverberg, "iCalendar
+ Message-based Interoperability Protocol (IMIP)", <a href="http://tools.ietf.org/html/rfc2447">RFC 2447</a>,
+ November 1998.
+
+ [<a name="ref-ITIP" id="ref-ITIP">ITIP</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="http://tools.ietf.org/html/rfc2446">RFC 2446</a>, November 1998.
+
+ [ISO 8601] ISO 8601, "Data elements and interchange formats-
+ Information interchange--Representation of dates and
+ times", International Organization for Standardization,
+ June, 1988.
+
+ [ISO 9070] ISO/IEC 9070, "Information Technology_SGML Support
+ Facilities--Registration Procedures for Public Text Owner
+ Identifiers", Second Edition, International Organization
+ for Standardization, April 1991.
+
+ [<a name="ref-RFC 822" id="ref-RFC 822">RFC 822</a>] Crocker, D., "Standard for the Format of ARPA Internet
+ Text Messages", STD 11, <a href="http://tools.ietf.org/html/rfc822">RFC 822</a>, August 1982.
+
+ [<a name="ref-RFC 1738" id="ref-RFC 1738">RFC 1738</a>] Berners-Lee, T., Masinter, L. and M. McCahill, "Uniform
+ Resource Locators (URL)", <a href="http://tools.ietf.org/html/rfc1738">RFC 1738</a>, December 1994.
+
+ [<a name="ref-RFC 1766" id="ref-RFC 1766">RFC 1766</a>] Alvestrand, H., "Tags for the Identification of
+ Languages", <a href="http://tools.ietf.org/html/rfc1766">RFC 1766</a>, March 1995.
+
+ [<a name="ref-RFC 2045" id="ref-RFC 2045">RFC 2045</a>] Freed, N. and N. Borenstein, " Multipurpose Internet Mail
+ Extensions (MIME) - Part One: Format of Internet Message
+ Bodies", <a href="http://tools.ietf.org/html/rfc2045">RFC 2045</a>, November 1996.
+
+ [<a name="ref-RFC 2046" id="ref-RFC 2046">RFC 2046</a>] Freed, N. and N. Borenstein, " Multipurpose Internet Mail
+ Extensions (MIME) - Part Two: Media Types", <a href="http://tools.ietf.org/html/rfc2046">RFC 2046</a>,
+ November 1996.
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 144]</span>
+</pre><pre class="newpage"><a name="page-145" id="page-145" href="#page-145" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ [<a name="ref-RFC 2048" id="ref-RFC 2048">RFC 2048</a>] Freed, N., Klensin, J. and J. Postel, "Multipurpose
+ Internet Mail Extensions (MIME) - Part Four: Registration
+ Procedures", <a href="http://tools.ietf.org/html/rfc2048">RFC 2048</a>, January 1997.
+
+ [<a name="ref-RFC 2119" id="ref-RFC 2119">RFC 2119</a>] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", <a href="http://tools.ietf.org/html/bcp14">BCP 14</a>, <a href="http://tools.ietf.org/html/rfc2119">RFC 2119</a>, March 1997.
+
+ [<a name="ref-RFC 2234" id="ref-RFC 2234">RFC 2234</a>] Crocker, D. and P. Overell, "Augmented BNF for Syntax
+ Specifications: ABNF", <a href="http://tools.ietf.org/html/rfc2234">RFC 2234</a>, November 1997.
+
+ [<a name="ref-RFC 2279" id="ref-RFC 2279">RFC 2279</a>] Yergeau, F., "UTF-8, a transformation format of ISO
+ 10646", <a href="http://tools.ietf.org/html/rfc2279">RFC 2279</a>, January 1998.
+
+ [<a name="ref-RFC 2425" id="ref-RFC 2425">RFC 2425</a>] Howes, T., Smith, M. and F. Dawson, "A MIME Content-Type
+ for Directory Information", <a href="http://tools.ietf.org/html/rfc2425">RFC 2425</a>, September 1998.
+
+ [<a name="ref-RFC 2426" id="ref-RFC 2426">RFC 2426</a>] Dawson, F. and T. Howes, "vCard MIME Directory Profile",
+ <a href="http://tools.ietf.org/html/rfc2426">RFC 2426</a>, September 1998.
+
+ [<a name="ref-TZ" id="ref-TZ">TZ</a>] Olson, A.D., et al, Time zone code and data,
+ <a href="ftp://elsie.nci.nih.gov/pub/">ftp://elsie.nci.nih.gov/pub/</a>, updated periodically.
+
+ [<a name="ref-VCAL" id="ref-VCAL">VCAL</a>] Internet Mail Consortium, "vCalendar - The Electronic
+ Calendaring and Scheduling Exchange Format",
+ <a href="http://www.imc.org/pdi/vcal-10.txt">http://www.imc.org/pdi/vcal-10.txt</a>, September 18, 1996.
+
+<span class="h2"><h2><a name="section-9">9</a> Acknowledgments</h2></span>
+
+ A hearty thanks to the IETF Calendaring and Scheduling Working Group
+ and also the following individuals who have participated in the
+ drafting, review and discussion of this memo:
+
+ Roland Alden, Harald T. Alvestrand, Eric Berman, Denis Bigorgne, John
+ Binici, Bill Bliss, Philippe Boucher, Steve Carter, Andre
+ Courtemanche, Dave Crocker, David Curley, Alec Dun, John Evans, Ross
+ Finlayson, Randell Flint, Ned Freed, Patrik Faltstrom, Chuck
+ Grandgent, Mark Handley, Steve Hanna, Paul B. Hill, Paul Hoffman,
+ Ross Hopson, Mark Horton, Daryl Huff, Bruce Kahn, C. Harald Koch,
+ Ryan Jansen, Don Lavange, Antoine Leca, Theodore Lorek, Steve
+ Mansour, Skip Montanaro, Keith Moore, Cecil Murray, Chris Newman,
+ John Noerenberg, Ralph Patterson, Pete Resnick, Keith Rhodes, Robert
+ Ripberger, John Rose, Doug Royer, Andras Salamar, Ted Schuh, Vinod
+ Seraphin, Derrick Shadel, Ken Shan, Andrew Shuman, Steve Silverberg,
+ William P. Spencer, John Sun, Mark Towfiq, Yvonne Tso, Robert Visnov,
+ James L. Weiner, Mike Weston, William Wyatt.
+
+
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 145]</span>
+</pre><pre class="newpage"><a name="page-146" id="page-146" href="#page-146" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+<span class="h2"><h2><a name="section-10">10</a> Authors' and Chairs' Addresses</h2></span>
+
+ The following address information is provided in a MIME-VCARD,
+ Electronic Business Card, format.
+
+ The authors of this memo are:
+
+ BEGIN:VCARD
+ VERSION:3.0
+ N:Dawson;Frank
+ FN:Frank Dawson
+ ORG:Lotus Development Corporation
+ ADR;TYPE=WORK,POSTAL,PARCEL:;;6544 Battleford Drive;
+ Raleigh;NC;27613-3502;USA
+ TEL;TYPE=WORK,MSG:+1-919-676-9515
+ TEL;TYPE=WORK,FAX:+1-919-676-9564
+ EMAIL;TYPE=PREF,INTERNET:Frank_Dawson@Lotus.com
+ EMAIL;TYPE=INTERNET:fdawson@earthlink.net
+ URL:http://home.earthlink.net/~fdawson
+ END:VCARD
+
+ BEGIN:VCARD
+ VERSION:3.0
+ N:Stenerson;Derik
+ FN:Derik Stenerson
+ ORG:Microsoft Corporation
+ ADR;TYPE=WORK,POSTAL,PARCEL:;;One Microsoft Way;
+ Redmond;WA;98052-6399;USA
+ TEL;TYPE=WORK,MSG:+1-425-936-5522
+ TEL;TYPE=WORK,FAX:+1-425-936-7329
+ EMAIL;TYPE=INTERNET:deriks@Microsoft.com
+ END:VCARD
+
+ The iCalendar object is a result of the work of the Internet
+ Engineering Task Force Calendaring and Scheduling Working Group. The
+ chairmen of that working group are:
+
+ BEGIN:VCARD
+ VERSION:3.0
+ N:Ganguly;Anik
+ FN:Anik Ganguly
+ ORG: Open Text Inc.
+ ADR;TYPE=WORK,POSTAL,PARCEL:;Suite 101;38777 West Six Mile Road;
+ Livonia;MI;48152;USA
+ TEL;TYPE=WORK,MSG:+1-734-542-5955
+ EMAIL;TYPE=INTERNET:ganguly@acm.org
+ END:VCARD
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 146]</span>
+</pre><pre class="newpage"><a name="page-147" id="page-147" href="#page-147" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+ The co-chairman of that working group is:
+
+ BEGIN:VCARD
+ VERSION:3.0
+ N:Moskowitz;Robert
+ FN:Robert Moskowitz
+ EMAIL;TYPE=INTERNET:rgm-ietf@htt-consult.com
+ END:VCARD
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<span class="grey">Dawson & Stenerson Standards Track [Page 147]</span>
+</pre><pre class="newpage"><a name="page-148" id="page-148" href="#page-148" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a> iCalendar November 1998</span>
+
+
+<span class="h2"><h2><a name="section-11">11</a>. Full Copyright Statement</h2></span>
+
+ Copyright (C) The Internet Society (1998). 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.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Dawson & Stenerson Standards Track [Page 148]
+</pre><pre class="newpage">
+</pre><br>
+<span class="noprint"><small><small>Html markup produced by rfcmarkup 1.74, available from
+<a href="http://tools.ietf.org/tools/rfcmarkup/">http://tools.ietf.org/tools/rfcmarkup/</a>
+</small></small></span>
+</body></html>
\ No newline at end of file
--- /dev/null
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml" lang="en"><head>
+
+
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <meta name="robots" content="index,follow">
+ <meta name="creator" content="rfcmarkup version 1.74">
+ <link rel="icon" href="http://tools.ietf.org/images/rfc.png" type="image/png">
+ <link rel="shortcut icon" href="http://tools.ietf.org/images/rfc.png" type="image/png">
+ <title>RFC 4791 - Calendaring Extensions to WebDAV (CalDAV)</title>
+
+ <style type="text/css">
+ body {
+ margin: 0px 8px;
+ font-size: 1em;
+ }
+ h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 {
+ font-weight: bold;
+ line-height: 0pt;
+ display: inline;
+ white-space: pre;
+ font-family: monospace;
+ font-size: 1em;
+ font-weight: bold;
+ }
+ pre {
+ font-size: 1em;
+ margin-top: 0px;
+ margin-bottom: 0px;
+ }
+ .pre {
+ white-space: pre;
+ font-family: monospace;
+ }
+ .header{
+ font-weight: bold;
+ }
+ .newpage {
+ page-break-before: always;
+ }
+ .invisible {
+ text-decoration: none;
+ color: white;
+ }
+ @media print {
+ body {
+ font-size: 10.5pt;
+ }
+ h1, h2, h3, h4, h5, h6 {
+ font-size: 10.5pt;
+ }
+
+ a:link, a:visited {
+ color: inherit;
+ text-decoration: none;
+ }
+ .noprint {
+ display: none;
+ }
+ }
+ @media screen {
+ .grey, .grey a:link, .grey a:visited {
+ color: #777;
+ }
+ .docinfo {
+ background-color: #EEE;
+ }
+ .top {
+ border-top: 7px solid #EEE;
+ }
+ .bgwhite { background-color: white; }
+ .bgred { background-color: #F44; }
+ .bggrey { background-color: #666; }
+ .bgbrown { background-color: #840; }
+ .bgorange { background-color: #FA0; }
+ .bgyellow { background-color: #EE0; }
+ .bgmagenta{ background-color: #F4F; }
+ .bgblue { background-color: #66F; }
+ .bgcyan { background-color: #4DD; }
+ .bggreen { background-color: #4F4; }
+
+ .legend { font-size: 90%; }
+ .cplate { font-size: 70%; border: solid grey 1px; }
+ }
+ </style>
+
+ <script type="text/javascript"><!--
+ function addHeaderTags() {
+ var spans = document.getElementsByTagName("span");
+ for (var i=0; i < spans.length; i++) {
+ var elem = spans[i];
+ if (elem) {
+ var level = elem.getAttribute("class");
+ if (level == "h1" || level == "h2" || level == "h3" || level == "h4" || level == "h5" || level == "h6") {
+ elem.innerHTML = "<"+level+">"+elem.innerHTML+"</"+level+">";
+ }
+ }
+ }
+ }
+ var legend_html = "Colour legend:<br /> <table> <tr><td>Unknown:</td> <td><span class='cplate bgwhite'> </span></td></tr> <tr><td>Draft:</td> <td><span class='cplate bgred'> </span></td></tr> <tr><td>Informational:</td> <td><span class='cplate bgorange'> </span></td></tr> <tr><td>Experimental:</td> <td><span class='cplate bgyellow'> </span></td></tr> <tr><td>Best Common Practice:</td><td><span class='cplate bgmagenta'> </span></td></tr> <tr><td>Proposed Standard:</td><td><span class='cplate bgblue'> </span></td></tr> <tr><td>Draft Standard:</td> <td><span class='cplate bgcyan'> </span></td></tr> <tr><td>Standard:</td> <td><span class='cplate bggreen'> </span></td></tr> <tr><td>Historic:</td> <td><span class='cplate bggrey'> </span></td></tr> <tr><td>Obsolete:</td> <td><span class='cplate bgbrown'> </span></td></tr> </table>";
+ function showElem(id) {
+ var elem = document.getElementById(id);
+ elem.innerHTML = eval(id+"_html");
+ elem.style.visibility='visible';
+ }
+ function hideElem(id) {
+ var elem = document.getElementById(id);
+ elem.style.visibility='hidden';
+ elem.innerHTML = "";
+ }
+ // -->
+ </script>
+</head><body onload="addHeaderTags()">
+ <div style="height: 13px;">
+ <div onmouseover="this.style.cursor='pointer';" onclick="showElem('legend');" onmouseout="hideElem('legend')" style="height: 6px; position: absolute;" class="pre noprint docinfo bgblue" title="Click for colour legend."> </div>
+ <div id="legend" class="docinfo noprint pre legend" style="border: 1px solid rgb(51, 68, 85); padding: 4px 9px 5px 7px; position: absolute; top: 4px; left: 4ex; visibility: hidden; background-color: white;" onmouseover="showElem('legend');" onmouseout="hideElem('legend');">
+ </div>
+ </div>
+<span class="pre noprint docinfo top">[<a href="http://tools.ietf.org/html/" title="Document search and retrieval page">RFCs/IDs</a>] [<a href="http://tools.ietf.org/rfc/rfc4791.txt" title="Plaintext version of this document">Plain</a>] [From <a href="http://tools.ietf.org/html/draft-dusseault-caldav">draft-dusseault-caldav</a>] </span><br>
+<span class="pre noprint docinfo"> </span><br>
+<span class="pre noprint docinfo"> PROPOSED STANDARD</span><br>
+<span class="pre noprint docinfo"> <a href="http://www.rfc-editor.org/errata_search.php?rfc=4791">Errata</a></span><br>
+<pre>Network Working Group C. Daboo
+Request for Comments: 4791 Apple
+Category: Standards Track B. Desruisseaux
+ Oracle
+ L. Dusseault
+ CommerceNet
+ March 2007
+
+
+ <span class="h1"><h1>Calendaring Extensions to WebDAV (CalDAV)</h1></span>
+
+Status of This Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The IETF Trust (2007).
+
+Abstract
+
+ This document defines extensions to the Web Distributed Authoring and
+ Versioning (WebDAV) protocol to specify a standard way of accessing,
+ managing, and sharing calendaring and scheduling information based on
+ the iCalendar format. This document defines the "calendar-access"
+ feature of CalDAV.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 1]</span>
+</pre><pre class="newpage"><a name="page-2" id="page-2" href="#page-2" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+Table of Contents
+
+ <a href="#section-1">1</a>. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . <a href="#page-5">5</a>
+ <a href="#section-1.1">1.1</a>. Notational Conventions . . . . . . . . . . . . . . . . . . <a href="#page-5">5</a>
+ <a href="#section-1.2">1.2</a>. XML Namespaces and Processing . . . . . . . . . . . . . . <a href="#page-5">5</a>
+ <a href="#section-1.3">1.3</a>. Method Preconditions and Postconditions . . . . . . . . . <a href="#page-6">6</a>
+ <a href="#section-2">2</a>. Requirements Overview . . . . . . . . . . . . . . . . . . . . <a href="#page-6">6</a>
+ <a href="#section-3">3</a>. Calendaring Data Model . . . . . . . . . . . . . . . . . . . . <a href="#page-7">7</a>
+ <a href="#section-3.1">3.1</a>. Calendar Server . . . . . . . . . . . . . . . . . . . . . <a href="#page-7">7</a>
+ <a href="#section-3.2">3.2</a>. Recurrence and the Data Model . . . . . . . . . . . . . . <a href="#page-8">8</a>
+ <a href="#section-4">4</a>. Calendar Resources . . . . . . . . . . . . . . . . . . . . . . <a href="#page-9">9</a>
+ <a href="#section-4.1">4.1</a>. Calendar Object Resources . . . . . . . . . . . . . . . . <a href="#page-9">9</a>
+ <a href="#section-4.2">4.2</a>. Calendar Collection . . . . . . . . . . . . . . . . . . . <a href="#page-10">10</a>
+ <a href="#section-5">5</a>. Calendar Access Feature . . . . . . . . . . . . . . . . . . . <a href="#page-11">11</a>
+ <a href="#section-5.1">5.1</a>. Calendar Access Support . . . . . . . . . . . . . . . . . <a href="#page-11">11</a>
+ 5.1.1. Example: Using OPTIONS for the Discovery of
+ Calendar Access Support . . . . . . . . . . . . . . . <a href="#page-12">12</a>
+ <a href="#section-5.2">5.2</a>. Calendar Collection Properties . . . . . . . . . . . . . . <a href="#page-12">12</a>
+ <a href="#section-5.2.1">5.2.1</a>. CALDAV:calendar-description Property . . . . . . . . . <a href="#page-12">12</a>
+ <a href="#section-5.2.2">5.2.2</a>. CALDAV:calendar-timezone Property . . . . . . . . . . <a href="#page-13">13</a>
+ <a href="#section-5.2.3">5.2.3</a>. CALDAV:supported-calendar-component-set Property . . . <a href="#page-14">14</a>
+ <a href="#section-5.2.4">5.2.4</a>. CALDAV:supported-calendar-data Property . . . . . . . <a href="#page-15">15</a>
+ <a href="#section-5.2.5">5.2.5</a>. CALDAV:max-resource-size Property . . . . . . . . . . <a href="#page-16">16</a>
+ <a href="#section-5.2.6">5.2.6</a>. CALDAV:min-date-time Property . . . . . . . . . . . . <a href="#page-17">17</a>
+ <a href="#section-5.2.7">5.2.7</a>. CALDAV:max-date-time Property . . . . . . . . . . . . <a href="#page-18">18</a>
+ <a href="#section-5.2.8">5.2.8</a>. CALDAV:max-instances Property . . . . . . . . . . . . <a href="#page-19">19</a>
+ <a href="#section-5.2.9">5.2.9</a>. CALDAV:max-attendees-per-instance Property . . . . . . <a href="#page-19">19</a>
+ <a href="#section-5.2.10">5.2.10</a>. Additional Precondition for PROPPATCH . . . . . . . . <a href="#page-20">20</a>
+ <a href="#section-5.3">5.3</a>. Creating Resources . . . . . . . . . . . . . . . . . . . . <a href="#page-20">20</a>
+ <a href="#section-5.3.1">5.3.1</a>. MKCALENDAR Method . . . . . . . . . . . . . . . . . . <a href="#page-20">20</a>
+ <a href="#section-5.3.1.1">5.3.1.1</a>. Status Codes . . . . . . . . . . . . . . . . . . . <a href="#page-22">22</a>
+ <a href="#section-5.3.1.2">5.3.1.2</a>. Example: Successful MKCALENDAR Request . . . . . . <a href="#page-23">23</a>
+ <a href="#section-5.3.2">5.3.2</a>. Creating Calendar Object Resources . . . . . . . . . . <a href="#page-25">25</a>
+ 5.3.2.1. Additional Preconditions for PUT, COPY, and
+ MOVE . . . . . . . . . . . . . . . . . . . . . . . <a href="#page-26">26</a>
+ 5.3.3. Non-Standard Components, Properties, and Parameters . 28
+ <a href="#section-5.3.4">5.3.4</a>. Calendar Object Resource Entity Tag . . . . . . . . . <a href="#page-28">28</a>
+ <a href="#section-6">6</a>. Calendaring Access Control . . . . . . . . . . . . . . . . . . <a href="#page-29">29</a>
+ <a href="#section-6.1">6.1</a>. Calendaring Privilege . . . . . . . . . . . . . . . . . . <a href="#page-29">29</a>
+ <a href="#section-6.1.1">6.1.1</a>. CALDAV:read-free-busy Privilege . . . . . . . . . . . <a href="#page-29">29</a>
+ <a href="#section-6.2">6.2</a>. Additional Principal Property . . . . . . . . . . . . . . <a href="#page-30">30</a>
+ <a href="#section-6.2.1">6.2.1</a>. CALDAV:calendar-home-set Property . . . . . . . . . . <a href="#page-30">30</a>
+ <a href="#section-7">7</a>. Calendaring Reports . . . . . . . . . . . . . . . . . . . . . <a href="#page-31">31</a>
+ <a href="#section-7.1">7.1</a>. REPORT Method . . . . . . . . . . . . . . . . . . . . . . <a href="#page-31">31</a>
+ <a href="#section-7.2">7.2</a>. Ordinary Collections . . . . . . . . . . . . . . . . . . . <a href="#page-31">31</a>
+ <a href="#section-7.3">7.3</a>. Date and Floating Time . . . . . . . . . . . . . . . . . . <a href="#page-32">32</a>
+ <a href="#section-7.4">7.4</a>. Time Range Filtering . . . . . . . . . . . . . . . . . . . <a href="#page-32">32</a>
+ <a href="#section-7.5">7.5</a>. Searching Text: Collations . . . . . . . . . . . . . . . . <a href="#page-33">33</a>
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 2]</span>
+</pre><pre class="newpage"><a name="page-3" id="page-3" href="#page-3" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ <a href="#section-7.5.1">7.5.1</a>. CALDAV:supported-collation-set Property . . . . . . . <a href="#page-34">34</a>
+ <a href="#section-7.6">7.6</a>. Partial Retrieval . . . . . . . . . . . . . . . . . . . . <a href="#page-34">34</a>
+ <a href="#section-7.7">7.7</a>. Non-Standard Components, Properties, and Parameters . . . <a href="#page-35">35</a>
+ <a href="#section-7.8">7.8</a>. CALDAV:calendar-query REPORT . . . . . . . . . . . . . . . <a href="#page-36">36</a>
+ <a href="#section-7.8.1">7.8.1</a>. Example: Partial Retrieval of Events by Time Range . . <a href="#page-38">38</a>
+ <a href="#section-7.8.2">7.8.2</a>. Example: Partial Retrieval of Recurring Events . . . . <a href="#page-42">42</a>
+ <a href="#section-7.8.3">7.8.3</a>. Example: Expanded Retrieval of Recurring Events . . . <a href="#page-45">45</a>
+ 7.8.4. Example: Partial Retrieval of Stored Free Busy
+ Components . . . . . . . . . . . . . . . . . . . . . . <a href="#page-48">48</a>
+ <a href="#section-7.8.5">7.8.5</a>. Example: Retrieval of To-Dos by Alarm Time Range . . . <a href="#page-50">50</a>
+ <a href="#section-7.8.6">7.8.6</a>. Example: Retrieval of Event by UID . . . . . . . . . . <a href="#page-51">51</a>
+ <a href="#section-7.8.7">7.8.7</a>. Example: Retrieval of Events by PARTSTAT . . . . . . . <a href="#page-53">53</a>
+ <a href="#section-7.8.8">7.8.8</a>. Example: Retrieval of Events Only . . . . . . . . . . <a href="#page-55">55</a>
+ <a href="#section-7.8.9">7.8.9</a>. Example: Retrieval of All Pending To-Dos . . . . . . . <a href="#page-59">59</a>
+ <a href="#section-7.8.10">7.8.10</a>. Example: Attempt to Query Unsupported Property . . . . <a href="#page-62">62</a>
+ <a href="#section-7.9">7.9</a>. CALDAV:calendar-multiget REPORT . . . . . . . . . . . . . <a href="#page-63">63</a>
+ 7.9.1. Example: Successful CALDAV:calendar-multiget REPORT . 64
+ <a href="#section-7.10">7.10</a>. CALDAV:free-busy-query REPORT . . . . . . . . . . . . . . <a href="#page-66">66</a>
+ <a href="#section-7.10.1">7.10.1</a>. Example: Successful CALDAV:free-busy-query REPORT . . <a href="#page-68">68</a>
+ <a href="#section-8">8</a>. Guidelines . . . . . . . . . . . . . . . . . . . . . . . . . . <a href="#page-69">69</a>
+ <a href="#section-8.1">8.1</a>. Client-to-Client Interoperability . . . . . . . . . . . . <a href="#page-69">69</a>
+ <a href="#section-8.2">8.2</a>. Synchronization Operations . . . . . . . . . . . . . . . . <a href="#page-69">69</a>
+ <a href="#section-8.2.1">8.2.1</a>. Use of Reports . . . . . . . . . . . . . . . . . . . . <a href="#page-69">69</a>
+ <a href="#section-8.2.1.1">8.2.1.1</a>. Restrict the Time Range . . . . . . . . . . . . . <a href="#page-69">69</a>
+ <a href="#section-8.2.1.2">8.2.1.2</a>. Synchronize by Time Range . . . . . . . . . . . . <a href="#page-70">70</a>
+ <a href="#section-8.2.1.3">8.2.1.3</a>. Synchronization Process . . . . . . . . . . . . . <a href="#page-70">70</a>
+ <a href="#section-8.2.2">8.2.2</a>. Restrict the Properties Returned . . . . . . . . . . . <a href="#page-72">72</a>
+ <a href="#section-8.3">8.3</a>. Use of Locking . . . . . . . . . . . . . . . . . . . . . . <a href="#page-72">72</a>
+ <a href="#section-8.4">8.4</a>. Finding Calendars . . . . . . . . . . . . . . . . . . . . <a href="#page-72">72</a>
+ <a href="#section-8.5">8.5</a>. Storing and Using Attachments . . . . . . . . . . . . . . <a href="#page-74">74</a>
+ <a href="#section-8.5.1">8.5.1</a>. Inline Attachments . . . . . . . . . . . . . . . . . . <a href="#page-74">74</a>
+ <a href="#section-8.5.2">8.5.2</a>. External Attachments . . . . . . . . . . . . . . . . . <a href="#page-75">75</a>
+ <a href="#section-8.6">8.6</a>. Storing and Using Alarms . . . . . . . . . . . . . . . . . <a href="#page-76">76</a>
+ <a href="#section-9">9</a>. XML Element Definitions . . . . . . . . . . . . . . . . . . . <a href="#page-77">77</a>
+ <a href="#section-9.1">9.1</a>. CALDAV:calendar XML Element . . . . . . . . . . . . . . . <a href="#page-77">77</a>
+ <a href="#section-9.2">9.2</a>. CALDAV:mkcalendar XML Element . . . . . . . . . . . . . . <a href="#page-77">77</a>
+ <a href="#section-9.3">9.3</a>. CALDAV:mkcalendar-response XML Element . . . . . . . . . . <a href="#page-78">78</a>
+ <a href="#section-9.4">9.4</a>. CALDAV:supported-collation XML Element . . . . . . . . . . <a href="#page-78">78</a>
+ <a href="#section-9.5">9.5</a>. CALDAV:calendar-query XML Element . . . . . . . . . . . . <a href="#page-78">78</a>
+ <a href="#section-9.6">9.6</a>. CALDAV:calendar-data XML Element . . . . . . . . . . . . . <a href="#page-79">79</a>
+ <a href="#section-9.6.1">9.6.1</a>. CALDAV:comp XML Element . . . . . . . . . . . . . . . <a href="#page-80">80</a>
+ <a href="#section-9.6.2">9.6.2</a>. CALDAV:allcomp XML Element . . . . . . . . . . . . . . <a href="#page-81">81</a>
+ <a href="#section-9.6.3">9.6.3</a>. CALDAV:allprop XML Element . . . . . . . . . . . . . . <a href="#page-81">81</a>
+ <a href="#section-9.6.4">9.6.4</a>. CALDAV:prop XML Element . . . . . . . . . . . . . . . <a href="#page-82">82</a>
+ <a href="#section-9.6.5">9.6.5</a>. CALDAV:expand XML Element . . . . . . . . . . . . . . <a href="#page-82">82</a>
+ <a href="#section-9.6.6">9.6.6</a>. CALDAV:limit-recurrence-set XML Element . . . . . . . <a href="#page-83">83</a>
+ <a href="#section-9.6.7">9.6.7</a>. CALDAV:limit-freebusy-set XML Element . . . . . . . . <a href="#page-84">84</a>
+ <a href="#section-9.7">9.7</a>. CALDAV:filter XML Element . . . . . . . . . . . . . . . . <a href="#page-85">85</a>
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 3]</span>
+</pre><pre class="newpage"><a name="page-4" id="page-4" href="#page-4" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ <a href="#section-9.7.1">9.7.1</a>. CALDAV:comp-filter XML Element . . . . . . . . . . . . <a href="#page-85">85</a>
+ <a href="#section-9.7.2">9.7.2</a>. CALDAV:prop-filter XML Element . . . . . . . . . . . . <a href="#page-86">86</a>
+ <a href="#section-9.7.3">9.7.3</a>. CALDAV:param-filter XML Element . . . . . . . . . . . <a href="#page-87">87</a>
+ <a href="#section-9.7.4">9.7.4</a>. CALDAV:is-not-defined XML Element . . . . . . . . . . <a href="#page-88">88</a>
+ <a href="#section-9.7.5">9.7.5</a>. CALDAV:text-match XML Element . . . . . . . . . . . . <a href="#page-88">88</a>
+ <a href="#section-9.8">9.8</a>. CALDAV:timezone XML Element . . . . . . . . . . . . . . . <a href="#page-89">89</a>
+ <a href="#section-9.9">9.9</a>. CALDAV:time-range XML Element . . . . . . . . . . . . . . <a href="#page-90">90</a>
+ <a href="#section-9.10">9.10</a>. CALDAV:calendar-multiget XML Element . . . . . . . . . . . <a href="#page-94">94</a>
+ <a href="#section-9.11">9.11</a>. CALDAV:free-busy-query XML Element . . . . . . . . . . . . <a href="#page-95">95</a>
+ <a href="#section-10">10</a>. Internationalization Considerations . . . . . . . . . . . . . <a href="#page-95">95</a>
+ <a href="#section-11">11</a>. Security Considerations . . . . . . . . . . . . . . . . . . . <a href="#page-95">95</a>
+ <a href="#section-12">12</a>. IANA Considerations . . . . . . . . . . . . . . . . . . . . . <a href="#page-96">96</a>
+ <a href="#section-12.1">12.1</a>. Namespace Registration . . . . . . . . . . . . . . . . . . <a href="#page-96">96</a>
+ <a href="#section-13">13</a>. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . <a href="#page-96">96</a>
+ <a href="#section-14">14</a>. References . . . . . . . . . . . . . . . . . . . . . . . . . . <a href="#page-97">97</a>
+ <a href="#section-14.1">14.1</a>. Normative References . . . . . . . . . . . . . . . . . . . <a href="#page-97">97</a>
+ <a href="#section-14.2">14.2</a>. Informative References . . . . . . . . . . . . . . . . . . <a href="#page-98">98</a>
+ <a href="#appendix-A">Appendix A</a>. CalDAV Method Privilege Table (Normative) . . . . . . <a href="#page-99">99</a>
+ <a href="#appendix-B">Appendix B</a>. Calendar Collections Used in the Examples . . . . . . <a href="#page-99">99</a>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 4]</span>
+</pre><pre class="newpage"><a name="page-5" id="page-5" href="#page-5" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+<span class="h2"><h2><a name="section-1">1</a>. Introduction</h2></span>
+
+ The concept of using HTTP [<a href="http://tools.ietf.org/html/rfc2616" title=""Hypertext Transfer Protocol -- HTTP/1.1"">RFC2616</a>] and WebDAV [<a href="http://tools.ietf.org/html/rfc2518" title=""HTTP Extensions for Distributed Authoring -- WEBDAV"">RFC2518</a>] as a basis
+ for a calendar access protocol is by no means a new concept: it was
+ discussed in the IETF CALSCH working group as early as 1997 or 1998.
+ Several companies have implemented calendar access protocols using
+ HTTP to upload and download iCalendar [<a href="http://tools.ietf.org/html/rfc2445" title=""Internet Calendaring and Scheduling Core Object Specification (iCalendar)"">RFC2445</a>] objects, and using
+ WebDAV to get listings of resources. However, those implementations
+ do not interoperate because there are many small and big decisions to
+ be made in how to model calendaring data as WebDAV resources, as well
+ as how to implement required features that aren't already part of
+ WebDAV. This document proposes a way to model calendar data in
+ WebDAV, with additional features to make an interoperable calendar
+ access protocol.
+
+<span class="h3"><h3><a name="section-1.1">1.1</a>. Notational Conventions</h3></span>
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+ document are to be interpreted as described in [<a href="http://tools.ietf.org/html/rfc2119" title=""Key words for use in RFCs to Indicate Requirement Levels"">RFC2119</a>].
+
+ The term "protected" is used in the Conformance field of property
+ definitions as defined in <a href="http://tools.ietf.org/html/rfc3253#section-1.4.2">Section 1.4.2 of [RFC3253]</a>.
+
+ When XML element types in the namespaces "DAV:" and
+ "urn:ietf:params:xml:ns:caldav" are referenced in this document
+ outside of the context of an XML fragment, the string "DAV:" and
+ "CALDAV:" will be prefixed to the element type names, respectively.
+
+<span class="h3"><h3><a name="section-1.2">1.2</a>. XML Namespaces and Processing</h3></span>
+
+ Definitions of XML elements in this document use XML element type
+ declarations (as found in XML Document Type Declarations), described
+ in <a href="#section-3.2">Section 3.2</a> of [<a href="#ref-W3C.REC-xml-20060816" title=""Extensible Markup Language (XML) 1.0 (Fourth Edition)"">W3C.REC-xml-20060816</a>].
+
+ The namespace "urn:ietf:params:xml:ns:caldav" is reserved for the XML
+ elements defined in this specification, its revisions, and related
+ CalDAV specifications. XML elements defined by individual
+ implementations MUST NOT use the "urn:ietf:params:xml:ns:caldav"
+ namespace, and instead should use a namespace that they control.
+
+ The XML declarations used in this document do not include namespace
+ information. Thus, implementers must not use these declarations as
+ the only way to create valid CalDAV properties or to validate CalDAV
+ XML element types. Some of the declarations refer to XML elements
+ defined by WebDAV [<a href="http://tools.ietf.org/html/rfc2518" title=""HTTP Extensions for Distributed Authoring -- WEBDAV"">RFC2518</a>], which use the "DAV:" namespace.
+ Wherever such XML elements appear, they are explicitly prefixed with
+ "DAV:" to avoid confusion.
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 5]</span>
+</pre><pre class="newpage"><a name="page-6" id="page-6" href="#page-6" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ Also note that some CalDAV XML element names are identical to WebDAV
+ XML element names, though their namespace differs. Care must be
+ taken not to confuse the two sets of names.
+
+ Processing of XML by CalDAV clients and servers MUST follow the rules
+ described in [<a href="http://tools.ietf.org/html/rfc2518" title=""HTTP Extensions for Distributed Authoring -- WEBDAV"">RFC2518</a>]; in particular, <a href="#section-14">Section 14</a>, and Appendix 3 of
+ that specification.
+
+<span class="h3"><h3><a name="section-1.3">1.3</a>. Method Preconditions and Postconditions</h3></span>
+
+ A "precondition" of a method describes the state of the server that
+ must be true for that method to be performed. A "postcondition" of a
+ method describes the state of the server that must be true after that
+ method has been completed. If a method precondition or postcondition
+ for a request is not satisfied, the response status of the request
+ MUST either be 403 (Forbidden), if the request should not be repeated
+ because it will always fail, or 409 (Conflict), if it is expected
+ that the user might be able to resolve the conflict and resubmit the
+ request.
+
+ In order to allow better client handling of 403 and 409 responses, a
+ distinct XML element type is associated with each method precondition
+ and postcondition of a request. When a particular precondition is
+ not satisfied or a particular postcondition cannot be achieved, the
+ appropriate XML element MUST be returned as the child of a top-level
+ DAV:error element in the response body, unless otherwise negotiated
+ by the request.
+
+<span class="h2"><h2><a name="section-2">2</a>. Requirements Overview</h2></span>
+
+ This section lists what functionality is required of a CalDAV server.
+ To advertise support for CalDAV, a server:
+
+ o MUST support iCalendar [<a href="http://tools.ietf.org/html/rfc2445" title=""Internet Calendaring and Scheduling Core Object Specification (iCalendar)"">RFC2445</a>] as a media type for the calendar
+ object resource format;
+
+ o MUST support WebDAV Class 1 [<a href="http://tools.ietf.org/html/rfc2518" title=""HTTP Extensions for Distributed Authoring -- WEBDAV"">RFC2518</a>] (note that [<a href="#ref-rfc2518bis" title=""HTTP Extensions for Distributed Authoring - WebDAV"">rfc2518bis</a>]
+ describes clarifications to [<a href="http://tools.ietf.org/html/rfc2518" title=""HTTP Extensions for Distributed Authoring -- WEBDAV"">RFC2518</a>] that aid interoperability);
+
+ o MUST support WebDAV ACL [<a href="http://tools.ietf.org/html/rfc3744" title=""Web Distributed Authoring and Versioning (WebDAV) Access Control Protocol"">RFC3744</a>] with the additional privilege
+ defined in <a href="#section-6.1">Section 6.1</a> of this document;
+
+ o MUST support transport over TLS [<a href="http://tools.ietf.org/html/rfc2246" title=""The TLS Protocol Version 1.0"">RFC2246</a>] as defined in [<a href="http://tools.ietf.org/html/rfc2818" title=""HTTP Over TLS"">RFC2818</a>]
+ (note that [<a href="http://tools.ietf.org/html/rfc2246" title=""The TLS Protocol Version 1.0"">RFC2246</a>] has been obsoleted by [<a href="http://tools.ietf.org/html/rfc4346" title=""The Transport Layer Security (TLS) Protocol Version 1.1"">RFC4346</a>]);
+
+ o MUST support ETags [<a href="http://tools.ietf.org/html/rfc2616" title=""Hypertext Transfer Protocol -- HTTP/1.1"">RFC2616</a>] with additional requirements
+ specified in <a href="#section-5.3.4">Section 5.3.4</a> of this document;
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 6]</span>
+</pre><pre class="newpage"><a name="page-7" id="page-7" href="#page-7" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ o MUST support all calendaring reports defined in <a href="#section-7">Section 7</a> of this
+ document; and
+
+ o MUST advertise support on all calendar collections and calendar
+ object resources for the calendaring reports in the DAV:supported-
+ report-set property, as defined in Versioning Extensions to WebDAV
+ [<a href="http://tools.ietf.org/html/rfc3253" title=""Versioning Extensions to WebDAV (Web Distributed Authoring and Versioning)"">RFC3253</a>].
+
+ In addition, a server:
+
+ o SHOULD support the MKCALENDAR method defined in <a href="#section-5.3.1">Section 5.3.1</a> of
+ this document.
+
+<span class="h2"><h2><a name="section-3">3</a>. Calendaring Data Model</h2></span>
+
+ One of the features that has made WebDAV a successful protocol is its
+ firm data model. This makes it a useful framework for other
+ applications such as calendaring. This specification follows the
+ same pattern by developing all features based on a well-described
+ data model.
+
+ As a brief overview, a CalDAV calendar is modeled as a WebDAV
+ collection with a defined structure; each calendar collection
+ contains a number of resources representing calendar objects as its
+ direct child resource. Each resource representing a calendar object
+ (event, to-do, journal entry, or other calendar components) is called
+ a "calendar object resource". Each calendar object resource and each
+ calendar collection can be individually locked and have individual
+ WebDAV properties. Requirements derived from this model are provided
+ in <a href="#section-4.1">Section 4.1</a> and <a href="#section-4.2">Section 4.2</a>.
+
+<span class="h3"><h3><a name="section-3.1">3.1</a>. Calendar Server</h3></span>
+
+ A CalDAV server is a calendaring-aware engine combined with a WebDAV
+ repository. A WebDAV repository is a set of WebDAV collections,
+ containing other WebDAV resources, within a unified URL namespace.
+ For example, the repository "http://www.example.com/webdav/" may
+ contain WebDAV collections and resources, all of which have URLs
+ beginning with "http://www.example.com/webdav/". Note that the root
+ URL, "http://www.example.com/", may not itself be a WebDAV repository
+ (for example, if the WebDAV support is implemented through a servlet
+ or other Web server extension).
+
+ A WebDAV repository MAY include calendar data in some parts of its
+ URL namespace, and non-calendaring data in other parts.
+
+ A WebDAV repository can advertise itself as a CalDAV server if it
+ supports the functionality defined in this specification at any point
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 7]</span>
+</pre><pre class="newpage"><a name="page-8" id="page-8" href="#page-8" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ within the root of the repository. That might mean that calendaring
+ data is spread throughout the repository and mixed with non-calendar
+ data in nearby collections (e.g., calendar data may be found in
+ /home/lisa/calendars/ as well as in /home/bernard/calendars/, and
+ non-calendar data in /home/lisa/contacts/). Or, it might mean that
+ calendar data can be found only in certain sections of the repository
+ (e.g., /calendar/). Calendaring features are only required in the
+ repository sections that are or contain calendar object resources.
+ Therefore, a repository confining calendar data to the /calendar/
+ collection would only need to support the CalDAV required features
+ within that collection.
+
+ The CalDAV server or repository is the canonical location for
+ calendar data and state information. Clients may submit requests to
+ change data or download data. Clients may store calendar objects
+ offline and attempt to synchronize at a later time. However, clients
+ MUST be prepared for calendar data on the server to change between
+ the time of last synchronization and when attempting an update, as
+ calendar collections may be shared and accessible via multiple
+ clients. Entity tags and other features make this possible.
+
+<span class="h3"><h3><a name="section-3.2">3.2</a>. Recurrence and the Data Model</h3></span>
+
+ Recurrence is an important part of the data model because it governs
+ how many resources are expected to exist. This specification models
+ a recurring calendar component and its recurrence exceptions as a
+ single resource. In this model, recurrence rules, recurrence dates,
+ exception rules, and exception dates are all part of the data in a
+ single calendar object resource. This model avoids problems of
+ limiting how many recurrence instances to store in the repository,
+ how to keep recurrence instances in sync with the recurring calendar
+ component, and how to link recurrence exceptions with the recurring
+ calendar component. It also results in less data to synchronize
+ between client and server, and makes it easier to make changes to all
+ recurrence instances or to a recurrence rule. It makes it easier to
+ create a recurring calendar component and to delete all recurrence
+ instances.
+
+ Clients are not forced to retrieve information about all recurrence
+ instances of a recurring component. The CALDAV:calendar-query and
+ CALDAV:calendar-multiget reports defined in this document allow
+ clients to retrieve only recurrence instances that overlap a given
+ time range.
+
+
+
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 8]</span>
+</pre><pre class="newpage"><a name="page-9" id="page-9" href="#page-9" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+<span class="h2"><h2><a name="section-4">4</a>. Calendar Resources</h2></span>
+
+<span class="h3"><h3><a name="section-4.1">4.1</a>. Calendar Object Resources</h3></span>
+
+ Calendar object resources contained in calendar collections MUST NOT
+ contain more than one type of calendar component (e.g., VEVENT,
+ VTODO, VJOURNAL, VFREEBUSY, etc.) with the exception of VTIMEZONE
+ components, which MUST be specified for each unique TZID parameter
+ value specified in the iCalendar object. For instance, a calendar
+ object resource can contain one VEVENT component and one VTIMEZONE
+ component, but it cannot contain one VEVENT component and one VTODO
+ component. Instead, the VEVENT and VTODO components would have to be
+ stored in separate calendar object resources in the same collection.
+
+ Calendar object resources contained in calendar collections MUST NOT
+ specify the iCalendar METHOD property.
+
+ The UID property value of the calendar components contained in a
+ calendar object resource MUST be unique in the scope of the calendar
+ collection in which they are stored.
+
+ Calendar components in a calendar collection that have different UID
+ property values MUST be stored in separate calendar object resources.
+
+ Calendar components with the same UID property value, in a given
+ calendar collection, MUST be contained in the same calendar object
+ resource. This ensures that all components in a recurrence "set" are
+ contained in the same calendar object resource. It is possible for a
+ calendar object resource to just contain components that represent
+ "overridden" instances (ones that modify the behavior of a regular
+ instance, and thus include a RECURRENCE-ID property) without also
+ including the "master" recurring component (the one that defines the
+ recurrence "set" and does not contain any RECURRENCE-ID property).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 9]</span>
+</pre><pre class="newpage"><a name="page-10" id="page-10" href="#page-10" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ For example, given the following iCalendar object:
+
+ BEGIN:VCALENDAR
+ PRODID:-//Example Corp.//CalDAV Client//EN
+ VERSION:2.0
+ BEGIN:VEVENT
+ UID:1@example.com
+ SUMMARY:One-off Meeting
+ DTSTAMP:20041210T183904Z
+ DTSTART:20041207T120000Z
+ DTEND:20041207T130000Z
+ END:VEVENT
+ BEGIN:VEVENT
+ UID:2@example.com
+ SUMMARY:Weekly Meeting
+ DTSTAMP:20041210T183838Z
+ DTSTART:20041206T120000Z
+ DTEND:20041206T130000Z
+ RRULE:FREQ=WEEKLY
+ END:VEVENT
+ BEGIN:VEVENT
+ UID:2@example.com
+ SUMMARY:Weekly Meeting
+ RECURRENCE-ID:20041213T120000Z
+ DTSTAMP:20041210T183838Z
+ DTSTART:20041213T130000Z
+ DTEND:20041213T140000Z
+ END:VEVENT
+ END:VCALENDAR
+
+ The VEVENT component with the UID value "1@example.com" would be
+ stored in its own calendar object resource. The two VEVENT
+ components with the UID value "2@example.com", which represent a
+ recurring event where one recurrence instance has been overridden,
+ would be stored in the same calendar object resource.
+
+<span class="h3"><h3><a name="section-4.2">4.2</a>. Calendar Collection</h3></span>
+
+ A calendar collection contains calendar object resources that
+ represent calendar components within a calendar. A calendar
+ collection is manifested to clients as a WebDAV resource collection
+ identified by a URL. A calendar collection MUST report the DAV:
+ collection and CALDAV:calendar XML elements in the value of the DAV:
+ resourcetype property. The element type declaration for CALDAV:
+ calendar is:
+
+ <!ELEMENT calendar EMPTY>
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 10]</span>
+</pre><pre class="newpage"><a name="page-11" id="page-11" href="#page-11" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ A calendar collection can be created through provisioning (i.e.,
+ automatically created when a user's account is provisioned), or it
+ can be created with the MKCALENDAR method (see <a href="#section-5.3.1">Section 5.3.1</a>). This
+ method can be useful for a user to create additional calendars (e.g.,
+ soccer schedule) or for users to share a calendar (e.g., team events
+ or conference rooms). However, note that this document doesn't
+ define the purpose of extra calendar collections. Users must rely on
+ non-standard cues to find out what a calendar collection is for, or
+ use the CALDAV:calendar-description property defined in <a href="#section-5.2.1">Section 5.2.1</a>
+ to provide such a cue.
+
+ The following restrictions are applied to the resources within a
+ calendar collection:
+
+ a. Calendar collections MUST only contain calendar object resources
+ and collections that are not calendar collections, i.e., the only
+ "top-level" non-collection resources allowed in a calendar
+ collection are calendar object resources. This ensures that
+ calendar clients do not have to deal with non-calendar data in a
+ calendar collection, though they do have to distinguish between
+ calendar object resources and collections when using standard
+ WebDAV techniques to examine the contents of a collection.
+
+ b. Collections contained in calendar collections MUST NOT contain
+ calendar collections at any depth, i.e., "nesting" of calendar
+ collections within other calendar collections at any depth is not
+ allowed. This specification does not define how collections
+ contained in a calendar collection are used or how they relate to
+ any calendar object resources contained in the calendar
+ collection.
+
+ Multiple calendar collections MAY be children of the same collection.
+
+<span class="h2"><h2><a name="section-5">5</a>. Calendar Access Feature</h2></span>
+
+<span class="h3"><h3><a name="section-5.1">5.1</a>. Calendar Access Support</h3></span>
+
+ A server supporting the features described in this document MUST
+ include "calendar-access" as a field in the DAV response header from
+ an OPTIONS request on any resource that supports any calendar
+ properties, reports, method, or privilege. A value of "calendar-
+ access" in the DAV response header MUST indicate that the server
+ supports all MUST level requirements specified in this document.
+
+
+
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 11]</span>
+</pre><pre class="newpage"><a name="page-12" id="page-12" href="#page-12" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+<span class="h4"><h4><a name="section-5.1.1">5.1.1</a>. Example: Using OPTIONS for the Discovery of Calendar Access</h4></span>
+ Support
+
+ >> Request <<
+
+ OPTIONS /home/bernard/calendars/ HTTP/1.1
+ Host: cal.example.com
+
+ >> Response <<
+
+ HTTP/1.1 200 OK
+ Allow: OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, COPY, MOVE
+ Allow: PROPFIND, PROPPATCH, LOCK, UNLOCK, REPORT, ACL
+ DAV: 1, 2, access-control, calendar-access
+ Date: Sat, 11 Nov 2006 09:32:12 GMT
+ Content-Length: 0
+
+ In this example, the OPTIONS method returns the value "calendar-
+ access" in the DAV response header to indicate that the collection
+ "/home/bernard/calendars/" supports the properties, reports, method,
+ or privilege defined in this specification.
+
+<span class="h3"><h3><a name="section-5.2">5.2</a>. Calendar Collection Properties</h3></span>
+
+ This section defines properties for calendar collections.
+
+<span class="h4"><h4><a name="section-5.2.1">5.2.1</a>. CALDAV:calendar-description Property</h4></span>
+
+ Name: calendar-description
+
+ Namespace: urn:ietf:params:xml:ns:caldav
+
+ Purpose: Provides a human-readable description of the calendar
+ collection.
+
+ Conformance: This property MAY be defined on any calendar
+ collection. If defined, it MAY be protected and SHOULD NOT be
+ returned by a PROPFIND DAV:allprop request (as defined in Section
+ 12.14.1 of [<a href="http://tools.ietf.org/html/rfc2518" title=""HTTP Extensions for Distributed Authoring -- WEBDAV"">RFC2518</a>]). An xml:lang attribute indicating the human
+ language of the description SHOULD be set for this property by
+ clients or through server provisioning. Servers MUST return any
+ xml:lang attribute if set for the property.
+
+ Description: If present, the property contains a description of the
+ calendar collection that is suitable for presentation to a user.
+ If not present, the client should assume no description for the
+ calendar collection.
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 12]</span>
+</pre><pre class="newpage"><a name="page-13" id="page-13" href="#page-13" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ Definition:
+
+ <!ELEMENT calendar-description (#PCDATA)>
+ PCDATA value: string
+
+ Example:
+
+ <C:calendar-description xml:lang="fr-CA"
+ xmlns:C="urn:ietf:params:xml:ns:caldav"
+ >Calendrier de Mathilde Desruisseaux</C:calendar-description>
+
+<span class="h4"><h4><a name="section-5.2.2">5.2.2</a>. CALDAV:calendar-timezone Property</h4></span>
+
+ Name: calendar-timezone
+
+ Namespace: urn:ietf:params:xml:ns:caldav
+
+ Purpose: Specifies a time zone on a calendar collection.
+
+ Conformance: This property SHOULD be defined on all calendar
+ collections. If defined, it SHOULD NOT be returned by a PROPFIND
+ DAV:allprop request (as defined in <a href="http://tools.ietf.org/html/rfc2518#section-12.14.1">Section 12.14.1 of [RFC2518]</a>).
+
+ Description: The CALDAV:calendar-timezone property is used to
+ specify the time zone the server should rely on to resolve "date"
+ values and "date with local time" values (i.e., floating time) to
+ "date with UTC time" values. The server will require this
+ information to determine if a calendar component scheduled with
+ "date" values or "date with local time" values overlaps a CALDAV:
+ time-range specified in a CALDAV:calendar-query REPORT. The
+ server will also require this information to compute the proper
+ FREEBUSY time period as "date with UTC time" in the VFREEBUSY
+ component returned in a response to a CALDAV:free-busy-query
+ REPORT request that takes into account calendar components
+ scheduled with "date" values or "date with local time" values. In
+ the absence of this property, the server MAY rely on the time zone
+ of their choice.
+
+ Note: The iCalendar data embedded within the CALDAV:calendar-
+ timezone XML element MUST follow the standard XML character data
+ encoding rules, including use of &lt;, &gt;, &amp; etc. entity
+ encoding or the use of a <![CDATA[ ... ]]> construct. In the
+ later case, the iCalendar data cannot contain the character
+ sequence "]]>", which is the end delimiter for the CDATA section.
+
+
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 13]</span>
+</pre><pre class="newpage"><a name="page-14" id="page-14" href="#page-14" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ Definition:
+
+ <!ELEMENT calendar-timezone (#PCDATA)>
+ PCDATA value: an iCalendar object with exactly one VTIMEZONE
+ component.
+
+ Example:
+
+ <C:calendar-timezone
+ xmlns:C="urn:ietf:params:xml:ns:caldav">BEGIN:VCALENDAR
+ PRODID:-//Example Corp.//CalDAV Client//EN
+ VERSION:2.0
+ BEGIN:VTIMEZONE
+ TZID:US-Eastern
+ LAST-MODIFIED:19870101T000000Z
+ BEGIN:STANDARD
+ DTSTART:19671029T020000
+ RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+ TZOFFSETFROM:-0400
+ TZOFFSETTO:-0500
+ TZNAME:Eastern Standard Time (US &amp; Canada)
+ END:STANDARD
+ BEGIN:DAYLIGHT
+ DTSTART:19870405T020000
+ RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+ TZOFFSETFROM:-0500
+ TZOFFSETTO:-0400
+ TZNAME:Eastern Daylight Time (US &amp; Canada)
+ END:DAYLIGHT
+ END:VTIMEZONE
+ END:VCALENDAR
+ </C:calendar-timezone>
+
+<span class="h4"><h4><a name="section-5.2.3">5.2.3</a>. CALDAV:supported-calendar-component-set Property</h4></span>
+
+ Name: supported-calendar-component-set
+
+ Namespace: urn:ietf:params:xml:ns:caldav
+
+ Purpose: Specifies the calendar component types (e.g., VEVENT,
+ VTODO, etc.) that calendar object resources can contain in the
+ calendar collection.
+
+ Conformance: This property MAY be defined on any calendar
+ collection. If defined, it MUST be protected and SHOULD NOT be
+ returned by a PROPFIND DAV:allprop request (as defined in Section
+ 12.14.1 of [<a href="http://tools.ietf.org/html/rfc2518" title=""HTTP Extensions for Distributed Authoring -- WEBDAV"">RFC2518</a>]).
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 14]</span>
+</pre><pre class="newpage"><a name="page-15" id="page-15" href="#page-15" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ Description: The CALDAV:supported-calendar-component-set property is
+ used to specify restrictions on the calendar component types that
+ calendar object resources may contain in a calendar collection.
+ Any attempt by the client to store calendar object resources with
+ component types not listed in this property, if it exists, MUST
+ result in an error, with the CALDAV:supported-calendar-component
+ precondition (<a href="#section-5.3.2.1">Section 5.3.2.1</a>) being violated. Since this
+ property is protected, it cannot be changed by clients using a
+ PROPPATCH request. However, clients can initialize the value of
+ this property when creating a new calendar collection with
+ MKCALENDAR. The empty-element tag <C:comp name="VTIMEZONE"/> MUST
+ only be specified if support for calendar object resources that
+ only contain VTIMEZONE components is provided or desired. Support
+ for VTIMEZONE components in calendar object resources that contain
+ VEVENT or VTODO components is always assumed. In the absence of
+ this property, the server MUST accept all component types, and the
+ client can assume that all component types are accepted.
+
+ Definition:
+
+ <!ELEMENT supported-calendar-component-set (comp+)>
+
+ Example:
+
+ <C:supported-calendar-component-set
+ xmlns:C="urn:ietf:params:xml:ns:caldav">
+ <C:comp name="VEVENT"/>
+ <C:comp name="VTODO"/>
+ </C:supported-calendar-component-set>
+
+<span class="h4"><h4><a name="section-5.2.4">5.2.4</a>. CALDAV:supported-calendar-data Property</h4></span>
+
+ Name: supported-calendar-data
+
+ Namespace: urn:ietf:params:xml:ns:caldav
+
+ Purpose: Specifies what media types are allowed for calendar object
+ resources in a calendar collection.
+
+ Conformance: This property MAY be defined on any calendar
+ collection. If defined, it MUST be protected and SHOULD NOT be
+ returned by a PROPFIND DAV:allprop request (as defined in Section
+ 12.14.1 of [<a href="http://tools.ietf.org/html/rfc2518" title=""HTTP Extensions for Distributed Authoring -- WEBDAV"">RFC2518</a>]).
+
+ Description: The CALDAV:supported-calendar-data property is used to
+ specify the media type supported for the calendar object resources
+ contained in a given calendar collection (e.g., iCalendar version
+ 2.0). Any attempt by the client to store calendar object
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 15]</span>
+</pre><pre class="newpage"><a name="page-16" id="page-16" href="#page-16" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ resources with a media type not listed in this property MUST
+ result in an error, with the CALDAV:supported-calendar-data
+ precondition (<a href="#section-5.3.2.1">Section 5.3.2.1</a>) being violated. In the absence of
+ this property, the server MUST only accept data with the media
+ type "text/calendar" and iCalendar version 2.0, and clients can
+ assume that the server will only accept this data.
+
+ Definition:
+
+ <!ELEMENT supported-calendar-data (calendar-data+)>
+
+ Example:
+
+ <C:supported-calendar-data
+ xmlns:C="urn:ietf:params:xml:ns:caldav">
+ <C:calendar-data content-type="text/calendar" version="2.0"/>
+ </C:supported-calendar-data>
+
+<span class="h4"><h4><a name="section-5.2.5">5.2.5</a>. CALDAV:max-resource-size Property</h4></span>
+
+ Name: max-resource-size
+
+ Namespace: urn:ietf:params:xml:ns:caldav
+
+ Purpose: Provides a numeric value indicating the maximum size of a
+ resource in octets that the server is willing to accept when a
+ calendar object resource is stored in a calendar collection.
+
+ Conformance: This property MAY be defined on any calendar
+ collection. If defined, it MUST be protected and SHOULD NOT be
+ returned by a PROPFIND DAV:allprop request (as defined in Section
+ 12.14.1 of [<a href="http://tools.ietf.org/html/rfc2518" title=""HTTP Extensions for Distributed Authoring -- WEBDAV"">RFC2518</a>]).
+
+ Description: The CALDAV:max-resource-size is used to specify a
+ numeric value that represents the maximum size in octets that the
+ server is willing to accept when a calendar object resource is
+ stored in a calendar collection. Any attempt to store a calendar
+ object resource exceeding this size MUST result in an error, with
+ the CALDAV:max-resource-size precondition (<a href="#section-5.3.2.1">Section 5.3.2.1</a>) being
+ violated. In the absence of this property, the client can assume
+ that the server will allow storing a resource of any reasonable
+ size.
+
+ Definition:
+
+ <!ELEMENT max-resource-size (#PCDATA)>
+ PCDATA value: a numeric value (positive integer)
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 16]</span>
+</pre><pre class="newpage"><a name="page-17" id="page-17" href="#page-17" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ Example:
+
+ <C:max-resource-size xmlns:C="urn:ietf:params:xml:ns:caldav"
+ >102400</C:max-resource-size>
+
+<span class="h4"><h4><a name="section-5.2.6">5.2.6</a>. CALDAV:min-date-time Property</h4></span>
+
+ Name: min-date-time
+
+ Namespace: urn:ietf:params:xml:ns:caldav
+
+ Purpose: Provides a DATE-TIME value indicating the earliest date and
+ time (in UTC) that the server is willing to accept for any DATE or
+ DATE-TIME value in a calendar object resource stored in a calendar
+ collection.
+
+ Conformance: This property MAY be defined on any calendar
+ collection. If defined, it MUST be protected and SHOULD NOT be
+ returned by a PROPFIND DAV:allprop request (as defined in Section
+ 12.14.1 of [<a href="http://tools.ietf.org/html/rfc2518" title=""HTTP Extensions for Distributed Authoring -- WEBDAV"">RFC2518</a>]).
+
+ Description: The CALDAV:min-date-time is used to specify an
+ iCalendar DATE-TIME value in UTC that indicates the earliest
+ inclusive date that the server is willing to accept for any
+ explicit DATE or DATE-TIME value in a calendar object resource
+ stored in a calendar collection. Any attempt to store a calendar
+ object resource using a DATE or DATE-TIME value earlier than this
+ value MUST result in an error, with the CALDAV:min-date-time
+ precondition (<a href="#section-5.3.2.1">Section 5.3.2.1</a>) being violated. Note that servers
+ MUST accept recurring components that specify instances beyond
+ this limit, provided none of those instances have been overridden.
+ In that case, the server MAY simply ignore those instances outside
+ of the acceptable range when processing reports on the calendar
+ object resource. In the absence of this property, the client can
+ assume any valid iCalendar date may be used at least up to the
+ CALDAV:max-date-time value, if that is defined.
+
+ Definition:
+
+ <!ELEMENT min-date-time (#PCDATA)>
+ PCDATA value: an iCalendar format DATE-TIME value in UTC
+
+ Example:
+
+ <C:min-date-time xmlns:C="urn:ietf:params:xml:ns:caldav"
+ >19000101T000000Z</C:min-date-time>
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 17]</span>
+</pre><pre class="newpage"><a name="page-18" id="page-18" href="#page-18" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+<span class="h4"><h4><a name="section-5.2.7">5.2.7</a>. CALDAV:max-date-time Property</h4></span>
+
+ Name: max-date-time
+
+ Namespace: urn:ietf:params:xml:ns:caldav
+
+ Purpose: Provides a DATE-TIME value indicating the latest date and
+ time (in UTC) that the server is willing to accept for any DATE or
+ DATE-TIME value in a calendar object resource stored in a calendar
+ collection.
+
+ Conformance: This property MAY be defined on any calendar
+ collection. If defined, it MUST be protected and SHOULD NOT be
+ returned by a PROPFIND DAV:allprop request (as defined in Section
+ 12.14.1 of [<a href="http://tools.ietf.org/html/rfc2518" title=""HTTP Extensions for Distributed Authoring -- WEBDAV"">RFC2518</a>]).
+
+ Description: The CALDAV:max-date-time is used to specify an
+ iCalendar DATE-TIME value in UTC that indicates the inclusive
+ latest date that the server is willing to accept for any date or
+ time value in a calendar object resource stored in a calendar
+ collection. Any attempt to store a calendar object resource using
+ a DATE or DATE-TIME value later than this value MUST result in an
+ error, with the CALDAV:max-date-time precondition
+ (<a href="#section-5.3.2.1">Section 5.3.2.1</a>) being violated. Note that servers MUST accept
+ recurring components that specify instances beyond this limit,
+ provided none of those instances have been overridden. In that
+ case, the server MAY simply ignore those instances outside of the
+ acceptable range when processing reports on the calendar object
+ resource. In the absence of this property, the client can assume
+ any valid iCalendar date may be used at least down to the CALDAV:
+ min-date-time value, if that is defined.
+
+ Definition:
+
+ <!ELEMENT max-date-time (#PCDATA)>
+ PCDATA value: an iCalendar format DATE-TIME value in UTC
+
+ Example:
+
+ <C:max-date-time xmlns:C="urn:ietf:params:xml:ns:caldav"
+ >20491231T235959Z</C:max-date-time>
+
+
+
+
+
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 18]</span>
+</pre><pre class="newpage"><a name="page-19" id="page-19" href="#page-19" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+<span class="h4"><h4><a name="section-5.2.8">5.2.8</a>. CALDAV:max-instances Property</h4></span>
+
+ Name: max-instances
+
+ Namespace: urn:ietf:params:xml:ns:caldav
+
+ Purpose: Provides a numeric value indicating the maximum number of
+ recurrence instances that a calendar object resource stored in a
+ calendar collection can generate.
+
+ Conformance: This property MAY be defined on any calendar
+ collection. If defined, it MUST be protected and SHOULD NOT be
+ returned by a PROPFIND DAV:allprop request (as defined in Section
+ 12.14.1 of [<a href="http://tools.ietf.org/html/rfc2518" title=""HTTP Extensions for Distributed Authoring -- WEBDAV"">RFC2518</a>]).
+
+ Description: The CALDAV:max-instances is used to specify a numeric
+ value that indicates the maximum number of recurrence instances
+ that a calendar object resource stored in a calendar collection
+ can generate. Any attempt to store a calendar object resource
+ with a recurrence pattern that generates more instances than this
+ value MUST result in an error, with the CALDAV:max-instances
+ precondition (<a href="#section-5.3.2.1">Section 5.3.2.1</a>) being violated. In the absence of
+ this property, the client can assume that the server has no limits
+ on the number of recurrence instances it can handle or expand.
+
+ Definition:
+
+ <!ELEMENT max-instances (#PCDATA)>
+ PCDATA value: a numeric value (integer greater than zero)
+
+ Example:
+
+ <C:max-instances xmlns:C="urn:ietf:params:xml:ns:caldav"
+ >100</C:max-instances>
+
+<span class="h4"><h4><a name="section-5.2.9">5.2.9</a>. CALDAV:max-attendees-per-instance Property</h4></span>
+
+ Name: max-attendees-per-instance
+
+ Namespace: urn:ietf:params:xml:ns:caldav
+
+ Purpose: Provides a numeric value indicating the maximum number of
+ ATTENDEE properties in any instance of a calendar object resource
+ stored in a calendar collection.
+
+ Conformance: This property MAY be defined on any calendar
+ collection. If defined, it MUST be protected and SHOULD NOT be
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 19]</span>
+</pre><pre class="newpage"><a name="page-20" id="page-20" href="#page-20" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ returned by a PROPFIND DAV:allprop request (as defined in Section
+ 12.14.1 of [<a href="http://tools.ietf.org/html/rfc2518" title=""HTTP Extensions for Distributed Authoring -- WEBDAV"">RFC2518</a>]).
+
+ Description: The CALDAV:max-attendees-per-instance is used to
+ specify a numeric value that indicates the maximum number of
+ iCalendar ATTENDEE properties on any one instance of a calendar
+ object resource stored in a calendar collection. Any attempt to
+ store a calendar object resource with more ATTENDEE properties per
+ instance than this value MUST result in an error, with the CALDAV:
+ max-attendees-per-instance precondition (<a href="#section-5.3.2.1">Section 5.3.2.1</a>) being
+ violated. In the absence of this property, the client can assume
+ that the server can handle any number of ATTENDEE properties in a
+ calendar component.
+
+ Definition:
+
+ <!ELEMENT max-attendees-per-instance (#PCDATA)>
+ PCDATA value: a numeric value (integer greater than zero)
+
+ Example:
+
+ <C:max-attendees-per-instance
+ xmlns:C="urn:ietf:params:xml:ns:caldav"
+ >25</C:max-attendees-per-instance>
+
+<span class="h4"><h4><a name="section-5.2.10">5.2.10</a>. Additional Precondition for PROPPATCH</h4></span>
+
+ This specification requires an additional Precondition for the
+ PROPPATCH method. The precondition is:
+
+ (CALDAV:valid-calendar-data): The time zone specified in CALDAV:
+ calendar-timezone property MUST be a valid iCalendar object
+ containing a single valid VTIMEZONE component.
+
+<span class="h3"><h3><a name="section-5.3">5.3</a>. Creating Resources</h3></span>
+
+ Calendar collections and calendar object resources may be created by
+ either a CalDAV client or by the CalDAV server. This specification
+ defines restrictions and a data model that both clients and servers
+ MUST adhere to when manipulating such calendar data.
+
+<span class="h4"><h4><a name="section-5.3.1">5.3.1</a>. MKCALENDAR Method</h4></span>
+
+ An HTTP request using the MKCALENDAR method creates a new calendar
+ collection resource. A server MAY restrict calendar collection
+ creation to particular collections.
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 20]</span>
+</pre><pre class="newpage"><a name="page-21" id="page-21" href="#page-21" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ Support for MKCALENDAR on the server is only RECOMMENDED and not
+ REQUIRED because some calendar stores only support one calendar per
+ user (or principal), and those are typically pre-created for each
+ account. However, servers and clients are strongly encouraged to
+ support MKCALENDAR whenever possible to allow users to create
+ multiple calendar collections to help organize their data better.
+
+ Clients SHOULD use the DAV:displayname property for a human-readable
+ name of the calendar. Clients can either specify the value of the
+ DAV:displayname property in the request body of the MKCALENDAR
+ request, or alternatively issue a PROPPATCH request to change the
+ DAV:displayname property to the appropriate value immediately after
+ issuing the MKCALENDAR request. Clients SHOULD NOT set the DAV:
+ displayname property to be the same as any other calendar collection
+ at the same URI "level". When displaying calendar collections to
+ users, clients SHOULD check the DAV:displayname property and use that
+ value as the name of the calendar. In the event that the DAV:
+ displayname property is empty, the client MAY use the last part of
+ the calendar collection URI as the name; however, that path segment
+ may be "opaque" and not represent any meaningful human-readable text.
+
+ If a MKCALENDAR request fails, the server state preceding the request
+ MUST be restored.
+
+ Marshalling:
+ If a request body is included, it MUST be a CALDAV:mkcalendar XML
+ element. Instruction processing MUST occur in the order
+ instructions are received (i.e., from top to bottom).
+ Instructions MUST either all be executed or none executed. Thus,
+ if any error occurs during processing, all executed instructions
+ MUST be undone and a proper error result returned. Instruction
+ processing details can be found in the definition of the DAV:set
+ instruction in <a href="http://tools.ietf.org/html/rfc2518#section-12.13.2">Section 12.13.2 of [RFC2518]</a>.
+
+ <!ELEMENT mkcalendar (DAV:set)>
+
+ If a response body for a successful request is included, it MUST
+ be a CALDAV:mkcalendar-response XML element.
+
+ <!ELEMENT mkcalendar-response ANY>
+
+ The response MUST include a Cache-Control:no-cache header.
+
+ Preconditions:
+
+ (DAV:resource-must-be-null): A resource MUST NOT exist at the
+ Request-URI;
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 21]</span>
+</pre><pre class="newpage"><a name="page-22" id="page-22" href="#page-22" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ (CALDAV:calendar-collection-location-ok): The Request-URI MUST
+ identify a location where a calendar collection can be created;
+
+ (CALDAV:valid-calendar-data): The time zone specified in the
+ CALDAV:calendar-timezone property MUST be a valid iCalendar object
+ containing a single valid VTIMEZONE component;
+
+ (DAV:needs-privilege): The DAV:bind privilege MUST be granted to
+ the current user on the parent collection of the Request-URI.
+
+ Postconditions:
+
+ (CALDAV:initialize-calendar-collection): A new calendar collection
+ exists at the Request-URI. The DAV:resourcetype of the calendar
+ collection MUST contain both DAV:collection and CALDAV:calendar
+ XML elements.
+
+<span class="h5"><h5><a name="section-5.3.1.1">5.3.1.1</a>. Status Codes</h5></span>
+
+ The following are examples of response codes one would expect to get
+ in a response to a MKCALENDAR request. Note that this list is by no
+ means exhaustive.
+
+ 201 (Created) - The calendar collection resource was created in
+ its entirety;
+
+ 207 (Multi-Status) - The calendar collection resource was not
+ created since one or more DAV:set instructions specified in the
+ request body could not be processed successfully. The following
+ are examples of response codes one would expect to be used in a
+ 207 (Multi-Status) response in this situation:
+
+ 403 (Forbidden) - The client, for reasons the server chooses
+ not to specify, cannot alter one of the properties;
+
+ 409 (Conflict) - The client has provided a value whose
+ semantics are not appropriate for the property. This includes
+ trying to set read-only properties;
+
+ 424 (Failed Dependency) - The DAV:set instruction on the
+ specified resource would have succeeded if it were not for the
+ failure of another DAV:set instruction specified in the request
+ body;
+
+ 423 (Locked) - The specified resource is locked and the client
+ either is not a lock owner or the lock type requires a lock
+ token to be submitted and the client did not submit it; and
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 22]</span>
+</pre><pre class="newpage"><a name="page-23" id="page-23" href="#page-23" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ 507 (Insufficient Storage) - The server did not have sufficient
+ space to record the property;
+
+ 403 (Forbidden) - This indicates at least one of two conditions:
+ 1) the server does not allow the creation of calendar collections
+ at the given location in its namespace, or 2) the parent
+ collection of the Request-URI exists but cannot accept members;
+
+ 409 (Conflict) - A collection cannot be made at the Request-URI
+ until one or more intermediate collections have been created;
+
+ 415 (Unsupported Media Type) - The server does not support the
+ request type of the body; and
+
+ 507 (Insufficient Storage) - The resource does not have sufficient
+ space to record the state of the resource after the execution of
+ this method.
+
+<span class="h5"><h5><a name="section-5.3.1.2">5.3.1.2</a>. Example: Successful MKCALENDAR Request</h5></span>
+
+ This example creates a calendar collection called /home/lisa/
+ calendars/events/ on the server cal.example.com with specific values
+ for the properties DAV:displayname, CALDAV:calendar-description,
+ CALDAV:supported-calendar-component-set, and CALDAV:calendar-
+ timezone.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 23]</span>
+</pre><pre class="newpage"><a name="page-24" id="page-24" href="#page-24" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ >> Request <<
+
+ MKCALENDAR /home/lisa/calendars/events/ HTTP/1.1
+ Host: cal.example.com
+ Content-Type: application/xml; charset="utf-8"
+ Content-Length: xxxx
+
+ <?xml version="1.0" encoding="utf-8" ?>
+ <C:mkcalendar xmlns:D="DAV:"
+ xmlns:C="urn:ietf:params:xml:ns:caldav">
+ <D:set>
+ <D:prop>
+ <D:displayname>Lisa's Events</D:displayname>
+ <C:calendar-description xml:lang="en"
+ >Calendar restricted to events.</C:calendar-description>
+ <C:supported-calendar-component-set>
+ <C:comp name="VEVENT"/>
+ </C:supported-calendar-component-set>
+ <C:calendar-timezone><![CDATA[BEGIN:VCALENDAR
+ PRODID:-//Example Corp.//CalDAV Client//EN
+ VERSION:2.0
+ BEGIN:VTIMEZONE
+ TZID:US-Eastern
+ LAST-MODIFIED:19870101T000000Z
+ BEGIN:STANDARD
+ DTSTART:19671029T020000
+ RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+ TZOFFSETFROM:-0400
+ TZOFFSETTO:-0500
+ TZNAME:Eastern Standard Time (US & Canada)
+ END:STANDARD
+ BEGIN:DAYLIGHT
+ DTSTART:19870405T020000
+ RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+ TZOFFSETFROM:-0500
+ TZOFFSETTO:-0400
+ TZNAME:Eastern Daylight Time (US & Canada)
+ END:DAYLIGHT
+ END:VTIMEZONE
+ END:VCALENDAR
+ ]]></C:calendar-timezone>
+ </D:prop>
+ </D:set>
+ </C:mkcalendar>
+
+
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 24]</span>
+</pre><pre class="newpage"><a name="page-25" id="page-25" href="#page-25" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ >> Response <<
+
+ HTTP/1.1 201 Created
+ Cache-Control: no-cache
+ Date: Sat, 11 Nov 2006 09:32:12 GMT
+ Content-Length: 0
+
+<span class="h4"><h4><a name="section-5.3.2">5.3.2</a>. Creating Calendar Object Resources</h4></span>
+
+ Clients populate calendar collections with calendar object resources.
+ The URL for each calendar object resource is entirely arbitrary and
+ does not need to bear a specific relationship to the calendar object
+ resource's iCalendar properties or other metadata. New calendar
+ object resources MUST be created with a PUT request targeted at an
+ unmapped URI. A PUT request targeted at a mapped URI updates an
+ existing calendar object resource.
+
+ When servers create new resources, it's not hard for the server to
+ choose an unmapped URI. It's slightly tougher for clients, because a
+ client might not want to examine all resources in the collection and
+ might not want to lock the entire collection to ensure that a new
+ resource isn't created with a name collision. However, there is an
+ HTTP feature to mitigate this. If the client intends to create a new
+ non-collection resource, such as a new VEVENT, the client SHOULD use
+ the HTTP request header "If-None-Match: *" on the PUT request. The
+ Request-URI on the PUT request MUST include the target collection,
+ where the resource is to be created, plus the name of the resource in
+ the last path segment. The "If-None-Match: *" request header ensures
+ that the client will not inadvertently overwrite an existing resource
+ if the last path segment turned out to already be used.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 25]</span>
+</pre><pre class="newpage"><a name="page-26" id="page-26" href="#page-26" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ >> Request <<
+
+ PUT /home/lisa/calendars/events/qwue23489.ics HTTP/1.1
+ If-None-Match: *
+ Host: cal.example.com
+ Content-Type: text/calendar
+ Content-Length: xxxx
+
+ BEGIN:VCALENDAR
+ VERSION:2.0
+ PRODID:-//Example Corp.//CalDAV Client//EN
+ BEGIN:VEVENT
+ UID:20010712T182145Z-123401@example.com
+ DTSTAMP:20060712T182145Z
+ DTSTART:20060714T170000Z
+ DTEND:20060715T040000Z
+ SUMMARY:Bastille Day Party
+ END:VEVENT
+ END:VCALENDAR
+
+ >> Response <<
+
+ HTTP/1.1 201 Created
+ Content-Length: 0
+ Date: Sat, 11 Nov 2006 09:32:12 GMT
+ ETag: "123456789-000-111"
+
+ The request to change an existing event is the same, but with a
+ specific ETag in the "If-Match" header, rather than the "If-None-
+ Match" header.
+
+ As indicated in <a href="http://tools.ietf.org/html/rfc2445#section-3.10">Section 3.10 of [RFC2445]</a>, the URL of calendar object
+ resources containing (an arbitrary set of) calendaring and scheduling
+ information may be suffixed by ".ics", and the URL of calendar object
+ resources containing free or busy time information may be suffixed by
+ ".ifb".
+
+<span class="h5"><h5><a name="section-5.3.2.1">5.3.2.1</a>. Additional Preconditions for PUT, COPY, and MOVE</h5></span>
+
+ This specification creates additional Preconditions for PUT, COPY,
+ and MOVE methods. These preconditions apply when a PUT operation of
+ a calendar object resource into a calendar collection occurs, or when
+ a COPY or MOVE operation of a calendar object resource into a
+ calendar collection occurs, or when a COPY or MOVE operation occurs
+ on a calendar collection.
+
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 26]</span>
+</pre><pre class="newpage"><a name="page-27" id="page-27" href="#page-27" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ The new preconditions are:
+
+ (CALDAV:supported-calendar-data): The resource submitted in the
+ PUT request, or targeted by a COPY or MOVE request, MUST be a
+ supported media type (i.e., iCalendar) for calendar object
+ resources;
+
+ (CALDAV:valid-calendar-data): The resource submitted in the PUT
+ request, or targeted by a COPY or MOVE request, MUST be valid data
+ for the media type being specified (i.e., MUST contain valid
+ iCalendar data);
+
+ (CALDAV:valid-calendar-object-resource): The resource submitted in
+ the PUT request, or targeted by a COPY or MOVE request, MUST obey
+ all restrictions specified in <a href="#section-4.1">Section 4.1</a> (e.g., calendar object
+ resources MUST NOT contain more than one type of calendar
+ component, calendar object resources MUST NOT specify the
+ iCalendar METHOD property, etc.);
+
+ (CALDAV:supported-calendar-component): The resource submitted in
+ the PUT request, or targeted by a COPY or MOVE request, MUST
+ contain a type of calendar component that is supported in the
+ targeted calendar collection;
+
+ (CALDAV:no-uid-conflict): The resource submitted in the PUT
+ request, or targeted by a COPY or MOVE request, MUST NOT specify
+ an iCalendar UID property value already in use in the targeted
+ calendar collection or overwrite an existing calendar object
+ resource with one that has a different UID property value.
+ Servers SHOULD report the URL of the resource that is already
+ making use of the same UID property value in the DAV:href element;
+
+ <!ELEMENT no-uid-conflict (DAV:href)>
+
+ (CALDAV:calendar-collection-location-ok): In a COPY or MOVE
+ request, when the Request-URI is a calendar collection, the
+ Destination-URI MUST identify a location where a calendar
+ collection can be created;
+
+ (CALDAV:max-resource-size): The resource submitted in the PUT
+ request, or targeted by a COPY or MOVE request, MUST have an octet
+ size less than or equal to the value of the CALDAV:max-resource-
+ size property value (<a href="#section-5.2.5">Section 5.2.5</a>) on the calendar collection
+ where the resource will be stored;
+
+ (CALDAV:min-date-time): The resource submitted in the PUT request,
+ or targeted by a COPY or MOVE request, MUST have all of its
+ iCalendar DATE or DATE-TIME property values (for each recurring
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 27]</span>
+</pre><pre class="newpage"><a name="page-28" id="page-28" href="#page-28" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ instance) greater than or equal to the value of the CALDAV:min-
+ date-time property value (<a href="#section-5.2.6">Section 5.2.6</a>) on the calendar
+ collection where the resource will be stored;
+
+ (CALDAV:max-date-time): The resource submitted in the PUT request,
+ or targeted by a COPY or MOVE request, MUST have all of its
+ iCalendar DATE or DATE-TIME property values (for each recurring
+ instance) less than the value of the CALDAV:max-date-time property
+ value (<a href="#section-5.2.7">Section 5.2.7</a>) on the calendar collection where the
+ resource will be stored;
+
+ (CALDAV:max-instances): The resource submitted in the PUT request,
+ or targeted by a COPY or MOVE request, MUST generate a number of
+ recurring instances less than or equal to the value of the CALDAV:
+ max-instances property value (<a href="#section-5.2.8">Section 5.2.8</a>) on the calendar
+ collection where the resource will be stored;
+
+ (CALDAV:max-attendees-per-instance): The resource submitted in the
+ PUT request, or targeted by a COPY or MOVE request, MUST have a
+ number of ATTENDEE properties on any one instance less than or
+ equal to the value of the CALDAV:max-attendees-per-instance
+ property value (<a href="#section-5.2.9">Section 5.2.9</a>) on the calendar collection where
+ the resource will be stored;
+
+<span class="h4"><h4><a name="section-5.3.3">5.3.3</a>. Non-Standard Components, Properties, and Parameters</h4></span>
+
+ iCalendar provides a "standard mechanism for doing non-standard
+ things". This extension support allows implementers to make use of
+ non-standard components, properties, and parameters whose names are
+ prefixed with the text "X-".
+
+ Servers MUST support the use of non-standard components, properties,
+ and parameters in calendar object resources stored via the PUT
+ method.
+
+ Servers may need to enforce rules for their own "private" components,
+ properties, or parameters, so servers MAY reject any attempt by the
+ client to change those or use values for those outside of any
+ restrictions the server may have. Servers SHOULD ensure that any
+ "private" components, properties, or parameters it uses follow the
+ convention of including a vendor id in the "X-" name, as described in
+ <a href="http://tools.ietf.org/html/rfc2445#section-4.2">Section 4.2 of [RFC2445]</a>, e.g., "X-ABC-PRIVATE".
+
+<span class="h4"><h4><a name="section-5.3.4">5.3.4</a>. Calendar Object Resource Entity Tag</h4></span>
+
+ The DAV:getetag property MUST be defined and set to a strong entity
+ tag on all calendar object resources.
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 28]</span>
+</pre><pre class="newpage"><a name="page-29" id="page-29" href="#page-29" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ A response to a GET request targeted at a calendar object resource
+ MUST contain an ETag response header field indicating the current
+ value of the strong entity tag of the calendar object resource.
+
+ Servers SHOULD return a strong entity tag (ETag header) in a PUT
+ response when the stored calendar object resource is equivalent by
+ octet equality to the calendar object resource submitted in the body
+ of the PUT request. This allows clients to reliably use the returned
+ strong entity tag for data synchronization purposes. For instance,
+ the client can do a PROPFIND request on the stored calendar object
+ resource and have the DAV:getetag property returned, and compare that
+ value with the strong entity tag it received on the PUT response, and
+ know that if they are equal, then the calendar object resource on the
+ server has not been changed.
+
+ In the case where the data stored by a server as a result of a PUT
+ request is not equivalent by octet equality to the submitted calendar
+ object resource, the behavior of the ETag response header is not
+ specified here, with the exception that a strong entity tag MUST NOT
+ be returned in the response. As a result, clients may need to
+ retrieve the modified calendar object resource (and ETag) as a basis
+ for further changes, rather than use the calendar object resource it
+ had sent with the PUT request.
+
+<span class="h2"><h2><a name="section-6">6</a>. Calendaring Access Control</h2></span>
+
+<span class="h3"><h3><a name="section-6.1">6.1</a>. Calendaring Privilege</h3></span>
+
+ CalDAV servers MUST support and adhere to the requirements of WebDAV
+ ACL [<a href="http://tools.ietf.org/html/rfc3744" title=""Web Distributed Authoring and Versioning (WebDAV) Access Control Protocol"">RFC3744</a>]. WebDAV ACL provides a framework for an extensible set
+ of privileges that can be applied to WebDAV collections and ordinary
+ resources. CalDAV servers MUST also support the calendaring
+ privilege defined in this section.
+
+<span class="h4"><h4><a name="section-6.1.1">6.1.1</a>. CALDAV:read-free-busy Privilege</h4></span>
+
+ Calendar users often wish to allow other users to see their busy time
+ information, without viewing the other details of the calendar
+ components (e.g., location, summary, attendees). This allows a
+ significant amount of privacy while still allowing other users to
+ schedule meetings at times when the user is likely to be free.
+
+ The CALDAV:read-free-busy privilege controls which calendar
+ collections, regular collections, and calendar object resources are
+ examined when a CALDAV:free-busy-query REPORT request is processed
+ (see <a href="#section-7.10">Section 7.10</a>). This privilege can be granted on calendar
+ collections, regular collections, or calendar object resources.
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 29]</span>
+</pre><pre class="newpage"><a name="page-30" id="page-30" href="#page-30" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ Servers MUST support this privilege on all calendar collections,
+ regular collections, and calendar object resources.
+
+
+ <!ELEMENT read-free-busy EMPTY>
+
+ The CALDAV:read-free-busy privilege MUST be aggregated in the DAV:
+ read privilege. Servers MUST allow the CALDAV:read-free-busy to be
+ granted without the DAV:read privilege being granted.
+
+ Clients should note that when only the CALDAV:read-free-busy
+ privilege has been granted on a resource, access to GET, HEAD,
+ OPTIONS, and PROPFIND on the resource is not implied (those
+ operations are governed by the DAV:read privilege).
+
+<span class="h3"><h3><a name="section-6.2">6.2</a>. Additional Principal Property</h3></span>
+
+ This section defines an additional property for WebDAV principal
+ resources, as defined in [<a href="http://tools.ietf.org/html/rfc3744" title=""Web Distributed Authoring and Versioning (WebDAV) Access Control Protocol"">RFC3744</a>].
+
+<span class="h4"><h4><a name="section-6.2.1">6.2.1</a>. CALDAV:calendar-home-set Property</h4></span>
+
+ Name: calendar-home-set
+
+ Namespace: urn:ietf:params:xml:ns:caldav
+
+ Purpose: Identifies the URL of any WebDAV collections that contain
+ calendar collections owned by the associated principal resource.
+
+ Conformance: This property SHOULD be defined on a principal
+ resource. If defined, it MAY be protected and SHOULD NOT be
+ returned by a PROPFIND DAV:allprop request (as defined in Section
+ 12.14.1 of [<a href="http://tools.ietf.org/html/rfc2518" title=""HTTP Extensions for Distributed Authoring -- WEBDAV"">RFC2518</a>]).
+
+ Description: The CALDAV:calendar-home-set property is meant to allow
+ users to easily find the calendar collections owned by the
+ principal. Typically, users will group all the calendar
+ collections that they own under a common collection. This
+ property specifies the URL of collections that are either calendar
+ collections or ordinary collections that have child or descendant
+ calendar collections owned by the principal.
+
+ Definition:
+
+ <!ELEMENT calendar-home-set (DAV:href*)>
+
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 30]</span>
+</pre><pre class="newpage"><a name="page-31" id="page-31" href="#page-31" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ Example:
+
+ <C:calendar-home-set xmlns:D="DAV:"
+ xmlns:C="urn:ietf:params:xml:ns:caldav">
+ <D:href>http://cal.example.com/home/bernard/calendars/</D:href>
+ </C:calendar-home-set>
+
+<span class="h2"><h2><a name="section-7">7</a>. Calendaring Reports</h2></span>
+
+ This section defines the reports that CalDAV servers MUST support on
+ calendar collections and calendar object resources.
+
+ CalDAV servers MUST advertise support for these reports on all
+ calendar collections and calendar object resources with the DAV:
+ supported-report-set property, defined in <a href="http://tools.ietf.org/html/rfc3253#section-3.1.5">Section 3.1.5 of [RFC3253]</a>.
+ CalDAV servers MAY also advertise support for these reports on
+ ordinary collections.
+
+ Some of these reports allow calendar data (from possibly multiple
+ resources) to be returned.
+
+<span class="h3"><h3><a name="section-7.1">7.1</a>. REPORT Method</h3></span>
+
+ The REPORT method (defined in <a href="http://tools.ietf.org/html/rfc3253#section-3.6">Section 3.6 of [RFC3253]</a>) provides an
+ extensible mechanism for obtaining information about one or more
+ resources. Unlike the PROPFIND method, which returns the value of
+ one or more named properties, the REPORT method can involve more
+ complex processing. REPORT is valuable in cases where the server has
+ access to all of the information needed to perform the complex
+ request (such as a query), and where it would require multiple
+ requests for the client to retrieve the information needed to perform
+ the same request.
+
+ CalDAV servers MUST support the DAV:expand-property REPORT defined in
+ <a href="http://tools.ietf.org/html/rfc3253#section-3.8">Section 3.8 of [RFC3253]</a>.
+
+<span class="h3"><h3><a name="section-7.2">7.2</a>. Ordinary Collections</h3></span>
+
+ Servers MAY support the reports defined in this document on ordinary
+ collections (collections that are not calendar collections), in
+ addition to calendar collections or calendar object resources. In
+ computing responses to the reports on ordinary collections, servers
+ MUST only consider calendar object resources contained in calendar
+ collections that are targeted by the REPORT request, based on the
+ value of the Depth request header.
+
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 31]</span>
+</pre><pre class="newpage"><a name="page-32" id="page-32" href="#page-32" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+<span class="h3"><h3><a name="section-7.3">7.3</a>. Date and Floating Time</h3></span>
+
+ iCalendar provides a way to specify DATE and DATE-TIME values that
+ are not bound to any time zone in particular, hereafter called
+ "floating date" and "floating time", respectively. These values are
+ used to represent the same day, hour, minute, and second value,
+ regardless of which time zone is being observed. For instance, the
+ DATE value "20051111", represents November 11, 2005 in no specific
+ time zone, while the DATE-TIME value "20051111T111100" represents
+ November 11, 2005, at 11:11 A.M. in no specific time zone.
+
+ CalDAV servers may need to convert "floating date" and "floating
+ time" values in date with UTC time values in the processing of
+ calendaring REPORT requests.
+
+ For the CALDAV:calendar-query REPORT, CalDAV servers MUST rely on the
+ value of the CALDAV:timezone XML element, if specified as part of the
+ request body, to perform the proper conversion of "floating date" and
+ "floating time" values to date with UTC time values. If the CALDAV:
+ timezone XML element is not specified in the request body, CalDAV
+ servers MUST rely on the value of the CALDAV:calendar-timezone
+ property, if defined, or else the CalDAV servers MAY rely on the time
+ zone of their choice.
+
+ For the CALDAV:free-busy-query REPORT, CalDAV servers MUST rely on
+ the value of the CALDAV:calendar-timezone property, if defined, to
+ compute the proper FREEBUSY time period value as date with UTC time
+ for calendar components scheduled with "floating date" or "floating
+ time". If the CALDAV:calendar-timezone property is not defined,
+ CalDAV servers MAY rely on the time zone of their choice.
+
+<span class="h3"><h3><a name="section-7.4">7.4</a>. Time Range Filtering</h3></span>
+
+ Some of the reports defined in this section can include a time range
+ filter that is used to restrict the set of calendar object resources
+ returned to just those that overlap the specified time range. The
+ time range filter can be applied to a calendar component as a whole,
+ or to specific calendar component properties with DATE or DATE-TIME
+ value types.
+
+ To determine whether a calendar object resource matches the time
+ range filter element, the start and end times for the targeted
+ component or property are determined and then compared to the
+ requested time range. If there is an overlap with the requested time
+ range, then the calendar object resource matches the filter element.
+ The rules defined in [<a href="http://tools.ietf.org/html/rfc2445" title=""Internet Calendaring and Scheduling Core Object Specification (iCalendar)"">RFC2445</a>] for determining the actual start and
+ end times of calendar components MUST be used, and these are fully
+ enumerated in <a href="#section-9.9">Section 9.9</a> of this document.
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 32]</span>
+</pre><pre class="newpage"><a name="page-33" id="page-33" href="#page-33" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ When such time range filtering is used, special consideration must be
+ given to recurring calendar components, such as VEVENT and VTODO.
+ The server MUST expand recurring components to determine whether any
+ recurrence instances overlap the specified time range. If one or
+ more recurrence instances overlap the time range, then the calendar
+ object resource matches the filter element.
+
+<span class="h3"><h3><a name="section-7.5">7.5</a>. Searching Text: Collations</h3></span>
+
+ Some of the reports defined in this section do text matches of
+ character strings provided by the client and are compared to stored
+ calendar data. Since iCalendar data is, by default, encoded in the
+ UTF-8 charset and may include characters outside the US-ASCII charset
+ range in some property and parameter values, there is a need to
+ ensure that text matching follows well-defined rules.
+
+ To deal with this, this specification makes use of the IANA Collation
+ Registry defined in [<a href="http://tools.ietf.org/html/rfc4790" title=""Internet Application Protocol Collation Registry"">RFC4790</a>] to specify collations that may be used
+ to carry out the text comparison operations with a well-defined rule.
+
+ The comparisons used in CalDAV are all "substring" matches, as per
+ <a href="http://tools.ietf.org/html/rfc4790#section-4.2">[RFC4790], Section 4.2</a>. Collations supported by the server MUST
+ support "substring" match operations.
+
+ CalDAV servers are REQUIRED to support the "i;ascii-casemap" and
+ "i;octet" collations, as described in [<a href="http://tools.ietf.org/html/rfc4790" title=""Internet Application Protocol Collation Registry"">RFC4790</a>], and MAY support
+ other collations.
+
+ Servers MUST advertise the set of collations that they support via
+ the CALDAV:supported-collation-set property defined on any resource
+ that supports reports that use collations.
+
+ Clients MUST only use collations from the list advertised by the
+ server.
+
+ In the absence of a collation explicitly specified by the client, or
+ if the client specifies the "default" collation identifier (as
+ defined in <a href="http://tools.ietf.org/html/rfc4790#section-3.1">[RFC4790], Section 3.1</a>), the server MUST default to using
+ "i;ascii-casemap" as the collation.
+
+ Wildcards (as defined in <a href="http://tools.ietf.org/html/rfc4790#section-3.2">[RFC4790], Section 3.2</a>) MUST NOT be used in
+ the collation identifier.
+
+ If the client chooses a collation not supported by the server, the
+ server MUST respond with a CALDAV:supported-collation precondition
+ error response.
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 33]</span>
+</pre><pre class="newpage"><a name="page-34" id="page-34" href="#page-34" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+<span class="h4"><h4><a name="section-7.5.1">7.5.1</a>. CALDAV:supported-collation-set Property</h4></span>
+
+ Name: supported-collation-set
+
+ Namespace: urn:ietf:params:xml:ns:caldav
+
+ Purpose: Identifies the set of collations supported by the server
+ for text matching operations.
+
+ Conformance: This property MUST be defined on any resource that
+ supports a report that does text matching. If defined, it MUST be
+ protected and SHOULD NOT be returned by a PROPFIND DAV:allprop
+ request (as defined in <a href="http://tools.ietf.org/html/rfc2518#section-12.14.1">Section 12.14.1 of [RFC2518]</a>).
+
+ Description: The CALDAV:supported-collation-set property contains
+ zero or more CALDAV:supported-collation elements, which specify
+ the collection identifiers of the collations supported by the
+ server.
+
+ Definition:
+
+ <!ELEMENT supported-collation-set (supported-collation*)>
+
+ <!ELEMENT supported-collation (#PCDATA)>
+
+ Example:
+
+ <C:supported-collation-set
+ xmlns:C="urn:ietf:params:xml:ns:caldav">
+ <C:supported-collation>i;ascii-casemap</C:supported-collation>
+ <C:supported-collation>i;octet</C:supported-collation>
+ </C:supported-collation-set>
+
+<span class="h3"><h3><a name="section-7.6">7.6</a>. Partial Retrieval</h3></span>
+
+ Some calendaring reports defined in this document allow partial
+ retrieval of calendar object resources. A CalDAV client can specify
+ what information to return in the body of a calendaring REPORT
+ request.
+
+ A CalDAV client can request particular WebDAV property values, all
+ WebDAV property values, or a list of the names of the resource's
+ WebDAV properties. A CalDAV client can also request calendar data to
+ be returned and specify whether all calendar components and
+ properties should be returned, or only particular ones. See CALDAV:
+ calendar-data in <a href="#section-9.6">Section 9.6</a>.
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 34]</span>
+</pre><pre class="newpage"><a name="page-35" id="page-35" href="#page-35" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ By default, the returned calendar data will include the component
+ that defines the recurrence set, referred to as the "master
+ component", as well as the components that define exceptions to the
+ recurrence set, referred to as the "overridden components".
+
+ A CalDAV client that is only interested in the recurrence instances
+ that overlap a specified time range can request to receive only the
+ "master component", along with the "overridden components" that
+ impact the specified time range, and thus, limit the data returned by
+ the server (see CALDAV:limit-recurrence-set in <a href="#section-9.6.6">Section 9.6.6</a>). An
+ overridden component impacts a time range if its current start and
+ end times overlap the time range, or if the original start and end
+ times -- the ones that would have been used if the instance were not
+ overridden -- overlap the time range, or if it affects other
+ instances that overlap the time range.
+
+ A CalDAV client with no support for recurrence properties (i.e.,
+ EXDATE, EXRULE, RDATE, and RRULE) and possibly VTIMEZONE components,
+ or a client unwilling to perform recurrence expansion because of
+ limited processing capability, can request to receive only the
+ recurrence instances that overlap a specified time range as separate
+ calendar components that each define exactly one recurrence instance
+ (see CALDAV:expand in <a href="#section-9.6.5">Section 9.6.5</a>.)
+
+ Finally, in the case of VFREEBUSY components, a CalDAV client can
+ request to receive only the FREEBUSY property values that overlap a
+ specified time range (see CALDAV:limit-freebusy-set in
+ <a href="#section-9.6.7">Section 9.6.7</a>.)
+
+<span class="h3"><h3><a name="section-7.7">7.7</a>. Non-Standard Components, Properties, and Parameters</h3></span>
+
+ Servers MUST support the use of non-standard component, property, or
+ parameter names in the CALDAV:calendar-data XML element in
+ calendaring REPORT requests to allow clients to request that non-
+ standard components, properties, and parameters be returned in the
+ calendar data provided in the response.
+
+ Servers MAY support the use of non-standard component, property, or
+ parameter names in the CALDAV:comp-filter, CALDAV:prop-filter, and
+ CALDAV:param-filter XML elements specified in the CALDAV:filter XML
+ element of calendaring REPORT requests.
+
+ Servers MUST fail with the CALDAV:supported-filter precondition if a
+ calendaring REPORT request uses a CALDAV:comp-filter, CALDAV:prop-
+ filter, or CALDAV:param-filter XML element that makes reference to a
+ non-standard component, property, or parameter name on which the
+ server does not support queries.
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 35]</span>
+</pre><pre class="newpage"><a name="page-36" id="page-36" href="#page-36" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+<span class="h3"><h3><a name="section-7.8">7.8</a>. CALDAV:calendar-query REPORT</h3></span>
+
+ The CALDAV:calendar-query REPORT performs a search for all calendar
+ object resources that match a specified filter. The response of this
+ report will contain all the WebDAV properties and calendar object
+ resource data specified in the request. In the case of the CALDAV:
+ calendar-data XML element, one can explicitly specify the calendar
+ components and properties that should be returned in the calendar
+ object resource data that matches the filter.
+
+ The format of this report is modeled on the PROPFIND method. The
+ request and response bodies of the CALDAV:calendar-query REPORT use
+ XML elements that are also used by PROPFIND. In particular, the
+ request can include XML elements to request WebDAV properties to be
+ returned. When that occurs, the response should follow the same
+ behavior as PROPFIND with respect to the DAV:multistatus response
+ elements used to return specific property results. For instance, a
+ request to retrieve the value of a property that does not exist is an
+ error and MUST be noted with a response XML element that contains a
+ 404 (Not Found) status value.
+
+ Support for the CALDAV:calendar-query REPORT is REQUIRED.
+
+ Marshalling:
+
+ The request body MUST be a CALDAV:calendar-query XML element, as
+ defined in <a href="#section-9.5">Section 9.5</a>.
+
+ The request MAY include a Depth header. If no Depth header is
+ included, Depth:0 is assumed.
+
+ The response body for a successful request MUST be a DAV:
+ multistatus XML element (i.e., the response uses the same format
+ as the response for PROPFIND). In the case where there are no
+ response elements, the returned DAV:multistatus XML element is
+ empty.
+
+ The response body for a successful CALDAV:calendar-query REPORT
+ request MUST contain a DAV:response element for each iCalendar
+ object that matched the search filter. Calendar data is being
+ returned in the CALDAV:calendar-data XML element inside the DAV:
+ propstat XML element.
+
+ Preconditions:
+
+ (CALDAV:supported-calendar-data): The attributes "content-type"
+ and "version" of the CALDAV:calendar-data XML element (see
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 36]</span>
+</pre><pre class="newpage"><a name="page-37" id="page-37" href="#page-37" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ <a href="#section-9.6">Section 9.6</a>) specify a media type supported by the server for
+ calendar object resources.
+
+ (CALDAV:valid-filter): The CALDAV:filter XML element (see
+ <a href="#section-9.7">Section 9.7</a>) specified in the REPORT request MUST be valid. For
+ instance, a CALDAV:filter cannot nest a <C:comp name="VEVENT">
+ element in a <C:comp name="VTODO"> element, and a CALDAV:filter
+ cannot nest a <C:time-range start="..." end="..."> element in a
+ <C:prop name="SUMMARY"> element.
+
+ (CALDAV:supported-filter): The CALDAV:comp-filter (see
+ <a href="#section-9.7.1">Section 9.7.1</a>), CALDAV:prop-filter (see <a href="#section-9.7.2">Section 9.7.2</a>), and
+ CALDAV:param-filter (see <a href="#section-9.7.3">Section 9.7.3</a>) XML elements used in the
+ CALDAV:filter XML element (see <a href="#section-9.7">Section 9.7</a>) in the REPORT request
+ only make reference to components, properties, and parameters for
+ which queries are supported by the server, i.e., if the CALDAV:
+ filter element attempts to reference an unsupported component,
+ property, or parameter, this precondition is violated. Servers
+ SHOULD report the CALDAV:comp-filter, CALDAV:prop-filter, or
+ CALDAV:param-filter for which it does not provide support.
+
+ <!ELEMENT supported-filter (comp-filter*,
+ prop-filter*,
+ param-filter*)>
+
+ (CALDAV:valid-calendar-data): The time zone specified in the
+ REPORT request MUST be a valid iCalendar object containing a
+ single valid VTIMEZONE component.
+
+ (CALDAV:min-date-time): Any XML element specifying a range of time
+ MUST have its start or end DATE or DATE-TIME values greater than
+ or equal to the value of the CALDAV:min-date-time property value
+ (<a href="#section-5.2.6">Section 5.2.6</a>) on the calendar collections being targeted by the
+ REPORT request;
+
+ (CALDAV:max-date-time): Any XML element specifying a range of time
+ MUST have its start or end DATE or DATE-TIME values less than or
+ equal to the value of the CALDAV:max-date-time property value
+ (<a href="#section-5.2.7">Section 5.2.7</a>) on the calendar collections being targeted by the
+ REPORT request;
+
+ (CALDAV:supported-collation): Any XML attribute specifying a
+ collation MUST specify a collation supported by the server as
+ described in <a href="#section-7.5">Section 7.5</a>.
+
+
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 37]</span>
+</pre><pre class="newpage"><a name="page-38" id="page-38" href="#page-38" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ Postconditions:
+
+ (DAV:number-of-matches-within-limits): The number of matching
+ calendar object resources must fall within server-specific,
+ predefined limits. For example, this condition might be triggered
+ if a search specification would cause the return of an extremely
+ large number of responses.
+
+<span class="h4"><h4><a name="section-7.8.1">7.8.1</a>. Example: Partial Retrieval of Events by Time Range</h4></span>
+
+ In this example, the client requests the server to return specific
+ components and properties of the VEVENT components that overlap the
+ time range from January 4, 2006, at 00:00:00 A.M. UTC to January 5,
+ 2006, at 00:00:00 A.M. UTC. In addition, the DAV:getetag property is
+ also requested and returned as part of the response. Note that the
+ first calendar object returned is a recurring event whose first
+ instance lies outside the requested time range, but whose third
+ instance does overlap the time range. Note that due to the CALDAV:
+ calendar-data element restrictions, the DTSTAMP property in VEVENT
+ components has not been returned, and the only property returned in
+ the VCALENDAR object is VERSION.
+
+ See <a href="#appendix-B">Appendix B</a> for the calendar data being targeted by this example.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 38]</span>
+</pre><pre class="newpage"><a name="page-39" id="page-39" href="#page-39" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ >> Request <<
+
+ REPORT /bernard/work/ HTTP/1.1
+ Host: cal.example.com
+ Depth: 1
+ Content-Type: application/xml; charset="utf-8"
+ Content-Length: xxxx
+
+ <?xml version="1.0" encoding="utf-8" ?>
+ <C:calendar-query xmlns:D="DAV:"
+ xmlns:C="urn:ietf:params:xml:ns:caldav">
+ <D:prop>
+ <D:getetag/>
+ <C:calendar-data>
+ <C:comp name="VCALENDAR">
+ <C:prop name="VERSION"/>
+ <C:comp name="VEVENT">
+ <C:prop name="SUMMARY"/>
+ <C:prop name="UID"/>
+ <C:prop name="DTSTART"/>
+ <C:prop name="DTEND"/>
+ <C:prop name="DURATION"/>
+ <C:prop name="RRULE"/>
+ <C:prop name="RDATE"/>
+ <C:prop name="EXRULE"/>
+ <C:prop name="EXDATE"/>
+ <C:prop name="RECURRENCE-ID"/>
+ </C:comp>
+ <C:comp name="VTIMEZONE"/>
+ </C:comp>
+ </C:calendar-data>
+ </D:prop>
+ <C:filter>
+ <C:comp-filter name="VCALENDAR">
+ <C:comp-filter name="VEVENT">
+ <C:time-range start="20060104T000000Z"
+ end="20060105T000000Z"/>
+ </C:comp-filter>
+ </C:comp-filter>
+ </C:filter>
+ </C:calendar-query>
+
+ >> Response <<
+
+ HTTP/1.1 207 Multi-Status
+ Date: Sat, 11 Nov 2006 09:32:12 GMT
+ Content-Type: application/xml; charset="utf-8"
+ Content-Length: xxxx
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 39]</span>
+</pre><pre class="newpage"><a name="page-40" id="page-40" href="#page-40" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ <?xml version="1.0" encoding="utf-8" ?>
+ <D:multistatus xmlns:D="DAV:"
+ xmlns:C="urn:ietf:params:xml:ns:caldav">
+ <D:response>
+ <D:href>http://cal.example.com/bernard/work/abcd2.ics</D:href>
+ <D:propstat>
+ <D:prop>
+ <D:getetag>"fffff-abcd2"</D:getetag>
+ <C:calendar-data>BEGIN:VCALENDAR
+ VERSION:2.0
+ BEGIN:VTIMEZONE
+ LAST-MODIFIED:20040110T032845Z
+ TZID:US/Eastern
+ BEGIN:DAYLIGHT
+ DTSTART:20000404T020000
+ RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+ TZNAME:EDT
+ TZOFFSETFROM:-0500
+ TZOFFSETTO:-0400
+ END:DAYLIGHT
+ BEGIN:STANDARD
+ DTSTART:20001026T020000
+ RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+ TZNAME:EST
+ TZOFFSETFROM:-0400
+ TZOFFSETTO:-0500
+ END:STANDARD
+ END:VTIMEZONE
+ BEGIN:VEVENT
+ DTSTART;TZID=US/Eastern:20060102T120000
+ DURATION:PT1H
+ RRULE:FREQ=DAILY;COUNT=5
+ SUMMARY:Event #2
+ UID:00959BC664CA650E933C892C@example.com
+ END:VEVENT
+ BEGIN:VEVENT
+ DTSTART;TZID=US/Eastern:20060104T140000
+ DURATION:PT1H
+ RECURRENCE-ID;TZID=US/Eastern:20060104T120000
+ SUMMARY:Event #2 bis
+ UID:00959BC664CA650E933C892C@example.com
+ END:VEVENT
+ BEGIN:VEVENT
+ DTSTART;TZID=US/Eastern:20060106T140000
+ DURATION:PT1H
+ RECURRENCE-ID;TZID=US/Eastern:20060106T120000
+ SUMMARY:Event #2 bis bis
+ UID:00959BC664CA650E933C892C@example.com
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 40]</span>
+</pre><pre class="newpage"><a name="page-41" id="page-41" href="#page-41" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ END:VEVENT
+ END:VCALENDAR
+ </C:calendar-data>
+ </D:prop>
+ <D:status>HTTP/1.1 200 OK</D:status>
+ </D:propstat>
+ </D:response>
+ <D:response>
+ <D:href>http://cal.example.com/bernard/work/abcd3.ics</D:href>
+ <D:propstat>
+ <D:prop>
+ <D:getetag>"fffff-abcd3"</D:getetag>
+ <C:calendar-data>BEGIN:VCALENDAR
+ VERSION:2.0
+ PRODID:-//Example Corp.//CalDAV Client//EN
+ BEGIN:VTIMEZONE
+ LAST-MODIFIED:20040110T032845Z
+ TZID:US/Eastern
+ BEGIN:DAYLIGHT
+ DTSTART:20000404T020000
+ RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+ TZNAME:EDT
+ TZOFFSETFROM:-0500
+ TZOFFSETTO:-0400
+ END:DAYLIGHT
+ BEGIN:STANDARD
+ DTSTART:20001026T020000
+ RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+ TZNAME:EST
+ TZOFFSETFROM:-0400
+ TZOFFSETTO:-0500
+ END:STANDARD
+ END:VTIMEZONE
+ BEGIN:VEVENT
+ DTSTART;TZID=US/Eastern:20060104T100000
+ DURATION:PT1H
+ SUMMARY:Event #3
+ UID:DC6C50A017428C5216A2F1CD@example.com
+ END:VEVENT
+ END:VCALENDAR
+ </C:calendar-data>
+ </D:prop>
+ <D:status>HTTP/1.1 200 OK</D:status>
+ </D:propstat>
+ </D:response>
+ </D:multistatus>
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 41]</span>
+</pre><pre class="newpage"><a name="page-42" id="page-42" href="#page-42" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+<span class="h4"><h4><a name="section-7.8.2">7.8.2</a>. Example: Partial Retrieval of Recurring Events</h4></span>
+
+ In this example, the client requests the server to return VEVENT
+ components that overlap the time range from January 3, 2006, at 00:
+ 00:00 A.M. UTC to January 5, 2006, at 00:00:00 A.M. UTC. Use of the
+ CALDAV:limit-recurrence-set element causes the server to only return
+ overridden recurrence components that overlap the time range
+ specified in that element or that affect other instances that overlap
+ the time range (e.g., in the case of a THISANDFUTURE behavior). In
+ this example, the first overridden component in the matching resource
+ is returned, but the second one is not.
+
+ See <a href="#appendix-B">Appendix B</a> for the calendar data being targeted by this example.
+
+ >> Request <<
+
+ REPORT /bernard/work/ HTTP/1.1
+ Host: cal.example.com
+ Depth: 1
+ Content-Type: application/xml; charset="utf-8"
+ Content-Length: xxxx
+
+ <?xml version="1.0" encoding="utf-8" ?>
+ <C:calendar-query xmlns:D="DAV:"
+ xmlns:C="urn:ietf:params:xml:ns:caldav">
+ <D:prop>
+ <C:calendar-data>
+ <C:limit-recurrence-set start="20060103T000000Z"
+ end="20060105T000000Z"/>
+ </C:calendar-data>
+ </D:prop>
+ <C:filter>
+ <C:comp-filter name="VCALENDAR">
+ <C:comp-filter name="VEVENT">
+ <C:time-range start="20060103T000000Z"
+ end="20060105T000000Z"/>
+ </C:comp-filter>
+ </C:comp-filter>
+ </C:filter>
+ </C:calendar-query>
+
+ >> Response <<
+
+ HTTP/1.1 207 Multi-Status
+ Date: Sat, 11 Nov 2006 09:32:12 GMT
+ Content-Type: application/xml; charset="utf-8"
+ Content-Length: xxxx
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 42]</span>
+</pre><pre class="newpage"><a name="page-43" id="page-43" href="#page-43" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ <?xml version="1.0" encoding="utf-8" ?>
+ <D:multistatus xmlns:D="DAV:"
+ xmlns:C="urn:ietf:params:xml:ns:caldav">
+ <D:response>
+ <D:href>http://cal.example.com/bernard/work/abcd2.ics</D:href>
+ <D:propstat>
+ <D:prop>
+ <D:getetag>"fffff-abcd2"</D:getetag>
+ <C:calendar-data>BEGIN:VCALENDAR
+ VERSION:2.0
+ PRODID:-//Example Corp.//CalDAV Client//EN
+ BEGIN:VTIMEZONE
+ LAST-MODIFIED:20040110T032845Z
+ TZID:US/Eastern
+ BEGIN:DAYLIGHT
+ DTSTART:20000404T020000
+ RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+ TZNAME:EDT
+ TZOFFSETFROM:-0500
+ TZOFFSETTO:-0400
+ END:DAYLIGHT
+ BEGIN:STANDARD
+ DTSTART:20001026T020000
+ RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+ TZNAME:EST
+ TZOFFSETFROM:-0400
+ TZOFFSETTO:-0500
+ END:STANDARD
+ END:VTIMEZONE
+ BEGIN:VEVENT
+ DTSTAMP:20060206T001121Z
+ DTSTART;TZID=US/Eastern:20060102T120000
+ DURATION:PT1H
+ RRULE:FREQ=DAILY;COUNT=5
+ SUMMARY:Event #2
+ UID:00959BC664CA650E933C892C@example.com
+ END:VEVENT
+ BEGIN:VEVENT
+ DTSTAMP:20060206T001121Z
+ DTSTART;TZID=US/Eastern:20060104T140000
+ DURATION:PT1H
+ RECURRENCE-ID;TZID=US/Eastern:20060104T120000
+ SUMMARY:Event #2 bis
+ UID:00959BC664CA650E933C892C@example.com
+ END:VEVENT
+ END:VCALENDAR
+ </C:calendar-data>
+ </D:prop>
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 43]</span>
+</pre><pre class="newpage"><a name="page-44" id="page-44" href="#page-44" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ <D:status>HTTP/1.1 200 OK</D:status>
+ </D:propstat>
+ </D:response>
+ <D:response>
+ <D:href>http://cal.example.com/bernard/work/abcd3.ics</D:href>
+ <D:propstat>
+ <D:prop>
+ <D:getetag>"fffff-abcd3"</D:getetag>
+ <C:calendar-data>BEGIN:VCALENDAR
+ VERSION:2.0
+ PRODID:-//Example Corp.//CalDAV Client//EN
+ BEGIN:VTIMEZONE
+ LAST-MODIFIED:20040110T032845Z
+ TZID:US/Eastern
+ BEGIN:DAYLIGHT
+ DTSTART:20000404T020000
+ RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+ TZNAME:EDT
+ TZOFFSETFROM:-0500
+ TZOFFSETTO:-0400
+ END:DAYLIGHT
+ BEGIN:STANDARD
+ DTSTART:20001026T020000
+ RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+ TZNAME:EST
+ TZOFFSETFROM:-0400
+ TZOFFSETTO:-0500
+ END:STANDARD
+ END:VTIMEZONE
+ BEGIN:VEVENT
+ ATTENDEE;PARTSTAT=ACCEPTED;ROLE=CHAIR:mailto:cyrus@example.com
+ ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:lisa@example.com
+ DTSTAMP:20060206T001220Z
+ DTSTART;TZID=US/Eastern:20060104T100000
+ DURATION:PT1H
+ LAST-MODIFIED:20060206T001330Z
+ ORGANIZER:mailto:cyrus@example.com
+ SEQUENCE:1
+ STATUS:TENTATIVE
+ SUMMARY:Event #3
+ UID:DC6C50A017428C5216A2F1CD@example.com
+ X-ABC-GUID:E1CX5Dr-0007ym-Hz@example.com
+ END:VEVENT
+ END:VCALENDAR
+ </C:calendar-data>
+ </D:prop>
+ <D:status>HTTP/1.1 200 OK</D:status>
+ </D:propstat>
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 44]</span>
+</pre><pre class="newpage"><a name="page-45" id="page-45" href="#page-45" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ </D:response>
+ </D:multistatus>
+
+<span class="h4"><h4><a name="section-7.8.3">7.8.3</a>. Example: Expanded Retrieval of Recurring Events</h4></span>
+
+ In this example, the client requests the server to return VEVENT
+ components that overlap the time range from January 2, 2006, at 00:
+ 00:00 A.M. UTC to January 5, 2006, at 00:00:00 A.M. UTC and to return
+ recurring calendar components expanded into individual recurrence
+ instance calendar components. Use of the CALDAV:expand element
+ causes the server to only return overridden recurrence instances that
+ overlap the time range specified in that element.
+
+ See <a href="#appendix-B">Appendix B</a> for the calendar data being targeted by this example.
+
+ >> Request <<
+
+ REPORT /bernard/work/ HTTP/1.1
+ Host: cal.example.com
+ Depth: 1
+ Content-Type: application/xml; charset="utf-8"
+ Content-Length: xxxx
+
+ <?xml version="1.0" encoding="utf-8" ?>
+ <C:calendar-query xmlns:D="DAV:"
+ xmlns:C="urn:ietf:params:xml:ns:caldav">
+ <D:prop>
+ <C:calendar-data>
+ <C:expand start="20060103T000000Z"
+ end="20060105T000000Z"/>
+ </C:calendar-data>
+ </D:prop>
+ <C:filter>
+ <C:comp-filter name="VCALENDAR">
+ <C:comp-filter name="VEVENT">
+ <C:time-range start="20060103T000000Z"
+ end="20060105T000000Z"/>
+ </C:comp-filter>
+ </C:comp-filter>
+ </C:filter>
+ </C:calendar-query>
+
+ >> Response <<
+
+ HTTP/1.1 207 Multi-Status
+ Date: Sat, 11 Nov 2006 09:32:12 GMT
+ Content-Type: application/xml; charset="utf-8"
+ Content-Length: xxxx
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 45]</span>
+</pre><pre class="newpage"><a name="page-46" id="page-46" href="#page-46" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ <?xml version="1.0" encoding="utf-8" ?>
+ <D:multistatus xmlns:D="DAV:"
+ xmlns:C="urn:ietf:params:xml:ns:caldav">
+ <D:response>
+ <D:href>http://cal.example.com/bernard/work/abcd2.ics</D:href>
+ <D:propstat>
+ <D:prop>
+ <D:getetag>"fffff-abcd2"</D:getetag>
+ <C:calendar-data>BEGIN:VCALENDAR
+ VERSION:2.0
+ PRODID:-//Example Corp.//CalDAV Client//EN
+ BEGIN:VEVENT
+ DTSTAMP:20060206T001121Z
+ DTSTART:20060103T170000
+ DURATION:PT1H
+ RECURRENCE-ID:20060103T170000
+ SUMMARY:Event #2
+ UID:00959BC664CA650E933C892C@example.com
+ END:VEVENT
+ BEGIN:VEVENT
+ DTSTAMP:20060206T001121Z
+ DTSTART:20060104T190000
+ DURATION:PT1H
+ RECURRENCE-ID:20060104T170000
+ SUMMARY:Event #2 bis
+ UID:00959BC664CA650E933C892C@example.com
+ END:VEVENT
+ END:VCALENDAR
+ </C:calendar-data>
+ </D:prop>
+ <D:status>HTTP/1.1 200 OK</D:status>
+ </D:propstat>
+ </D:response>
+ <D:response>
+ <D:href>http://cal.example.com/bernard/work/abcd3.ics</D:href>
+ <D:propstat>
+ <D:prop>
+ <D:getetag>"fffff-abcd3"</D:getetag>
+ <C:calendar-data>BEGIN:VCALENDAR
+ VERSION:2.0
+ PRODID:-//Example Corp.//CalDAV Client//EN
+ BEGIN:VEVENT
+ ATTENDEE;PARTSTAT=ACCEPTED;ROLE=CHAIR:mailto:cyrus@example.com
+ ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:lisa@example.com
+ DTSTAMP:20060206T001220Z
+ DTSTART:20060104T150000
+ DURATION:PT1H
+ LAST-MODIFIED:20060206T001330Z
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 46]</span>
+</pre><pre class="newpage"><a name="page-47" id="page-47" href="#page-47" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ ORGANIZER:mailto:cyrus@example.com
+ SEQUENCE:1
+ STATUS:TENTATIVE
+ SUMMARY:Event #3
+ UID:DC6C50A017428C5216A2F1CD@example.com
+ X-ABC-GUID:E1CX5Dr-0007ym-Hz@example.com
+ END:VEVENT
+ END:VCALENDAR
+ </C:calendar-data>
+ </D:prop>
+ <D:status>HTTP/1.1 200 OK</D:status>
+ </D:propstat>
+ </D:response>
+ </D:multistatus>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 47]</span>
+</pre><pre class="newpage"><a name="page-48" id="page-48" href="#page-48" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+<span class="h4"><h4><a name="section-7.8.4">7.8.4</a>. Example: Partial Retrieval of Stored Free Busy Components</h4></span>
+
+ In this example, the client requests the server to return the
+ VFREEBUSY components that have free busy information that overlap the
+ time range from January 2, 2006, at 00:00:00 A.M. UTC (inclusively)
+ to January 3, 2006, at 00:00:00 A.M. UTC (exclusively). Use of the
+ CALDAV:limit-freebusy-set element causes the server to only return
+ the FREEBUSY property values that overlap the time range specified in
+ that element. Note that this is not an example of discovering when
+ the calendar owner is busy.
+
+ See <a href="#appendix-B">Appendix B</a> for the calendar data being targeted by this example.
+
+ >> Request <<
+
+ REPORT /bernard/work/ HTTP/1.1
+ Host: cal.example.com
+ Depth: 1
+ Content-Type: application/xml; charset="utf-8"
+ Content-Length: xxxx
+
+ <?xml version="1.0" encoding="utf-8" ?>
+ <C:calendar-query xmlns:D="DAV:"
+ xmlns:C="urn:ietf:params:xml:ns:caldav">
+ <D:prop>
+ <C:calendar-data>
+ <C:limit-freebusy-set start="20060102T000000Z"
+ end="20060103T000000Z"/>
+ </C:calendar-data>
+ </D:prop>
+ <C:filter>
+ <C:comp-filter name="VCALENDAR">
+ <C:comp-filter name="VFREEBUSY">
+ <C:time-range start="20060102T000000Z"
+ end="20060103T000000Z"/>
+ </C:comp-filter>
+ </C:comp-filter>
+ </C:filter>
+ </C:calendar-query>
+
+
+
+
+
+
+
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 48]</span>
+</pre><pre class="newpage"><a name="page-49" id="page-49" href="#page-49" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ >> Response <<
+
+ HTTP/1.1 207 Multi-Status
+ Date: Sat, 11 Nov 2006 09:32:12 GMT
+ Content-Type: application/xml; charset="utf-8"
+ Content-Length: xxxx
+
+ <?xml version="1.0" encoding="utf-8" ?>
+ <D:multistatus xmlns:D="DAV:"
+ xmlns:C="urn:ietf:params:xml:ns:caldav">
+ <D:response>
+ <D:href>http://cal.example.com/bernard/work/abcd8.ics</D:href>
+ <D:propstat>
+ <D:prop>
+ <D:getetag>"fffff-abcd8"</D:getetag>
+ <C:calendar-data>BEGIN:VCALENDAR
+ VERSION:2.0
+ PRODID:-//Example Corp.//CalDAV Client//EN
+ BEGIN:VFREEBUSY
+ ORGANIZER;CN="Bernard Desruisseaux":mailto:bernard@example.com
+ UID:76ef34-54a3d2@example.com
+ DTSTAMP:20050530T123421Z
+ DTSTART:20060101T100000Z
+ DTEND:20060108T100000Z
+ FREEBUSY;FBTYPE=BUSY-TENTATIVE:20060102T100000Z/20060102T120000Z
+ END:VFREEBUSY
+ END:VCALENDAR
+ </C:calendar-data>
+ </D:prop>
+ <D:status>HTTP/1.1 200 OK</D:status>
+ </D:propstat>
+ </D:response>
+ </D:multistatus>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 49]</span>
+</pre><pre class="newpage"><a name="page-50" id="page-50" href="#page-50" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+<span class="h4"><h4><a name="section-7.8.5">7.8.5</a>. Example: Retrieval of To-Dos by Alarm Time Range</h4></span>
+
+ In this example, the client requests the server to return the VTODO
+ components that have an alarm trigger scheduled in the specified time
+ range.
+
+ See <a href="#appendix-B">Appendix B</a> for the calendar data being targeted by this example.
+
+ >> Request <<
+
+ REPORT /bernard/work/ HTTP/1.1
+ Host: cal.example.com
+ Depth: 1
+ Content-Type: application/xml; charset="utf-8"
+ Content-Length: xxxx
+
+ <?xml version="1.0" encoding="utf-8" ?>
+ <C:calendar-query xmlns:C="urn:ietf:params:xml:ns:caldav">
+ <D:prop xmlns:D="DAV:">
+ <D:getetag/>
+ <C:calendar-data/>
+ </D:prop>
+ <C:filter>
+ <C:comp-filter name="VCALENDAR">
+ <C:comp-filter name="VTODO">
+ <C:comp-filter name="VALARM">
+ <C:time-range start="20060106T100000Z"
+ end="20060107T100000Z"/>
+ </C:comp-filter>
+ </C:comp-filter>
+ </C:comp-filter>
+ </C:filter>
+ </C:calendar-query>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 50]</span>
+</pre><pre class="newpage"><a name="page-51" id="page-51" href="#page-51" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ >> Response <<
+
+ HTTP/1.1 207 Multi-Status
+ Date: Sat, 11 Nov 2006 09:32:12 GMT
+ Content-Type: application/xml; charset="utf-8"
+ Content-Length: xxxx
+
+ <?xml version="1.0" encoding="utf-8" ?>
+ <D:multistatus xmlns:D="DAV:"
+ xmlns:C="urn:ietf:params:xml:ns:caldav">
+ <D:response>
+ <D:href>http://cal.example.com/bernard/work/abcd4.ics</D:href>
+ <D:propstat>
+ <D:prop>
+ <D:getetag>"fffff-abcd4"</D:getetag>
+ <C:calendar-data>BEGIN:VCALENDAR
+ VERSION:2.0
+ PRODID:-//Example Corp.//CalDAV Client//EN
+ BEGIN:VTODO
+ DTSTAMP:20060205T235300Z
+ DUE;TZID=US/Eastern:20060106T120000
+ LAST-MODIFIED:20060205T235308Z
+ SEQUENCE:1
+ STATUS:NEEDS-ACTION
+ SUMMARY:Task #2
+ UID:E10BA47467C5C69BB74E8720@example.com
+ BEGIN:VALARM
+ ACTION:AUDIO
+ TRIGGER;RELATED=START:-PT10M
+ END:VALARM
+ END:VTODO
+ END:VCALENDAR
+ </C:calendar-data>
+ </D:prop>
+ <D:status>HTTP/1.1 200 OK</D:status>
+ </D:propstat>
+ </D:response>
+ </D:multistatus>
+
+<span class="h4"><h4><a name="section-7.8.6">7.8.6</a>. Example: Retrieval of Event by UID</h4></span>
+
+ In this example, the client requests the server to return the VEVENT
+ component that has the UID property set to
+ "DC6C50A017428C5216A2F1CD@example.com".
+
+ See <a href="#appendix-B">Appendix B</a> for the calendar data being targeted by this example.
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 51]</span>
+</pre><pre class="newpage"><a name="page-52" id="page-52" href="#page-52" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ >> Request <<
+
+ REPORT /bernard/work/ HTTP/1.1
+ Host: cal.example.com
+ Depth: 1
+ Content-Type: application/xml; charset="utf-8"
+ Content-Length: xxxx
+
+ <?xml version="1.0" encoding="utf-8" ?>
+ <C:calendar-query xmlns:C="urn:ietf:params:xml:ns:caldav">
+ <D:prop xmlns:D="DAV:">
+ <D:getetag/>
+ <C:calendar-data/>
+ </D:prop>
+ <C:filter>
+ <C:comp-filter name="VCALENDAR">
+ <C:comp-filter name="VEVENT">
+ <C:prop-filter name="UID">
+ <C:text-match collation="i;octet"
+ >DC6C50A017428C5216A2F1CD@example.com</C:text-match>
+ </C:prop-filter>
+ </C:comp-filter>
+ </C:comp-filter>
+ </C:filter>
+ </C:calendar-query>
+
+ >> Response <<
+
+ HTTP/1.1 207 Multi-Status
+ Date: Sat, 11 Nov 2006 09:32:12 GMT
+ Content-Type: application/xml; charset="utf-8"
+ Content-Length: xxxx
+
+ <?xml version="1.0" encoding="utf-8" ?>
+ <D:multistatus xmlns:D="DAV:"
+ xmlns:C="urn:ietf:params:xml:ns:caldav">
+ <D:response>
+ <D:href>http://cal.example.com/bernard/work/abcd3.ics</D:href>
+ <D:propstat>
+ <D:prop>
+ <D:getetag>"fffff-abcd3"</D:getetag>
+ <C:calendar-data>BEGIN:VCALENDAR
+ VERSION:2.0
+ PRODID:-//Example Corp.//CalDAV Client//EN
+ BEGIN:VTIMEZONE
+ LAST-MODIFIED:20040110T032845Z
+ TZID:US/Eastern
+ BEGIN:DAYLIGHT
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 52]</span>
+</pre><pre class="newpage"><a name="page-53" id="page-53" href="#page-53" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ DTSTART:20000404T020000
+ RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+ TZNAME:EDT
+ TZOFFSETFROM:-0500
+ TZOFFSETTO:-0400
+ END:DAYLIGHT
+ BEGIN:STANDARD
+ DTSTART:20001026T020000
+ RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+ TZNAME:EST
+ TZOFFSETFROM:-0400
+ TZOFFSETTO:-0500
+ END:STANDARD
+ END:VTIMEZONE
+ BEGIN:VEVENT
+ ATTENDEE;PARTSTAT=ACCEPTED;ROLE=CHAIR:mailto:cyrus@example.com
+ ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:lisa@example.com
+ DTSTAMP:20060206T001220Z
+ DTSTART;TZID=US/Eastern:20060104T100000
+ DURATION:PT1H
+ LAST-MODIFIED:20060206T001330Z
+ ORGANIZER:mailto:cyrus@example.com
+ SEQUENCE:1
+ STATUS:TENTATIVE
+ SUMMARY:Event #3
+ UID:DC6C50A017428C5216A2F1CD@example.com
+ X-ABC-GUID:E1CX5Dr-0007ym-Hz@example.com
+ END:VEVENT
+ END:VCALENDAR
+ </C:calendar-data>
+ </D:prop>
+ <D:status>HTTP/1.1 200 OK</D:status>
+ </D:propstat>
+ </D:response>
+ </D:multistatus>
+
+<span class="h4"><h4><a name="section-7.8.7">7.8.7</a>. Example: Retrieval of Events by PARTSTAT</h4></span>
+
+ In this example, the client requests the server to return the VEVENT
+ components that have the ATTENDEE property with the value
+ "mailto:lisa@example.com" and for which the PARTSTAT parameter is set
+ to NEEDS-ACTION.
+
+ See <a href="#appendix-B">Appendix B</a> for the calendar data being targeted by this example.
+
+
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 53]</span>
+</pre><pre class="newpage"><a name="page-54" id="page-54" href="#page-54" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ >> Request <<
+
+ REPORT /bernard/work/ HTTP/1.1
+ Host: cal.example.com
+ Depth: 1
+ Content-Type: application/xml; charset="utf-8"
+ Content-Length: xxxx
+
+ <?xml version="1.0" encoding="utf-8" ?>
+ <C:calendar-query xmlns:C="urn:ietf:params:xml:ns:caldav">
+ <D:prop xmlns:D="DAV:">
+ <D:getetag/>
+ <C:calendar-data/>
+ </D:prop>
+ <C:filter>
+ <C:comp-filter name="VCALENDAR">
+ <C:comp-filter name="VEVENT">
+ <C:prop-filter name="ATTENDEE">
+ <C:text-match collation="i;ascii-casemap"
+ >mailto:lisa@example.com</C:text-match>
+ <C:param-filter name="PARTSTAT">
+ <C:text-match collation="i;ascii-casemap"
+ >NEEDS-ACTION</C:text-match>
+ </C:param-filter>
+ </C:prop-filter>
+ </C:comp-filter>
+ </C:comp-filter>
+ </C:filter>
+ </C:calendar-query>
+
+ >> Response <<
+
+ HTTP/1.1 207 Multi-Status
+ Date: Sat, 11 Nov 2006 09:32:12 GMT
+ Content-Type: application/xml; charset="utf-8"
+ Content-Length: xxxx
+
+ <?xml version="1.0" encoding="utf-8" ?>
+ <D:multistatus xmlns:D="DAV:"
+ xmlns:C="urn:ietf:params:xml:ns:caldav">
+ <D:response>
+ <D:href>http://cal.example.com/bernard/work/abcd3.ics</D:href>
+ <D:propstat>
+ <D:prop>
+ <D:getetag>"fffff-abcd3"</D:getetag>
+ <C:calendar-data>BEGIN:VCALENDAR
+ VERSION:2.0
+ PRODID:-//Example Corp.//CalDAV Client//EN
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 54]</span>
+</pre><pre class="newpage"><a name="page-55" id="page-55" href="#page-55" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ BEGIN:VTIMEZONE
+ LAST-MODIFIED:20040110T032845Z
+ TZID:US/Eastern
+ BEGIN:DAYLIGHT
+ DTSTART:20000404T020000
+ RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+ TZNAME:EDT
+ TZOFFSETFROM:-0500
+ TZOFFSETTO:-0400
+ END:DAYLIGHT
+ BEGIN:STANDARD
+ DTSTART:20001026T020000
+ RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+ TZNAME:EST
+ TZOFFSETFROM:-0400
+ TZOFFSETTO:-0500
+ END:STANDARD
+ END:VTIMEZONE
+ BEGIN:VEVENT
+ ATTENDEE;PARTSTAT=ACCEPTED;ROLE=CHAIR:mailto:cyrus@example.com
+ ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:lisa@example.com
+ DTSTAMP:20060206T001220Z
+ DTSTART;TZID=US/Eastern:20060104T100000
+ DURATION:PT1H
+ LAST-MODIFIED:20060206T001330Z
+ ORGANIZER:mailto:cyrus@example.com
+ SEQUENCE:1
+ STATUS:TENTATIVE
+ SUMMARY:Event #3
+ UID:DC6C50A017428C5216A2F1CD@example.com
+ X-ABC-GUID:E1CX5Dr-0007ym-Hz@example.com
+ END:VEVENT
+ END:VCALENDAR
+ </C:calendar-data>
+ </D:prop>
+ <D:status>HTTP/1.1 200 OK</D:status>
+ </D:propstat>
+ </D:response>
+ </D:multistatus>
+
+<span class="h4"><h4><a name="section-7.8.8">7.8.8</a>. Example: Retrieval of Events Only</h4></span>
+
+ In this example, the client requests the server to return all VEVENT
+ components.
+
+ See <a href="#appendix-B">Appendix B</a> for the calendar data being targeted by this example.
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 55]</span>
+</pre><pre class="newpage"><a name="page-56" id="page-56" href="#page-56" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ >> Request <<
+
+ REPORT /bernard/work/ HTTP/1.1
+ Host: cal.example.com
+ Depth: 1
+ Content-Type: application/xml; charset="utf-8"
+ Content-Length: xxxx
+
+ <?xml version="1.0" encoding="utf-8" ?>
+ <C:calendar-query xmlns:C="urn:ietf:params:xml:ns:caldav">
+ <D:prop xmlns:D="DAV:">
+ <D:getetag/>
+ <C:calendar-data/>
+ </D:prop>
+ <C:filter>
+ <C:comp-filter name="VCALENDAR">
+ <C:comp-filter name="VEVENT"/>
+ </C:comp-filter>
+ </C:filter>
+ </C:calendar-query>
+
+ >> Response <<
+
+ HTTP/1.1 207 Multi-Status
+ Date: Sat, 11 Nov 2006 09:32:12 GMT
+ Content-Type: application/xml; charset="utf-8"
+ Content-Length: xxxx
+
+ <?xml version="1.0" encoding="utf-8" ?>
+ <D:multistatus xmlns:D="DAV:"
+ xmlns:C="urn:ietf:params:xml:ns:caldav">
+ <D:response>
+ <D:href>http://cal.example.com/bernard/work/abcd1.ics</D:href>
+ <D:propstat>
+ <D:prop>
+ <D:getetag>"fffff-abcd1"</D:getetag>
+ <C:calendar-data>BEGIN:VCALENDAR
+ VERSION:2.0
+ PRODID:-//Example Corp.//CalDAV Client//EN
+ BEGIN:VTIMEZONE
+ LAST-MODIFIED:20040110T032845Z
+ TZID:US/Eastern
+ BEGIN:DAYLIGHT
+ DTSTART:20000404T020000
+ RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+ TZNAME:EDT
+ TZOFFSETFROM:-0500
+ TZOFFSETTO:-0400
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 56]</span>
+</pre><pre class="newpage"><a name="page-57" id="page-57" href="#page-57" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ END:DAYLIGHT
+ BEGIN:STANDARD
+ DTSTART:20001026T020000
+ RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+ TZNAME:EST
+ TZOFFSETFROM:-0400
+ TZOFFSETTO:-0500
+ END:STANDARD
+ END:VTIMEZONE
+ BEGIN:VEVENT
+ DTSTAMP:20060206T001102Z
+ DTSTART;TZID=US/Eastern:20060102T100000
+ DURATION:PT1H
+ SUMMARY:Event #1
+ Description:Go Steelers!
+ UID:74855313FA803DA593CD579A@example.com
+ END:VEVENT
+ END:VCALENDAR
+ </C:calendar-data>
+ </D:prop>
+ <D:status>HTTP/1.1 200 OK</D:status>
+ </D:propstat>
+ </D:response>
+ <D:response>
+ <D:href>http://cal.example.com/bernard/work/abcd2.ics</D:href>
+ <D:propstat>
+ <D:prop>
+ <D:getetag>"fffff-abcd2"</D:getetag>
+ <C:calendar-data>BEGIN:VCALENDAR
+ VERSION:2.0
+ PRODID:-//Example Corp.//CalDAV Client//EN
+ BEGIN:VTIMEZONE
+ LAST-MODIFIED:20040110T032845Z
+ TZID:US/Eastern
+ BEGIN:DAYLIGHT
+ DTSTART:20000404T020000
+ RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+ TZNAME:EDT
+ TZOFFSETFROM:-0500
+ TZOFFSETTO:-0400
+ END:DAYLIGHT
+ BEGIN:STANDARD
+ DTSTART:20001026T020000
+ RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+ TZNAME:EST
+ TZOFFSETFROM:-0400
+ TZOFFSETTO:-0500
+ END:STANDARD
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 57]</span>
+</pre><pre class="newpage"><a name="page-58" id="page-58" href="#page-58" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ END:VTIMEZONE
+ BEGIN:VEVENT
+ DTSTAMP:20060206T001121Z
+ DTSTART;TZID=US/Eastern:20060102T120000
+ DURATION:PT1H
+ RRULE:FREQ=DAILY;COUNT=5
+ SUMMARY:Event #2
+ UID:00959BC664CA650E933C892C@example.com
+ END:VEVENT
+ BEGIN:VEVENT
+ DTSTAMP:20060206T001121Z
+ DTSTART;TZID=US/Eastern:20060104T140000
+ DURATION:PT1H
+ RECURRENCE-ID;TZID=US/Eastern:20060104T120000
+ SUMMARY:Event #2 bis
+ UID:00959BC664CA650E933C892C@example.com
+ END:VEVENT
+ BEGIN:VEVENT
+ DTSTAMP:20060206T001121Z
+ DTSTART;TZID=US/Eastern:20060106T140000
+ DURATION:PT1H
+ RECURRENCE-ID;TZID=US/Eastern:20060106T120000
+ SUMMARY:Event #2 bis bis
+ UID:00959BC664CA650E933C892C@example.com
+ END:VEVENT
+ END:VCALENDAR
+ </C:calendar-data>
+ </D:prop>
+ <D:status>HTTP/1.1 200 OK</D:status>
+ </D:propstat>
+ </D:response>
+ <D:response>
+ <D:href>http://cal.example.com/bernard/work/abcd3.ics</D:href>
+ <D:propstat>
+ <D:prop>
+ <D:getetag>"fffff-abcd3"</D:getetag>
+ <C:calendar-data>BEGIN:VCALENDAR
+ VERSION:2.0
+ PRODID:-//Example Corp.//CalDAV Client//EN
+ BEGIN:VTIMEZONE
+ LAST-MODIFIED:20040110T032845Z
+ TZID:US/Eastern
+ BEGIN:DAYLIGHT
+ DTSTART:20000404T020000
+ RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+ TZNAME:EDT
+ TZOFFSETFROM:-0500
+ TZOFFSETTO:-0400
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 58]</span>
+</pre><pre class="newpage"><a name="page-59" id="page-59" href="#page-59" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ END:DAYLIGHT
+ BEGIN:STANDARD
+ DTSTART:20001026T020000
+ RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+ TZNAME:EST
+ TZOFFSETFROM:-0400
+ TZOFFSETTO:-0500
+ END:STANDARD
+ END:VTIMEZONE
+ BEGIN:VEVENT
+ ATTENDEE;PARTSTAT=ACCEPTED;ROLE=CHAIR:mailto:cyrus@example.com
+ ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:lisa@example.com
+ DTSTAMP:20060206T001220Z
+ DTSTART;TZID=US/Eastern:20060104T100000
+ DURATION:PT1H
+ LAST-MODIFIED:20060206T001330Z
+ ORGANIZER:mailto:cyrus@example.com
+ SEQUENCE:1
+ STATUS:TENTATIVE
+ SUMMARY:Event #3
+ UID:DC6C50A017428C5216A2F1CD@example.com
+ X-ABC-GUID:E1CX5Dr-0007ym-Hz@example.com
+ END:VEVENT
+ END:VCALENDAR
+ </C:calendar-data>
+ </D:prop>
+ <D:status>HTTP/1.1 200 OK</D:status>
+ </D:propstat>
+ </D:response>
+ </D:multistatus>
+
+<span class="h4"><h4><a name="section-7.8.9">7.8.9</a>. Example: Retrieval of All Pending To-Dos</h4></span>
+
+ In this example, the client requests the server to return all VTODO
+ components that do not include a COMPLETED property and do not have a
+ STATUS property value matching CANCELLED, i.e., VTODOs that still
+ need to be worked on.
+
+ See <a href="#appendix-B">Appendix B</a> for the calendar data being targeted by this example.
+
+
+
+
+
+
+
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 59]</span>
+</pre><pre class="newpage"><a name="page-60" id="page-60" href="#page-60" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ >> Request <<
+
+ REPORT /bernard/work/ HTTP/1.1
+ Host: cal.example.com
+ Depth: 1
+ Content-Type: application/xml; charset="utf-8"
+ Content-Length: xxxx
+
+ <?xml version="1.0" encoding="utf-8" ?>
+ <C:calendar-query xmlns:C="urn:ietf:params:xml:ns:caldav">
+ <D:prop xmlns:D="DAV:">
+ <D:getetag/>
+ <C:calendar-data/>
+ </D:prop>
+ <C:filter>
+ <C:comp-filter name="VCALENDAR">
+ <C:comp-filter name="VTODO">
+ <C:prop-filter name="COMPLETED">
+ <C:is-not-defined/>
+ </C:prop-filter>
+ <C:prop-filter name="STATUS">
+ <C:text-match
+ negate-condition="yes">CANCELLED</C:text-match>
+ </C:prop-filter>
+ </C:comp-filter>
+ </C:comp-filter>
+ </C:filter>
+ </C:calendar-query>
+
+ >> Response <<
+
+ HTTP/1.1 207 Multi-Status
+ Date: Sat, 11 Nov 2006 09:32:12 GMT
+ Content-Type: application/xml; charset="utf-8"
+ Content-Length: xxxx
+
+ <?xml version="1.0" encoding="utf-8" ?>
+ <D:multistatus xmlns:D="DAV:"
+ xmlns:C="urn:ietf:params:xml:ns:caldav">
+ <D:response>
+ <D:href>http://cal.example.com/bernard/work/abcd4.ics</D:href>
+ <D:propstat>
+ <D:prop>
+ <D:getetag>"fffff-abcd4"</D:getetag>
+ <C:calendar-data>BEGIN:VCALENDAR
+ VERSION:2.0
+ PRODID:-//Example Corp.//CalDAV Client//EN
+ BEGIN:VTODO
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 60]</span>
+</pre><pre class="newpage"><a name="page-61" id="page-61" href="#page-61" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ DTSTAMP:20060205T235335Z
+ DUE;VALUE=DATE:20060104
+ STATUS:NEEDS-ACTION
+ SUMMARY:Task #1
+ UID:DDDEEB7915FA61233B861457@example.com
+ BEGIN:VALARM
+ ACTION:AUDIO
+ TRIGGER;RELATED=START:-PT10M
+ END:VALARM
+ END:VTODO
+ END:VCALENDAR
+ </C:calendar-data>
+ </D:prop>
+ <D:status>HTTP/1.1 200 OK</D:status>
+ </D:propstat>
+ </D:response>
+
+ <D:response>
+ <D:href>http://cal.example.com/bernard/work/abcd5.ics</D:href>
+ <D:propstat>
+ <D:prop>
+ <D:getetag>"fffff-abcd5"</D:getetag>
+ <C:calendar-data>BEGIN:VCALENDAR
+ VERSION:2.0
+ PRODID:-//Example Corp.//CalDAV Client//EN
+ BEGIN:VTODO
+ DTSTAMP:20060205T235300Z
+ DUE;VALUE=DATE:20060106
+ LAST-MODIFIED:20060205T235308Z
+ SEQUENCE:1
+ STATUS:NEEDS-ACTION
+ SUMMARY:Task #2
+ UID:E10BA47467C5C69BB74E8720@example.com
+ BEGIN:VALARM
+ ACTION:AUDIO
+ TRIGGER;RELATED=START:-PT10M
+ END:VALARM
+ END:VTODO
+ END:VCALENDAR
+ </C:calendar-data>
+ </D:prop>
+ <D:status>HTTP/1.1 200 OK</D:status>
+ </D:propstat>
+ </D:response>
+ </D:multistatus>
+
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 61]</span>
+</pre><pre class="newpage"><a name="page-62" id="page-62" href="#page-62" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+<span class="h4"><h4><a name="section-7.8.10">7.8.10</a>. Example: Attempt to Query Unsupported Property</h4></span>
+
+ In this example, the client requests the server to return all VEVENT
+ components that include an X-ABC-GUID property with a value matching
+ "ABC". However, the server does not support querying that non-
+ standard property, and instead returns an error response.
+
+ See <a href="#appendix-B">Appendix B</a> for the calendar data being targeted by this example.
+
+ >> Request <<
+
+ REPORT /bernard/work/ HTTP/1.1
+ Host: cal.example.com
+ Depth: 1
+ Content-Type: application/xml; charset="utf-8"
+ Content-Length: xxxx
+
+ <?xml version="1.0" encoding="utf-8" ?>
+ <C:calendar-query xmlns:C="urn:ietf:params:xml:ns:caldav">
+ <D:prop xmlns:D="DAV:">
+ <D:getetag/>
+ <C:calendar-data/>
+ </D:prop>
+ <C:filter>
+ <C:comp-filter name="VCALENDAR">
+ <C:comp-filter name="VEVENT">
+ <C:prop-filter name="X-ABC-GUID">
+ <C:text-match>ABC</C:text-match>
+ </C:prop-filter>
+ </C:comp-filter>
+ </C:comp-filter>
+ </C:filter>
+ </C:calendar-query>
+
+ >> Response <<
+
+ HTTP/1.1 403 Forbidden
+ Date: Sat, 11 Nov 2005 09:32:12 GMT
+ Content-Type: application/xml; charset="utf-8"
+ Content-Length: xxxx
+
+ <?xml version="1.0" encoding="utf-8" ?>
+ <D:error>
+ <C:supported-filter>
+ <C:prop-filter name="X-ABC-GUID"/>
+ </C:supported-filter>
+ </D:error>
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 62]</span>
+</pre><pre class="newpage"><a name="page-63" id="page-63" href="#page-63" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+<span class="h3"><h3><a name="section-7.9">7.9</a>. CALDAV:calendar-multiget REPORT</h3></span>
+
+ The CALDAV:calendar-multiget REPORT is used to retrieve specific
+ calendar object resources from within a collection, if the Request-
+ URI is a collection, or to retrieve a specific calendar object
+ resource, if the Request-URI is a calendar object resource. This
+ report is similar to the CALDAV:calendar-query REPORT (see
+ <a href="#section-7.8">Section 7.8</a>), except that it takes a list of DAV:href elements,
+ instead of a CALDAV:filter element, to determine which calendar
+ object resources to return.
+
+ Support for the CALDAV:calendar-multiget REPORT is REQUIRED.
+
+ Marshalling:
+
+ The request body MUST be a CALDAV:calendar-multiget XML element
+ (see <a href="#section-9.10">Section 9.10</a>). If the Request-URI is a collection resource,
+ then the DAV:href elements MUST refer to calendar object resources
+ within that collection, and they MAY refer to calendar object
+ resources at any depth within the collection. As a result, the
+ "Depth" header MUST be ignored by the server and SHOULD NOT be
+ sent by the client. If the Request-URI refers to a non-collection
+ resource, then there MUST be a single DAV:href element that is
+ equivalent to the Request-URI.
+
+ The response body for a successful request MUST be a DAV:
+ multistatus XML element.
+
+ The response body for a successful CALDAV:calendar-multiget REPORT
+ request MUST contain a DAV:response element for each calendar
+ object resource referenced by the provided set of DAV:href
+ elements. Calendar data is being returned in the CALDAV:calendar-
+ data element inside the DAV:prop element.
+
+ In the case of an error accessing any of the provided DAV:href
+ resources, the server MUST return the appropriate error status
+ code in the DAV:status element of the corresponding DAV:response
+ element.
+
+ Preconditions:
+
+ (CALDAV:supported-calendar-data): The attributes "content-type"
+ and "version" of the CALDAV:calendar-data XML elements (see
+ <a href="#section-9.6">Section 9.6</a>) specify a media type supported by the server for
+ calendar object resources.
+
+ (CALDAV:min-date-time): Any XML element specifying a range of time
+ MUST have its start or end DATE or DATE-TIME values greater than
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 63]</span>
+</pre><pre class="newpage"><a name="page-64" id="page-64" href="#page-64" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ or equal to the value of the CALDAV:min-date-time property value
+ (<a href="#section-5.2.6">Section 5.2.6</a>) on the calendar collections being targeted by the
+ REPORT request;
+
+ (CALDAV:max-date-time): Any XML element specifying a range of time
+ MUST have its start or end DATE or DATE-TIME values less than or
+ equal to the value of the CALDAV:max-date-time property value
+ (<a href="#section-5.2.7">Section 5.2.7</a>) on the calendar collections being targeted by the
+ REPORT request;
+
+ Postconditions:
+
+ None.
+
+<span class="h4"><h4><a name="section-7.9.1">7.9.1</a>. Example: Successful CALDAV:calendar-multiget REPORT</h4></span>
+
+ In this example, the client requests the server to return specific
+ properties of the VEVENT components referenced by specific URIs. In
+ addition, the DAV:getetag property is also requested and returned as
+ part of the response. Note that in this example, the resource at
+ http://cal.example.com/bernard/work/mtg1.ics does not exist,
+ resulting in an error status response.
+
+ See <a href="#appendix-B">Appendix B</a> for the calendar data being targeted by this example.
+
+ >> Request <<
+
+ REPORT /bernard/work/ HTTP/1.1
+ Host: cal.example.com
+ Content-Type: application/xml; charset="utf-8"
+ Content-Length: xxxx
+
+ <?xml version="1.0" encoding="utf-8" ?>
+ <C:calendar-multiget xmlns:D="DAV:"
+ xmlns:C="urn:ietf:params:xml:ns:caldav">
+ <D:prop>
+ <D:getetag/>
+ <C:calendar-data/>
+ </D:prop>
+ <D:href>/bernard/work/abcd1.ics</D:href>
+ <D:href>/bernard/work/mtg1.ics</D:href>
+ </C:calendar-multiget>
+
+ >> Response <<
+
+ HTTP/1.1 207 Multi-Status
+ Date: Sat, 11 Nov 2006 09:32:12 GMT
+ Content-Type: application/xml; charset="utf-8"
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 64]</span>
+</pre><pre class="newpage"><a name="page-65" id="page-65" href="#page-65" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ Content-Length: xxxx
+
+ <?xml version="1.0" encoding="utf-8" ?>
+ <D:multistatus xmlns:D="DAV:"
+ xmlns:C="urn:ietf:params:xml:ns:caldav">
+ <D:response>
+ <D:href>http://cal.example.com/bernard/work/abcd1.ics</D:href>
+ <D:propstat>
+ <D:prop>
+ <D:getetag>"fffff-abcd1"</D:getetag>
+ <C:calendar-data>BEGIN:VCALENDAR
+ VERSION:2.0
+ PRODID:-//Example Corp.//CalDAV Client//EN
+ BEGIN:VTIMEZONE
+ LAST-MODIFIED:20040110T032845Z
+ TZID:US/Eastern
+ BEGIN:DAYLIGHT
+ DTSTART:20000404T020000
+ RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+ TZNAME:EDT
+ TZOFFSETFROM:-0500
+ TZOFFSETTO:-0400
+ END:DAYLIGHT
+ BEGIN:STANDARD
+ DTSTART:20001026T020000
+ RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+ TZNAME:EST
+ TZOFFSETFROM:-0400
+ TZOFFSETTO:-0500
+ END:STANDARD
+ END:VTIMEZONE
+ BEGIN:VEVENT
+ DTSTAMP:20060206T001102Z
+ DTSTART;TZID=US/Eastern:20060102T100000
+ DURATION:PT1H
+ SUMMARY:Event #1
+ Description:Go Steelers!
+ UID:74855313FA803DA593CD579A@example.com
+ END:VEVENT
+ END:VCALENDAR
+ </C:calendar-data>
+ </D:prop>
+ <D:status>HTTP/1.1 200 OK</D:status>
+ </D:propstat>
+ </D:response>
+ <D:response>
+ <D:href>http://cal.example.com/bernard/work/mtg1.ics</D:href>
+ <D:status>HTTP/1.1 404 Not Found</D:status>
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 65]</span>
+</pre><pre class="newpage"><a name="page-66" id="page-66" href="#page-66" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ </D:response>
+ </D:multistatus>
+
+<span class="h3"><h3><a name="section-7.10">7.10</a>. CALDAV:free-busy-query REPORT</h3></span>
+
+ The CALDAV:free-busy-query REPORT generates a VFREEBUSY component
+ containing free busy information for all the calendar object
+ resources targeted by the request and that have the CALDAV:read-free-
+ busy or DAV:read privilege granted to the current user.
+
+ Only VEVENT components without a TRANSP property or with the TRANSP
+ property set to OPAQUE, and VFREEBUSY components SHOULD be considered
+ in generating the free busy time information.
+
+ In the case of VEVENT components, the free or busy time type (FBTYPE)
+ of the FREEBUSY properties in the returned VFREEBUSY component SHOULD
+ be derived from the value of the TRANSP and STATUS properties, as
+ outlined in the table below:
+
+ +---------------------------++------------------+
+ | VEVENT || VFREEBUSY |
+ +-------------+-------------++------------------+
+ | TRANSP | STATUS || FBTYPE |
+ +=============+=============++==================+
+ | | CONFIRMED || BUSY |
+ | | (default) || |
+ | OPAQUE +-------------++------------------+
+ | (default) | CANCELLED || FREE |
+ | +-------------++------------------+
+ | | TENTATIVE || BUSY-TENTATIVE |
+ | +-------------++------------------+
+ | | x-name || BUSY or |
+ | | || x-name |
+ +-------------+-------------++------------------+
+ | | CONFIRMED || |
+ | TRANSPARENT | CANCELLED || FREE |
+ | | TENTATIVE || |
+ | | x-name || |
+ +-------------+-------------++------------------+
+
+ Duplicate busy time periods with the same FBTYPE parameter value
+ SHOULD NOT be specified in the returned VFREEBUSY component. Servers
+ SHOULD coalesce consecutive or overlapping busy time periods of the
+ same type. Busy time periods with different FBTYPE parameter values
+ MAY overlap.
+
+ Support for the CALDAV:free-busy-query REPORT is REQUIRED.
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 66]</span>
+</pre><pre class="newpage"><a name="page-67" id="page-67" href="#page-67" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ Marshalling:
+
+ The request body MUST be a CALDAV:free-busy-query XML element (see
+ <a href="#section-9.11">Section 9.11</a>), which MUST contain exactly one CALDAV:time-range
+ XML element, as defined in <a href="#section-9.9">Section 9.9</a>.
+
+ The request MAY include a Depth header. If no Depth header is
+ included, Depth:0 is assumed.
+
+ The response body for a successful request MUST be an iCalendar
+ object that contains exactly one VFREEBUSY component that
+ describes the busy time intervals for the calendar object
+ resources containing VEVENT, or VFREEBUSY components that satisfy
+ the Depth value and for which the current user is at least granted
+ the CALDAV:read-free-busy privilege. If no calendar object
+ resources are found to satisfy these conditions, a VFREEBUSY
+ component with no FREEBUSY property MUST be returned. This report
+ only returns busy time information. Free time information can be
+ inferred from the returned busy time information.
+
+ If the current user is not granted the CALDAV:read-free-busy or
+ DAV:read privileges on the Request-URI, the CALDAV:free-busy-query
+ REPORT request MUST fail and return a 404 (Not Found) status
+ value. This restriction will prevent users from discovering URLs
+ of resources for which they are only granted the CALDAV:read-free-
+ busy privilege.
+
+ The CALDAV:free-busy-query REPORT request can only be run against
+ a collection (either a regular collection or a calendar
+ collection). An attempt to run the report on a calendar object
+ resource MUST fail and return a 403 (Forbidden) status value.
+
+ Preconditions:
+
+ None.
+
+ Postconditions:
+
+ (DAV:number-of-matches-within-limits): The number of matching
+ calendar object resources must fall within server-specific,
+ predefined limits. For example, this postcondition might fail if
+ the specified CALDAV:time-range would cause an extremely large
+ number of calendar object resources to be considered in computing
+ the response.
+
+
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 67]</span>
+</pre><pre class="newpage"><a name="page-68" id="page-68" href="#page-68" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+<span class="h4"><h4><a name="section-7.10.1">7.10.1</a>. Example: Successful CALDAV:free-busy-query REPORT</h4></span>
+
+ In this example, the client requests the server to return free busy
+ information on the calendar collection /bernard/work/, between 9:00
+ A.M. and 5:00 P.M. EST (2:00 P.M. and 10:00 P.M. UTC) on the January
+ 4, 2006. The server responds, indicating two busy time intervals of
+ one hour, one of which is tentative.
+
+ See <a href="#appendix-B">Appendix B</a> for the calendar data being targeted by this example.
+
+ >> Request <<
+
+ REPORT /bernard/work/ HTTP/1.1
+ Host: cal.example.com
+ Depth: 1
+ Content-Type: application/xml; charset="utf-8"
+ Content-Length: xxxx
+
+ <?xml version="1.0" encoding="utf-8" ?>
+ <C:free-busy-query xmlns:C="urn:ietf:params:xml:ns:caldav">
+ <C:time-range start="20060104T140000Z"
+ end="20060105T220000Z"/>
+ </C:free-busy-query>
+
+ >> Response <<
+
+ HTTP/1.1 200 OK
+ Date: Sat, 11 Nov 2006 09:32:12 GMT
+ Content-Type: text/calendar
+ Content-Length: xxxx
+
+ BEGIN:VCALENDAR
+ VERSION:2.0
+ PRODID:-//Example Corp.//CalDAV Server//EN
+ BEGIN:VFREEBUSY
+ DTSTAMP:20050125T090000Z
+ DTSTART:20060104T140000Z
+ DTEND:20060105T220000Z
+ FREEBUSY;FBTYPE=BUSY-TENTATIVE:20060104T150000Z/PT1H
+ FREEBUSY:20060104T190000Z/PT1H
+ END:VFREEBUSY
+ END:VCALENDAR
+
+
+
+
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 68]</span>
+</pre><pre class="newpage"><a name="page-69" id="page-69" href="#page-69" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+<span class="h2"><h2><a name="section-8">8</a>. Guidelines</h2></span>
+
+<span class="h3"><h3><a name="section-8.1">8.1</a>. Client-to-Client Interoperability</h3></span>
+
+ There are a number of actions clients can take that will be legal
+ (the server will not return errors), but that can degrade
+ interoperability with other client implementations accessing the same
+ data. For example, a recurrence rule could be replaced with a set of
+ recurrence dates, a single recurring event could be replaced with a
+ set of independent resources to represent each recurrence, or the
+ start/end time values can be translated from the original time zone
+ to another time zone. Although this advice amounts to iCalendar
+ interoperability best practices and is not limited only to CalDAV
+ usage, interoperability problems are likely to be more evident in
+ CalDAV use cases.
+
+<span class="h3"><h3><a name="section-8.2">8.2</a>. Synchronization Operations</h3></span>
+
+ WebDAV already provides functionality required to synchronize a
+ collection or set of collections, to make changes offline, and
+ provides a simple way to resolve conflicts when reconnected. ETags
+ are the key to making this work, but these are not required of all
+ WebDAV servers. Since offline functionality is more important to
+ calendar applications than to some other WebDAV applications, CalDAV
+ servers MUST support ETags, as specified in <a href="#section-5.3.4">Section 5.3.4</a>.
+
+<span class="h4"><h4><a name="section-8.2.1">8.2.1</a>. Use of Reports</h4></span>
+
+<span class="h5"><h5><a name="section-8.2.1.1">8.2.1.1</a>. Restrict the Time Range</h5></span>
+
+ The reports provided in CalDAV can be used by clients to optimize
+ their performance in terms of network bandwidth usage and resource
+ consumption on the local client machine. Both are certainly major
+ considerations for mobile or handheld devices with limited capacity,
+ but they are also relevant to desktop client applications in cases
+ where the calendar collections contain large amounts of data.
+
+ Typically, clients present calendar data to users in views that span
+ a finite time interval, so whenever possible, clients should only
+ retrieve calendar components from the server using CALDAV:calendar-
+ query REPORT, combined with a CALDAV:time-range element, to limit the
+ set of returned components to just those needed to populate the
+ current view.
+
+
+
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 69]</span>
+</pre><pre class="newpage"><a name="page-70" id="page-70" href="#page-70" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+<span class="h5"><h5><a name="section-8.2.1.2">8.2.1.2</a>. Synchronize by Time Range</h5></span>
+
+ Typically in a calendar, historical data (events, to-dos, etc. that
+ have completed prior to the current date) do not change, though they
+ may be deleted. As a result, a client can speed up the
+ synchronization process by only considering data for the present time
+ and the future up to a reasonable limit (e.g., one week, one month).
+ If the user then tries to examine a portion of the calendar outside
+ the range that has been synchronized, the client can perform another
+ synchronization operation on the new time interval being examined.
+ This "just-in-time" synchronization can minimize bandwidth for common
+ user interaction behaviors.
+
+<span class="h5"><h5><a name="section-8.2.1.3">8.2.1.3</a>. Synchronization Process</h5></span>
+
+ If a client wants to support calendar data synchronization, as
+ opposed to downloading calendar data each time it is needed, the
+ client needs to cache the calendar object resource's URI and ETag,
+ along with the actual calendar data. While the URI remains static
+ for the lifetime of the calendar object resource, the ETag will
+ change with each successive change to the calendar object resource.
+ Thus, to synchronize a local data cache with the server, the client
+ can first fetch the URI/ETag pairs for the time interval being
+ considered, and compare those results with the cached data. Any
+ cached component whose ETag differs from that on the server needs to
+ be refreshed.
+
+ In order to properly detect the changes between the server and client
+ data, the client will need to keep a record of which calendar object
+ resources have been created, changed, or deleted since the last
+ synchronization operation so that it can reconcile those changes with
+ the data on the server.
+
+ Here's an example of how to do that:
+
+ The client issues a CALDAV:calendar-query REPORT request for a
+ specific time range and asks for only the DAV:getetag property to be
+ returned:
+
+
+
+
+
+
+
+
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 70]</span>
+</pre><pre class="newpage"><a name="page-71" id="page-71" href="#page-71" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ REPORT /bernard/work/ HTTP/1.1
+ Host: cal.example.com
+ Depth: 1
+ Content-Type: application/xml; charset="utf-8"
+ Content-Length: xxxx
+
+ <?xml version="1.0" encoding="utf-8" ?>
+ <C:calendar-query xmlns:D="DAV:"
+ xmlns:C="urn:ietf:params:xml:ns:caldav">
+ <D:prop>
+ <D:getetag/>
+ </D:prop>
+ <C:filter>
+ <C:comp-filter name="VCALENDAR">
+ <C:comp-filter name="VEVENT">
+ <C:time-range start="20040902T000000Z"
+ end="20040903T000000Z"/>
+ </C:comp-filter>
+ </C:comp-filter>
+ </C:filter>
+ </C:calendar-query>
+
+ The client then uses the results to determine which calendar object
+ resources have changed, been created, or deleted on the server, and
+ how those relate to locally cached calendar object resources that may
+ have changed, been created, or deleted. If the client determines
+ that there are calendar object resources on the server that need to
+ be fetched, the client issues a CALDAV:calendar-multiget REPORT
+ request to fetch its calendar data:
+
+ REPORT /bernard/work/ HTTP/1.1
+ Host: cal.example.com
+ Content-Type: application/xml; charset="utf-8"
+ Content-Length: xxxx
+
+ <?xml version="1.0" encoding="utf-8" ?>
+ <C:calendar-multiget xmlns:D="DAV:"
+ xmlns:C="urn:ietf:params:xml:ns:caldav">
+ <D:prop>
+ <D:getetag/>
+ <C:calendar-data/>
+ </D:prop>
+ <D:href>/bernard/work/abcd1.ics</D:href>
+ <D:href>/bernard/work/mtg1.ics</D:href>
+ </C:calendar-multiget>
+
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 71]</span>
+</pre><pre class="newpage"><a name="page-72" id="page-72" href="#page-72" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+<span class="h4"><h4><a name="section-8.2.2">8.2.2</a>. Restrict the Properties Returned</h4></span>
+
+ A client may not need all the calendar properties of a calendar
+ object resource when presenting information to the user. Since some
+ calendar property values can be large (e.g., ATTACH or ATTENDEE), a
+ client can choose to restrict the calendar properties to be returned
+ in a calendaring REPORT request to those it knows it will use.
+
+ However, if a client needs to make a change to a calendar object
+ resource, it can only change the entire calendar object resource via
+ a PUT request. There is currently no way to incrementally make a
+ change to a set of calendar properties of a calendar object resource.
+ As a result, the client will have to get the entire calendar object
+ resource that is being changed.
+
+<span class="h3"><h3><a name="section-8.3">8.3</a>. Use of Locking</h3></span>
+
+ WebDAV locks can be used to prevent two clients that are modifying
+ the same resource from either overwriting each others' changes
+ (though that problem can also be solved by using ETags) or wasting
+ time making changes that will conflict with another set of changes.
+ In a multi-user calendar system, an interactive calendar client could
+ lock an event while the user is editing the event, and unlock the
+ event when the user finishes or cancels. Locks can also be used to
+ prevent changes while data is being reorganized. For example, a
+ calendar client might lock two calendar collections prior to moving a
+ bunch of calendar resources from one to another.
+
+ Clients are responsible for requesting a lock timeout period that is
+ appropriate to the use case. When the user explicitly decides to
+ reserve a resource and prevent other changes, a long timeout might be
+ appropriate, but in cases where the client automatically decides to
+ lock the resource, the timeout should be short (and the client can
+ always refresh the lock should it need to). A short lock timeout
+ means that if the client is unable to remove the lock, the other
+ calendar users aren't prevented from making changes.
+
+<span class="h3"><h3><a name="section-8.4">8.4</a>. Finding Calendars</h3></span>
+
+ Much of the time, a calendar client (or agent) will discover a new
+ calendar's location by being provided directly with the URL. For
+ example, a user will type his or her own calendar location into
+ client configuration information or copy and paste a URL from email
+ into the calendar application. The client need only confirm that the
+ URL points to a resource that is a calendar collection. The client
+ may also be able to browse WebDAV collections to find calendar
+ collections.
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 72]</span>
+</pre><pre class="newpage"><a name="page-73" id="page-73" href="#page-73" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ The choice of HTTP URLs means that calendar object resources are
+ backward compatible with existing software, but does have the
+ disadvantage that existing software does not usually know to look at
+ the OPTIONS response to that URL to determine what can be done with
+ it. This is somewhat of a barrier for WebDAV usage as well as with
+ CalDAV usage. This specification does not offer a way through this
+ other than making the information available in the OPTIONS response
+ should this be requested.
+
+ For calendar sharing and scheduling use cases, one might wish to find
+ the calendar belonging to another user. If the other user has a
+ calendar in the same repository, that calendar can be found by using
+ the principal namespace required by WebDAV ACL support. For other
+ cases, the authors have no universal solution, but implementers can
+ consider whether to use vCard [<a href="http://tools.ietf.org/html/rfc2426" title=""vCard MIME Directory Profile"">RFC2426</a>] or LDAP [<a href="http://tools.ietf.org/html/rfc4511" title=""Lightweight Directory Access Protocol (LDAP): The Protocol"">RFC4511</a>] standards
+ together with calendar attributes [<a href="http://tools.ietf.org/html/rfc2739" title=""Calendar Attributes for vCard and LDAP"">RFC2739</a>].
+
+ Because CalDAV requires servers to support WebDAV ACL [<a href="http://tools.ietf.org/html/rfc3744" title=""Web Distributed Authoring and Versioning (WebDAV) Access Control Protocol"">RFC3744</a>],
+ including principal namespaces, and with the addition of the CALDAV:
+ calendar-home-set property, there are a couple options for CalDAV
+ clients to find one's own calendar or another user's calendar.
+
+ In this case, a DAV:principal-match REPORT is used to find a named
+ property (the CALDAV:calendar-home-set) on the Principal-URL of the
+ current user. Using this, a WebDAV client can learn "who am I" and
+ "where are my calendars". The REPORT request body looks like this:
+
+ <?xml version="1.0" encoding="utf-8" ?>
+ <D:principal-match xmlns:D="DAV:">
+ <D:self/>
+ <D:prop>
+ <C:calendar-home-set
+ xmlns:C="urn:ietf:params:xml:ns:caldav"/>
+ </D:prop>
+ </D:principal-match>
+
+ To find other users' calendars, the DAV:principal-property-search
+ REPORT can be used to filter on some properties and return others.
+ To search for a calendar owned by a user named "Laurie", the REPORT
+ request body would look like this:
+
+
+
+
+
+
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 73]</span>
+</pre><pre class="newpage"><a name="page-74" id="page-74" href="#page-74" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ <?xml version="1.0" encoding="utf-8" ?>
+ <D:principal-property-search xmlns:D="DAV:">
+ <D:property-search>
+ <D:prop>
+ <D:displayname/>
+ </D:prop>
+ <D:match>Laurie</D:match>
+ </D:property-search>
+ <D:prop>
+ <C:calendar-home-set
+ xmlns:C="urn:ietf:params:xml:ns:caldav"/>
+ <D:displayname/>
+ </D:prop>
+ </D:principal-property-search>
+
+ The server performs a case-sensitive or caseless search for a
+ matching string subset of "Laurie" within the DAV:displayname
+ property. Thus, the server might return "Laurie Dusseault", "Laurier
+ Desruisseaux", or "Wilfrid Laurier" as matching DAV:displayname
+ values, and return the calendars for each of these.
+
+<span class="h3"><h3><a name="section-8.5">8.5</a>. Storing and Using Attachments</h3></span>
+
+ CalDAV clients MAY create attachments in calendar components either
+ as inline or external. This section contains some guidelines for
+ creating and managing attachments.
+
+<span class="h4"><h4><a name="section-8.5.1">8.5.1</a>. Inline Attachments</h4></span>
+
+ CalDAV clients MUST support inline attachments as specified in
+ iCalendar [<a href="http://tools.ietf.org/html/rfc2445" title=""Internet Calendaring and Scheduling Core Object Specification (iCalendar)"">RFC2445</a>]. CalDAV servers MUST support inline attachments,
+ so clients can rely on being able to create attachments this way. On
+ the other hand, inline attachments have some drawbacks:
+
+ o Servers MAY impose limitations on the size of calendar object
+ resources (i.e., refusing PUT requests of very large iCalendar
+ objects). Servers that impose such limitations MUST use the
+ CALDAV:max-resource-size property on a calendar collection to
+ inform the client as to what the limitation is (see
+ <a href="#section-5.2.5">Section 5.2.5</a>).
+
+ o Servers MAY impose storage quota limitations on calendar
+ collections (See [<a href="http://tools.ietf.org/html/rfc4331" title=""Quota and Size Properties for Distributed Authoring and Versioning (DAV) Collections"">RFC4331</a>]).
+
+ o Any change to a calendar object resource containing an inline
+ attachment requires the entire inline attachment to be re-
+ uploaded.
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 74]</span>
+</pre><pre class="newpage"><a name="page-75" id="page-75" href="#page-75" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ o Clients synchronizing a changed calendar object resource have to
+ download the entire calendar object resource, even if the
+ attachment is unchanged.
+
+<span class="h4"><h4><a name="section-8.5.2">8.5.2</a>. External Attachments</h4></span>
+
+ CalDAV clients SHOULD support downloading of external attachments
+ referenced by arbitrary URI schemes, by either processing them
+ directly, or by passing the attachment URI to a suitable "helper
+ application" for processing, if such an application exists. CalDAV
+ clients MUST support downloading of external attachments referenced
+ by the "http" or "https" URI schemes. An external attachment could
+ be:
+
+ o In a collection in the calendar collection containing the calendar
+ object resource;
+
+ o Somewhere else in the same repository that hosts the calendar
+ collection; or
+
+ o On an HTTP or FTP server elsewhere.
+
+ CalDAV servers MAY provide support for child collections in calendar
+ collections. CalDAV servers MAY allow the MKCOL method to create
+ child collections in calendar collections. Child collections of
+ calendar collections MAY contain any type of resource except calendar
+ collections that they MUST NOT contain. Some CalDAV servers won't
+ allow child collections in calendar collections, and it may be
+ possible on such a server to discover other locations where
+ attachments can be stored.
+
+ Clients are entirely responsible for maintaining reference
+ consistency with calendar components that link to external
+ attachments. A client deleting a calendar component with an external
+ attachment might therefore also delete the attachment if that's
+ appropriate; however, appropriateness can be very hard to determine.
+ A new component might easily reference some pre-existing Web resource
+ that is intended to have independent existence from the calendar
+ component (the "attachment" could be a major proposal to be discussed
+ in a meeting, for instance). Best practices will probably emerge and
+ should probably be documented, but for now, clients should be wary of
+ engaging in aggressive "cleanup" of external attachments. A client
+ could involve the user in making decisions about removing
+ unreferenced documents, or a client could be conservative in only
+ deleting attachments it had created.
+
+ Also, clients are responsible for consistency of permissions when
+ using external attachments. One reason for servers to support the
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 75]</span>
+</pre><pre class="newpage"><a name="page-76" id="page-76" href="#page-76" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ storage of attachments within child collections of calendar
+ collections is that ACL inheritance might make it easier to grant the
+ same permissions to attachments that are granted on the calendar
+ collection. Otherwise, it can be very difficult to keep permissions
+ synchronized. With attachments stored on separate repositories, it
+ can be impossible to keep permissions consistent -- the two
+ repositories may not support the same permissions or have the same
+ set of principals. Some systems have used tickets or other anonymous
+ access control mechanisms to provide partially satisfactory solutions
+ to these kinds of problems.
+
+<span class="h3"><h3><a name="section-8.6">8.6</a>. Storing and Using Alarms</h3></span>
+
+ Note that all CalDAV calendar collections (including those the user
+ might treat as public or group calendars) can contain alarm
+ information on events and to-dos. Users can synchronize a calendar
+ between multiple devices and decide to have alarms execute on a
+ different device than the device that created the alarm. Not all
+ alarm action types are completely interoperable (e.g., those that
+ name a sound file to play).
+
+ When the action is AUDIO and the client is configured to execute
+ the alarm, the client SHOULD play the suggested sound if it's
+ available or play another sound, but SHOULD NOT rewrite the alarm
+ just to replace the suggested sound with a sound that's locally
+ available.
+
+ When the action is DISPLAY and the client is configured to execute
+ the alarm, the client SHOULD execute a display alarm by displaying
+ according to the suggested description or some reasonable
+ replacement, but SHOULD NOT rewrite the alarm for its own
+ convenience.
+
+ When the action is EMAIL and the client is incapable of sending
+ email, it SHOULD ignore the alarm, but it MUST continue to
+ synchronize the alarm itself.
+
+ This specification makes no recommendations about executing alarms
+ of type PROCEDURE, except to note that clients are advised to take
+ care to avoid creating security holes by executing these.
+
+ Non-interoperable alarm information (e.g., should somebody define a
+ color to be used in a display alarm) should be put in non-standard
+ properties inside the VALARM component in order to keep the basic
+ alarm usable on all devices.
+
+ Clients that allow changes to calendar object resources MUST
+ synchronize the alarm data that already exists in the resources.
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 76]</span>
+</pre><pre class="newpage"><a name="page-77" id="page-77" href="#page-77" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ Clients MAY execute alarms that are downloaded in this fashion,
+ possibly based on user preference. If a client is only doing read
+ operations on a calendar and there is no risk of losing alarm
+ information, then the client MAY discard alarm information.
+
+ This specification makes no attempt to provide multi-user alarms on
+ group calendars or to find out for whom an alarm is intended.
+ Addressing those issues might require extensions to iCalendar; for
+ example, to store alarms per-user, or to indicate for which user a
+ VALARM was intended. In the meantime, clients might maximize
+ interoperability by generally not uploading alarm information to
+ public, group, or resource calendars.
+
+<span class="h2"><h2><a name="section-9">9</a>. XML Element Definitions</h2></span>
+
+<span class="h3"><h3><a name="section-9.1">9.1</a>. CALDAV:calendar XML Element</h3></span>
+
+ Name: calendar
+
+ Namespace: urn:ietf:params:xml:ns:caldav
+
+ Purpose: Specifies the resource type of a calendar collection.
+
+ Description: See <a href="#section-4.2">Section 4.2</a>.
+
+ Definition:
+
+ <!ELEMENT calendar EMPTY>
+
+<span class="h3"><h3><a name="section-9.2">9.2</a>. CALDAV:mkcalendar XML Element</h3></span>
+
+ Name: mkcalendar
+
+ Namespace: urn:ietf:params:xml:ns:caldav
+
+ Purpose: Specifies a request that includes the WebDAV property
+ values to be set for a calendar collection resource when it is
+ created.
+
+ Description: See <a href="#section-5.3.1">Section 5.3.1</a>.
+
+ Definition:
+
+ <!ELEMENT mkcalendar (DAV:set)>
+
+
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 77]</span>
+</pre><pre class="newpage"><a name="page-78" id="page-78" href="#page-78" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+<span class="h3"><h3><a name="section-9.3">9.3</a>. CALDAV:mkcalendar-response XML Element</h3></span>
+
+ Name: mkcalendar-response
+
+ Namespace: urn:ietf:params:xml:ns:caldav
+
+ Purpose: Specifies a response body for a successful MKCALENDAR
+ request.
+
+ Description: See <a href="#section-5.3.1">Section 5.3.1</a>.
+
+ Definition:
+
+ <!ELEMENT mkcalendar-response ANY>
+
+<span class="h3"><h3><a name="section-9.4">9.4</a>. CALDAV:supported-collation XML Element</h3></span>
+
+ Name: supported-collation
+
+ Namespace: urn:ietf:params:xml:ns:caldav
+
+ Purpose: Identifies a single collation via its collation identifier,
+ as defined by [<a href="http://tools.ietf.org/html/rfc4790" title=""Internet Application Protocol Collation Registry"">RFC4790</a>].
+
+ Description: The CALDAV:supported-collation contains the text of a
+ collation identifier, as described in <a href="#section-7.5.1">Section 7.5.1</a>.
+
+ Definition:
+
+ <!ELEMENT supported-collation (#PCDATA)>
+ PCDATA value: collation identifier
+
+<span class="h3"><h3><a name="section-9.5">9.5</a>. CALDAV:calendar-query XML Element</h3></span>
+
+ Name: calendar-query
+
+ Namespace: urn:ietf:params:xml:ns:caldav
+
+ Purpose: Defines a report for querying calendar object resources.
+
+ Description: See <a href="#section-7.8">Section 7.8</a>.
+
+ Definition:
+
+ <!ELEMENT calendar-query ((DAV:allprop |
+ DAV:propname |
+ DAV:prop)?, filter, timezone?)>
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 78]</span>
+</pre><pre class="newpage"><a name="page-79" id="page-79" href="#page-79" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+<span class="h3"><h3><a name="section-9.6">9.6</a>. CALDAV:calendar-data XML Element</h3></span>
+
+ Name: calendar-data
+
+ Namespace: urn:ietf:params:xml:ns:caldav
+
+ Purpose: Specified one of the following:
+
+ 1. A supported media type for calendar object resources when
+ nested in the CALDAV:supported-calendar-data property;
+
+ 2. The parts of a calendar object resource should be returned by
+ a calendaring report;
+
+ 3. The content of a calendar object resource in a response to a
+ calendaring report.
+
+ Description: When nested in the CALDAV:supported-calendar-data
+ property, the CALDAV:calendar-data XML element specifies a media
+ type supported by the CalDAV server for calendar object resources.
+
+ When used in a calendaring REPORT request, the CALDAV:calendar-
+ data XML element specifies which parts of calendar object
+ resources need to be returned in the response. If the CALDAV:
+ calendar-data XML element doesn't contain any CALDAV:comp element,
+ calendar object resources will be returned in their entirety.
+
+ Finally, when used in a calendaring REPORT response, the CALDAV:
+ calendar-data XML element specifies the content of a calendar
+ object resource. Given that XML parsers normalize the two-
+ character sequence CRLF (US-ASCII decimal 13 and US-ASCII decimal
+ 10) to a single LF character (US-ASCII decimal 10), the CR
+ character (US-ASCII decimal 13) MAY be omitted in calendar object
+ resources specified in the CALDAV:calendar-data XML element.
+ Furthermore, calendar object resources specified in the CALDAV:
+ calendar-data XML element MAY be invalid per their media type
+ specification if the CALDAV:calendar-data XML element part of the
+ calendaring REPORT request did not specify required properties
+ (e.g., UID, DTSTAMP, etc.), or specified a CALDAV:prop XML element
+ with the "novalue" attribute set to "yes".
+
+ Note: The CALDAV:calendar-data XML element is specified in requests
+ and responses inside the DAV:prop XML element as if it were a
+ WebDAV property. However, the CALDAV:calendar-data XML element is
+ not a WebDAV property and, as such, is not returned in PROPFIND
+ responses, nor used in PROPPATCH requests.
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 79]</span>
+</pre><pre class="newpage"><a name="page-80" id="page-80" href="#page-80" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ Note: The iCalendar data embedded within the CALDAV:calendar-data
+ XML element MUST follow the standard XML character data encoding
+ rules, including use of &lt;, &gt;, &amp; etc. entity encoding or
+ the use of a <![CDATA[ ... ]]> construct. In the later case, the
+ iCalendar data cannot contain the character sequence "]]>", which
+ is the end delimiter for the CDATA section.
+
+ Definition:
+
+ <!ELEMENT calendar-data EMPTY>
+
+ when nested in the CALDAV:supported-calendar-data property
+ to specify a supported media type for calendar object
+ resources;
+
+ <!ELEMENT calendar-data (comp?,
+ (expand | limit-recurrence-set)?,
+ limit-freebusy-set?)>
+
+ when nested in the DAV:prop XML element in a calendaring
+ REPORT request to specify which parts of calendar object
+ resources should be returned in the response;
+
+ <!ELEMENT calendar-data (#PCDATA)>
+ PCDATA value: iCalendar object
+
+ when nested in the DAV:prop XML element in a calendaring
+ REPORT response to specify the content of a returned
+ calendar object resource.
+
+ <!ATTLIST calendar-data content-type CDATA "text/calendar"
+ version CDATA "2.0">
+ content-type value: a MIME media type
+ version value: a version string
+
+ attributes can be used on all three variants of the
+ CALDAV:calendar-data XML element.
+
+<span class="h4"><h4><a name="section-9.6.1">9.6.1</a>. CALDAV:comp XML Element</h4></span>
+
+ Name: comp
+
+ Namespace: urn:ietf:params:xml:ns:caldav
+
+ Purpose: Defines which component types to return.
+
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 80]</span>
+</pre><pre class="newpage"><a name="page-81" id="page-81" href="#page-81" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ Description: The name value is a calendar component name (e.g.,
+ VEVENT).
+
+ Definition:
+
+ <!ELEMENT comp ((allprop | prop*), (allcomp | comp*))>
+
+ <!ATTLIST comp name CDATA #REQUIRED>
+ name value: a calendar component name
+
+ Note: The CALDAV:prop and CALDAV:allprop elements have the same name
+ as the DAV:prop and DAV:allprop elements defined in [<a href="http://tools.ietf.org/html/rfc2518" title=""HTTP Extensions for Distributed Authoring -- WEBDAV"">RFC2518</a>].
+ However, the CALDAV:prop and CALDAV:allprop elements are defined
+ in the "urn:ietf:params:xml:ns:caldav" namespace instead of the
+ "DAV:" namespace.
+
+<span class="h4"><h4><a name="section-9.6.2">9.6.2</a>. CALDAV:allcomp XML Element</h4></span>
+
+ Name: allcomp
+
+ Namespace: urn:ietf:params:xml:ns:caldav
+
+ Purpose: Specifies that all components shall be returned.
+
+ Description: The CALDAV:allcomp XML element can be used when the
+ client wants all types of components returned by a calendaring
+ REPORT request.
+
+ Definition:
+
+ <!ELEMENT allcomp EMPTY>
+
+<span class="h4"><h4><a name="section-9.6.3">9.6.3</a>. CALDAV:allprop XML Element</h4></span>
+
+ Name: allprop
+
+ Namespace: urn:ietf:params:xml:ns:caldav
+
+ Purpose: Specifies that all properties shall be returned.
+
+ Description: The CALDAV:allprop XML element can be used when the
+ client wants all properties of components returned by a
+ calendaring REPORT request.
+
+ Definition:
+
+ <!ELEMENT allprop EMPTY>
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 81]</span>
+</pre><pre class="newpage"><a name="page-82" id="page-82" href="#page-82" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ Note: The CALDAV:allprop element has the same name as the DAV:
+ allprop element defined in [<a href="http://tools.ietf.org/html/rfc2518" title=""HTTP Extensions for Distributed Authoring -- WEBDAV"">RFC2518</a>]. However, the CALDAV:allprop
+ element is defined in the "urn:ietf:params:xml:ns:caldav"
+ namespace instead of the "DAV:" namespace.
+
+<span class="h4"><h4><a name="section-9.6.4">9.6.4</a>. CALDAV:prop XML Element</h4></span>
+
+ Name: prop
+
+ Namespace: urn:ietf:params:xml:ns:caldav
+
+ Purpose: Defines which properties to return in the response.
+
+ Description: The "name" attribute specifies the name of the calendar
+ property to return (e.g., ATTENDEE). The "novalue" attribute can
+ be used by clients to request that the actual value of the
+ property not be returned (if the "novalue" attribute is set to
+ "yes"). In that case, the server will return just the iCalendar
+ property name and any iCalendar parameters and a trailing ":"
+ without the subsequent value data.
+
+ Definition:
+
+ <!ELEMENT prop EMPTY>
+
+ <!ATTLIST prop name CDATA #REQUIRED
+ novalue (yes | no) "no">
+ name value: a calendar property name
+ novalue value: "yes" or "no"
+
+ Note: The CALDAV:prop element has the same name as the DAV:prop
+ element defined in [<a href="http://tools.ietf.org/html/rfc2518" title=""HTTP Extensions for Distributed Authoring -- WEBDAV"">RFC2518</a>]. However, the CALDAV:prop element is
+ defined in the "urn:ietf:params:xml:ns:caldav" namespace instead
+ of the "DAV:" namespace.
+
+<span class="h4"><h4><a name="section-9.6.5">9.6.5</a>. CALDAV:expand XML Element</h4></span>
+
+ Name: expand
+
+ Namespace: urn:ietf:params:xml:ns:caldav
+
+ Purpose: Forces the server to expand recurring components into
+ individual recurrence instances.
+
+ Description: The CALDAV:expand XML element specifies that for a
+ given calendaring REPORT request, the server MUST expand the
+ recurrence set into calendar components that define exactly one
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 82]</span>
+</pre><pre class="newpage"><a name="page-83" id="page-83" href="#page-83" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ recurrence instance, and MUST return only those whose scheduled
+ time intersect a specified time range.
+
+ The "start" attribute specifies the inclusive start of the time
+ range, and the "end" attribute specifies the non-inclusive end of
+ the time range. Both attributes are specified as date with UTC
+ time value. The value of the "end" attribute MUST be greater than
+ the value of the "start" attribute.
+
+ The server MUST use the same logic as defined for CALDAV:time-
+ range to determine if a recurrence instance intersects the
+ specified time range.
+
+ Recurring components, other than the initial instance, MUST
+ include a RECURRENCE-ID property indicating which instance they
+ refer to.
+
+ The returned calendar components MUST NOT use recurrence
+ properties (i.e., EXDATE, EXRULE, RDATE, and RRULE) and MUST NOT
+ have reference to or include VTIMEZONE components. Date and local
+ time with reference to time zone information MUST be converted
+ into date with UTC time.
+
+ Definition:
+
+ <!ELEMENT expand EMPTY>
+
+ <!ATTLIST expand start CDATA #REQUIRED
+ end CDATA #REQUIRED>
+ start value: an iCalendar "date with UTC time"
+ end value: an iCalendar "date with UTC time"
+
+<span class="h4"><h4><a name="section-9.6.6">9.6.6</a>. CALDAV:limit-recurrence-set XML Element</h4></span>
+
+ Name: limit-recurrence-set
+
+ Namespace: urn:ietf:params:xml:ns:caldav
+
+ Purpose: Specifies a time range to limit the set of "overridden
+ components" returned by the server.
+
+ Description: The CALDAV:limit-recurrence-set XML element specifies
+ that for a given calendaring REPORT request, the server MUST
+ return, in addition to the "master component", only the
+ "overridden components" that impact a specified time range. An
+ overridden component impacts a time range if its current start and
+ end times overlap the time range, or if the original start and end
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 83]</span>
+</pre><pre class="newpage"><a name="page-84" id="page-84" href="#page-84" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ times -- the ones that would have been used if the instance were
+ not overridden -- overlap the time range.
+
+ The "start" attribute specifies the inclusive start of the time
+ range, and the "end" attribute specifies the non-inclusive end of
+ the time range. Both attributes are specified as date with UTC
+ time value. The value of the "end" attribute MUST be greater than
+ the value of the "start" attribute.
+
+ The server MUST use the same logic as defined for CALDAV:time-
+ range to determine if the current or original scheduled time of an
+ "overridden" recurrence instance intersects the specified time
+ range.
+
+ Overridden components that have a RANGE parameter on their
+ RECURRENCE-ID property may specify one or more instances in the
+ recurrence set, and some of those instances may fall within the
+ specified time range or may have originally fallen within the
+ specified time range prior to being overridden. If that is the
+ case, the overridden component MUST be included in the results, as
+ it has a direct impact on the interpretation of instances within
+ the specified time range.
+
+ Definition:
+
+ <!ELEMENT limit-recurrence-set EMPTY>
+
+ <!ATTLIST limit-recurrence-set start CDATA #REQUIRED
+ end CDATA #REQUIRED>
+ start value: an iCalendar "date with UTC time"
+ end value: an iCalendar "date with UTC time"
+
+<span class="h4"><h4><a name="section-9.6.7">9.6.7</a>. CALDAV:limit-freebusy-set XML Element</h4></span>
+
+ Name: limit-freebusy-set
+
+ Namespace: urn:ietf:params:xml:ns:caldav
+
+ Purpose: Specifies a time range to limit the set of FREEBUSY values
+ returned by the server.
+
+ Description: The CALDAV:limit-freebusy-set XML element specifies
+ that for a given calendaring REPORT request, the server MUST only
+ return the FREEBUSY property values of a VFREEBUSY component that
+ intersects a specified time range.
+
+ The "start" attribute specifies the inclusive start of the time
+ range, and the "end" attribute specifies the non-inclusive end of
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 84]</span>
+</pre><pre class="newpage"><a name="page-85" id="page-85" href="#page-85" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ the time range. Both attributes are specified as "date with UTC
+ time" value. The value of the "end" attribute MUST be greater
+ than the value of the "start" attribute.
+
+ The server MUST use the same logic as defined for CALDAV:time-
+ range to determine if a FREEBUSY property value intersects the
+ specified time range.
+
+ Definition:
+
+ <!ELEMENT limit-freebusy-set EMPTY>
+
+ <!ATTLIST limit-freebusy-set start CDATA #REQUIRED
+ end CDATA #REQUIRED>
+ start value: an iCalendar "date with UTC time"
+ end value: an iCalendar "date with UTC time"
+
+<span class="h3"><h3><a name="section-9.7">9.7</a>. CALDAV:filter XML Element</h3></span>
+
+ Name: filter
+
+ Namespace: urn:ietf:params:xml:ns:caldav
+
+ Purpose: Specifies a filter to limit the set of calendar components
+ returned by the server.
+
+ Description: The CALDAV:filter XML element specifies the search
+ filter used to limit the calendar components returned by a
+ calendaring REPORT request.
+
+ Definition:
+
+ <!ELEMENT filter (comp-filter)>
+
+<span class="h4"><h4><a name="section-9.7.1">9.7.1</a>. CALDAV:comp-filter XML Element</h4></span>
+
+ Name: comp-filter
+
+ Namespace: urn:ietf:params:xml:ns:caldav
+
+ Purpose: Specifies search criteria on calendar components.
+
+ Description: The CALDAV:comp-filter XML element specifies a query
+ targeted at the calendar object (i.e., VCALENDAR) or at a specific
+ calendar component type (e.g., VEVENT). The scope of the
+ CALDAV:comp-filter XML element is the calendar object when used as
+ a child of the CALDAV:filter XML element. The scope of the
+ CALDAV:comp-filter XML element is the enclosing calendar component
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 85]</span>
+</pre><pre class="newpage"><a name="page-86" id="page-86" href="#page-86" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ when used as a child of another CALDAV:comp-filter XML element. A
+ CALDAV:comp-filter is said to match if:
+
+ * The CALDAV:comp-filter XML element is empty and the calendar
+ object or calendar component type specified by the "name"
+ attribute exists in the current scope;
+
+ or:
+
+ * The CALDAV:comp-filter XML element contains a CALDAV:is-not-
+ defined XML element and the calendar object or calendar
+ component type specified by the "name" attribute does not exist
+ in the current scope;
+
+ or:
+
+ * The CALDAV:comp-filter XML element contains a CALDAV:time-range
+ XML element and at least one recurrence instance in the
+ targeted calendar component is scheduled to overlap the
+ specified time range, and all specified CALDAV:prop-filter and
+ CALDAV:comp-filter child XML elements also match the targeted
+ calendar component;
+
+ or:
+
+ * The CALDAV:comp-filter XML element only contains CALDAV:prop-
+ filter and CALDAV:comp-filter child XML elements that all match
+ the targeted calendar component.
+
+ Definition:
+
+ <!ELEMENT comp-filter (is-not-defined | (time-range?,
+ prop-filter*, comp-filter*))>
+
+ <!ATTLIST comp-filter name CDATA #REQUIRED>
+ name value: a calendar object or calendar component
+ type (e.g., VEVENT)
+
+<span class="h4"><h4><a name="section-9.7.2">9.7.2</a>. CALDAV:prop-filter XML Element</h4></span>
+
+ Name: prop-filter
+
+ Namespace: urn:ietf:params:xml:ns:caldav
+
+ Purpose: Specifies search criteria on calendar properties.
+
+ Description: The CALDAV:prop-filter XML element specifies a query
+ targeted at a specific calendar property (e.g., CATEGORIES) in the
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 86]</span>
+</pre><pre class="newpage"><a name="page-87" id="page-87" href="#page-87" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ scope of the enclosing calendar component. A calendar property is
+ said to match a CALDAV:prop-filter if:
+
+ * The CALDAV:prop-filter XML element is empty and a property of
+ the type specified by the "name" attribute exists in the
+ enclosing calendar component;
+
+ or:
+
+ * The CALDAV:prop-filter XML element contains a CALDAV:is-not-
+ defined XML element and no property of the type specified by
+ the "name" attribute exists in the enclosing calendar
+ component;
+
+ or:
+
+ * The CALDAV:prop-filter XML element contains a CALDAV:time-range
+ XML element and the property value overlaps the specified time
+ range, and all specified CALDAV:param-filter child XML elements
+ also match the targeted property;
+
+ or:
+
+ * The CALDAV:prop-filter XML element contains a CALDAV:text-match
+ XML element and the property value matches it, and all
+ specified CALDAV:param-filter child XML elements also match the
+ targeted property;
+
+ Definition:
+
+ <!ELEMENT prop-filter (is-not-defined |
+ ((time-range | text-match)?,
+ param-filter*))>
+
+ <!ATTLIST prop-filter name CDATA #REQUIRED>
+ name value: a calendar property name (e.g., ATTENDEE)
+
+<span class="h4"><h4><a name="section-9.7.3">9.7.3</a>. CALDAV:param-filter XML Element</h4></span>
+
+ Name: param-filter
+
+ Namespace: urn:ietf:params:xml:ns:caldav
+
+ Purpose: Limits the search to specific parameter values.
+
+ Description: The CALDAV:param-filter XML element specifies a query
+ targeted at a specific calendar property parameter (e.g.,
+ PARTSTAT) in the scope of the calendar property on which it is
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 87]</span>
+</pre><pre class="newpage"><a name="page-88" id="page-88" href="#page-88" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ defined. A calendar property parameter is said to match a CALDAV:
+ param-filter if:
+
+ * The CALDAV:param-filter XML element is empty and a parameter of
+ the type specified by the "name" attribute exists on the
+ calendar property being examined;
+
+ or:
+
+ * The CALDAV:param-filter XML element contains a CALDAV:is-not-
+ defined XML element and no parameter of the type specified by
+ the "name" attribute exists on the calendar property being
+ examined;
+
+ Definition:
+
+ <!ELEMENT param-filter (is-not-defined | text-match?)>
+
+ <!ATTLIST param-filter name CDATA #REQUIRED>
+ name value: a property parameter name (e.g., PARTSTAT)
+
+<span class="h4"><h4><a name="section-9.7.4">9.7.4</a>. CALDAV:is-not-defined XML Element</h4></span>
+
+ Name: is-not-defined
+
+ Namespace: urn:ietf:params:xml:ns:caldav
+
+ Purpose: Specifies that a match should occur if the enclosing
+ component, property, or parameter does not exist.
+
+ Description: The CALDAV:is-not-defined XML element specifies that a
+ match occurs if the enclosing component, property, or parameter
+ value specified in a calendaring REPORT request does not exist in
+ the calendar data being tested.
+
+ Definition:
+
+ <!ELEMENT is-not-defined EMPTY>
+
+<span class="h4"><h4><a name="section-9.7.5">9.7.5</a>. CALDAV:text-match XML Element</h4></span>
+
+ Name: text-match
+
+ Namespace: urn:ietf:params:xml:ns:caldav
+
+ Purpose: Specifies a substring match on a property or parameter
+ value.
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 88]</span>
+</pre><pre class="newpage"><a name="page-89" id="page-89" href="#page-89" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ Description: The CALDAV:text-match XML element specifies text used
+ for a substring match against the property or parameter value
+ specified in a calendaring REPORT request.
+
+ The "collation" attribute is used to select the collation that the
+ server MUST use for character string matching. In the absence of
+ this attribute, the server MUST use the "i;ascii-casemap"
+ collation.
+
+ The "negate-condition" attribute is used to indicate that this
+ test returns a match if the text matches when the attribute value
+ is set to "no", or return a match if the text does not match, if
+ the attribute value is set to "yes". For example, this can be
+ used to match components with a STATUS property not set to
+ CANCELLED.
+
+ Definition:
+
+ <!ELEMENT text-match (#PCDATA)>
+ PCDATA value: string
+
+ <!ATTLIST text-match collation CDATA "i;ascii-casemap"
+ negate-condition (yes | no) "no">
+
+<span class="h3"><h3><a name="section-9.8">9.8</a>. CALDAV:timezone XML Element</h3></span>
+
+ Name: timezone
+
+ Namespace: urn:ietf:params:xml:ns:caldav
+
+ Purpose: Specifies the time zone component to use when determining
+ the results of a report.
+
+ Description: The CALDAV:timezone XML element specifies that for a
+ given calendaring REPORT request, the server MUST rely on the
+ specified VTIMEZONE component instead of the CALDAV:calendar-
+ timezone property of the calendar collection, in which the
+ calendar object resource is contained to resolve "date" values and
+ "date with local time" values (i.e., floating time) to "date with
+ UTC time" values. The server will require this information to
+ determine if a calendar component scheduled with "date" values or
+ "date with local time" values intersects a CALDAV:time-range
+ specified in a CALDAV:calendar-query REPORT.
+
+ Note: The iCalendar data embedded within the CALDAV:timezone XML
+ element MUST follow the standard XML character data encoding
+ rules, including use of &lt;, &gt;, &amp; etc. entity encoding or
+ the use of a <![CDATA[ ... ]]> construct. In the later case, the
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 89]</span>
+</pre><pre class="newpage"><a name="page-90" id="page-90" href="#page-90" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ iCalendar data cannot contain the character sequence "]]>", which
+ is the end delimiter for the CDATA section.
+
+ Definition:
+
+ <!ELEMENT timezone (#PCDATA)>
+ PCDATA value: an iCalendar object with exactly one VTIMEZONE
+
+<span class="h3"><h3><a name="section-9.9">9.9</a>. CALDAV:time-range XML Element</h3></span>
+
+ Name: time-range
+
+ Namespace: urn:ietf:params:xml:ns:caldav
+
+ Purpose: Specifies a time range to limit the set of calendar
+ components returned by the server.
+
+ Description: The CALDAV:time-range XML element specifies that for a
+ given calendaring REPORT request, the server MUST only return the
+ calendar object resources that, depending on the context, have a
+ component or property whose value intersects a specified time
+ range.
+
+ The "start" attribute specifies the inclusive start of the time
+ range, and the "end" attribute specifies the non-inclusive end of
+ the time range. Both attributes MUST be specified as "date with
+ UTC time" value. Time ranges open at one end can be specified by
+ including only one attribute; however, at least one attribute MUST
+ always be present in the CALDAV:time-range element. If either the
+ "start" or "end" attribute is not specified in the CALDAV:time-
+ range XML element, assume "-infinity" and "+infinity" as their
+ value, respectively. If both "start" and "end" are present, the
+ value of the "end" attribute MUST be greater than the value of the
+ "start" attribute.
+
+ Time range tests MUST consider every recurrence instance when
+ testing the time range condition; if any one instance matches,
+ then the test returns true. Testing recurrence instances requires
+ the server to infer an effective value for DTSTART, DTEND,
+ DURATION, and DUE properties for an instance based on the
+ recurrence patterns and any overrides.
+
+ A VEVENT component overlaps a given time range if the condition
+ for the corresponding component state specified in the table below
+ is satisfied. Note that, as specified in [<a href="http://tools.ietf.org/html/rfc2445" title=""Internet Calendaring and Scheduling Core Object Specification (iCalendar)"">RFC2445</a>], the DTSTART
+ property is REQUIRED in the VEVENT component. The conditions
+ depend on the presence of the DTEND and DURATION properties in the
+ VEVENT component. Furthermore, the value of the DTEND property
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 90]</span>
+</pre><pre class="newpage"><a name="page-91" id="page-91" href="#page-91" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ MUST be later in time than the value of the DTSTART property. The
+ duration of a VEVENT component with no DTEND and DURATION
+ properties is 1 day (+P1D) when the DTSTART is a DATE value, and 0
+ seconds when the DTSTART is a DATE-TIME value.
+
+ +---------------------------------------------------------------+
+ | VEVENT has the DTEND property? |
+ | +-----------------------------------------------------------+
+ | | VEVENT has the DURATION property? |
+ | | +-------------------------------------------------------+
+ | | | DURATION property value is greater than 0 seconds? |
+ | | | +---------------------------------------------------+
+ | | | | DTSTART property is a DATE-TIME value? |
+ | | | | +-----------------------------------------------+
+ | | | | | Condition to evaluate |
+ +---+---+---+---+-----------------------------------------------+
+ | Y | N | N | * | (start < DTEND AND end > DTSTART) |
+ +---+---+---+---+-----------------------------------------------+
+ | N | Y | Y | * | (start < DTSTART+DURATION AND end > DTSTART) |
+ | | +---+---+-----------------------------------------------+
+ | | | N | * | (start <= DTSTART AND end > DTSTART) |
+ +---+---+---+---+-----------------------------------------------+
+ | N | N | N | Y | (start <= DTSTART AND end > DTSTART) |
+ +---+---+---+---+-----------------------------------------------+
+ | N | N | N | N | (start < DTSTART+P1D AND end > DTSTART) |
+ +---+---+---+---+-----------------------------------------------+
+
+ A VTODO component is said to overlap a given time range if the
+ condition for the corresponding component state specified in the
+ table below is satisfied. The conditions depend on the presence
+ of the DTSTART, DURATION, DUE, COMPLETED, and CREATED properties
+ in the VTODO component. Note that, as specified in [<a href="http://tools.ietf.org/html/rfc2445" title=""Internet Calendaring and Scheduling Core Object Specification (iCalendar)"">RFC2445</a>], the
+ DUE value MUST be a DATE-TIME value equal to or after the DTSTART
+ value if specified.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 91]</span>
+</pre><pre class="newpage"><a name="page-92" id="page-92" href="#page-92" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ +-------------------------------------------------------------------+
+ | VTODO has the DTSTART property? |
+ | +---------------------------------------------------------------+
+ | | VTODO has the DURATION property? |
+ | | +-----------------------------------------------------------+
+ | | | VTODO has the DUE property? |
+ | | | +-------------------------------------------------------+
+ | | | | VTODO has the COMPLETED property? |
+ | | | | +---------------------------------------------------+
+ | | | | | VTODO has the CREATED property? |
+ | | | | | +-----------------------------------------------+
+ | | | | | | Condition to evaluate |
+ +---+---+---+---+---+-----------------------------------------------+
+ | Y | Y | N | * | * | (start <= DTSTART+DURATION) AND |
+ | | | | | | ((end > DTSTART) OR |
+ | | | | | | (end >= DTSTART+DURATION)) |
+ +---+---+---+---+---+-----------------------------------------------+
+ | Y | N | Y | * | * | ((start < DUE) OR (start <= DTSTART)) |
+ | | | | | | AND |
+ | | | | | | ((end > DTSTART) OR (end >= DUE)) |
+ +---+---+---+---+---+-----------------------------------------------+
+ | Y | N | N | * | * | (start <= DTSTART) AND (end > DTSTART) |
+ +---+---+---+---+---+-----------------------------------------------+
+ | N | N | Y | * | * | (start < DUE) AND (end >= DUE) |
+ +---+---+---+---+---+-----------------------------------------------+
+ | N | N | N | Y | Y | ((start <= CREATED) OR (start <= COMPLETED))|
+ | | | | | | AND |
+ | | | | | | ((end >= CREATED) OR (end >= COMPLETED))|
+ +---+---+---+---+---+-----------------------------------------------+
+ | N | N | N | Y | N | (start <= COMPLETED) AND (end >= COMPLETED) |
+ +---+---+---+---+---+-----------------------------------------------+
+ | N | N | N | N | Y | (end > CREATED) |
+ +---+---+---+---+---+-----------------------------------------------+
+ | N | N | N | N | N | TRUE |
+ +---+---+---+---+---+-----------------------------------------------+
+
+ A VJOURNAL component overlaps a given time range if the condition
+ for the corresponding component state specified in the table below
+ is satisfied. The conditions depend on the presence of the
+ DTSTART property in the VJOURNAL component and on whether the
+ DTSTART is a DATE-TIME or DATE value. The effective "duration" of
+ a VJOURNAL component is 1 day (+P1D) when the DTSTART is a DATE
+ value, and 0 seconds when the DTSTART is a DATE-TIME value.
+
+
+
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 92]</span>
+</pre><pre class="newpage"><a name="page-93" id="page-93" href="#page-93" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ +----------------------------------------------------+
+ | VJOURNAL has the DTSTART property? |
+ | +------------------------------------------------+
+ | | DTSTART property is a DATE-TIME value? |
+ | | +--------------------------------------------+
+ | | | Condition to evaluate |
+ +---+---+--------------------------------------------+
+ | Y | Y | (start <= DTSTART) AND (end > DTSTART) |
+ +---+---+--------------------------------------------+
+ | Y | N | (start < DTSTART+P1D) AND (end > DTSTART) |
+ +---+---+--------------------------------------------+
+ | N | * | FALSE |
+ +---+---+--------------------------------------------+
+
+ A VFREEBUSY component overlaps a given time range if the condition
+ for the corresponding component state specified in the table below
+ is satisfied. The conditions depend on the presence in the
+ VFREEBUSY component of the DTSTART and DTEND properties, and any
+ FREEBUSY properties in the absence of DTSTART and DTEND. Any
+ DURATION property is ignored, as it has a special meaning when
+ used in a VFREEBUSY component.
+
+ When only FREEBUSY properties are used, each period in each
+ FREEBUSY property is compared against the time range, irrespective
+ of the type of free busy information (free, busy, busy-tentative,
+ busy-unavailable) represented by the property.
+
+
+ +------------------------------------------------------+
+ | VFREEBUSY has both the DTSTART and DTEND properties? |
+ | +--------------------------------------------------+
+ | | VFREEBUSY has the FREEBUSY property? |
+ | | +----------------------------------------------+
+ | | | Condition to evaluate |
+ +---+---+----------------------------------------------+
+ | Y | * | (start <= DTEND) AND (end > DTSTART) |
+ +---+---+----------------------------------------------+
+ | N | Y | (start < freebusy-period-end) AND |
+ | | | (end > freebusy-period-start) |
+ +---+---+----------------------------------------------+
+ | N | N | FALSE |
+ +---+---+----------------------------------------------+
+
+ A VALARM component is said to overlap a given time range if the
+ following condition holds:
+
+ (start <= trigger-time) AND (end > trigger-time)
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 93]</span>
+</pre><pre class="newpage"><a name="page-94" id="page-94" href="#page-94" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ A VALARM component can be defined such that it triggers repeatedly.
+ Such a VALARM component is said to overlap a given time range if at
+ least one of its triggers overlaps the time range.
+
+ The calendar properties COMPLETED, CREATED, DTEND, DTSTAMP,
+ DTSTART, DUE, and LAST-MODIFIED overlap a given time range if the
+ following condition holds:
+
+ (start <= date-time) AND (end > date-time)
+
+ Note that if DTEND is not present in a VEVENT, but DURATION is, then
+ the test should instead operate on the 'effective' DTEND, i.e.,
+ DTSTART+DURATION. Similarly, if DUE is not present in a VTODO, but
+ DTSTART and DURATION are, then the test should instead operate on the
+ 'effective' DUE, i.e., DTSTART+DURATION.
+
+ The semantic of CALDAV:time-range is not defined for any other
+ calendar components and properties.
+
+ Definition:
+
+ <!ELEMENT time-range EMPTY>
+
+ <!ATTLIST time-range start CDATA #IMPLIED
+ end CDATA #IMPLIED>
+ start value: an iCalendar "date with UTC time"
+ end value: an iCalendar "date with UTC time"
+
+<span class="h3"><h3><a name="section-9.10">9.10</a>. CALDAV:calendar-multiget XML Element</h3></span>
+
+ Name: calendar-multiget
+
+ Namespace: urn:ietf:params:xml:ns:caldav
+
+ Purpose: CalDAV report used to retrieve specific calendar object
+ resources.
+
+ Description: See <a href="#section-7.9">Section 7.9</a>.
+
+ Definition:
+
+ <!ELEMENT calendar-multiget ((DAV:allprop |
+ DAV:propname |
+ DAV:prop)?, DAV:href+)>
+
+
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 94]</span>
+</pre><pre class="newpage"><a name="page-95" id="page-95" href="#page-95" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+<span class="h3"><h3><a name="section-9.11">9.11</a>. CALDAV:free-busy-query XML Element</h3></span>
+
+ Name: free-busy-query
+
+ Namespace: urn:ietf:params:xml:ns:caldav
+
+ Purpose: CalDAV report used to generate a VFREEBUSY to determine
+ busy time over a specific time range.
+
+ Description: See <a href="#section-7.10">Section 7.10</a>.
+
+ Definition:
+
+ <!ELEMENT free-busy-query (time-range)>
+
+<span class="h2"><h2><a name="section-10">10</a>. Internationalization Considerations</h2></span>
+
+ CalDAV allows internationalized strings to be stored and retrieved
+ for the description of calendar collections (see <a href="#section-5.2.1">Section 5.2.1</a>).
+
+ The CALDAV:calendar-query REPORT (<a href="#section-7.8">Section 7.8</a>) includes a text
+ searching option controlled by the CALDAV:text-match element, and
+ details of character handling are covered in the description of that
+ element (see <a href="#section-9.7.5">Section 9.7.5</a>).
+
+<span class="h2"><h2><a name="section-11">11</a>. Security Considerations</h2></span>
+
+ HTTP protocol transactions are sent in the clear over the network
+ unless protection from snooping is negotiated. This can be
+ accomplished by use of TLS, as defined in [<a href="http://tools.ietf.org/html/rfc2818" title=""HTTP Over TLS"">RFC2818</a>]. In particular,
+ HTTP Basic authentication MUST NOT be used unless TLS is in effect.
+
+ Servers MUST take adequate precautions to ensure that malicious
+ clients cannot consume excessive server resources (CPU, memory, disk,
+ etc.) through carefully crafted reports. For example, a client could
+ upload an event with a recurrence rule that specifies a recurring
+ event occurring every second for the next 100 years, which would
+ result in approximately 3 x 10^9 instances! A report that asks for
+ recurrences to be expanded over that range would likely constitute a
+ denial-of-service attack on the server.
+
+ When creating new resources (including calendar collections), clients
+ MUST ensure that the resource name (the last path segment of the
+ resource URI) assigned to the new resource does not expose any data
+ from within the iCalendar resource itself or information about the
+ nature of a calendar collection. This is required to ensure that the
+ presence of a specific iCalendar component or nature of components in
+ a collection cannot be inferred based on the name of a resource.
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 95]</span>
+</pre><pre class="newpage"><a name="page-96" id="page-96" href="#page-96" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ When rolling up free-busy information, more information about a
+ user's events is exposed if busy periods overlap or are adjacent
+ (this tells the client requesting the free-busy information that the
+ calendar owner has at least two events, rather than knowing only that
+ the calendar owner has one or more events during the busy period).
+ Thus, a conservative approach to calendar data privacy would have
+ servers always coalesce such busy periods when they are the same
+ type.
+
+ Procedure alarms are a known security risk for either clients or
+ servers to handle, particularly when the alarm was created by another
+ agent. Clients and servers are not required to execute such
+ procedure alarms.
+
+ Security considerations described in iCalendar [<a href="http://tools.ietf.org/html/rfc2445" title=""Internet Calendaring and Scheduling Core Object Specification (iCalendar)"">RFC2445</a>] and iTIP
+ [<a href="http://tools.ietf.org/html/rfc2446" title=""iCalendar Transport-Independent Interoperability Protocol (iTIP) Scheduling Events, BusyTime, To-dos and Journal Entries"">RFC2446</a>] are also applicable to CalDAV.
+
+ Beyond these, CalDAV does not raise any security considerations that
+ are not present in HTTP [<a href="http://tools.ietf.org/html/rfc2616" title=""Hypertext Transfer Protocol -- HTTP/1.1"">RFC2616</a>] and WebDAV [<a href="http://tools.ietf.org/html/rfc2518" title=""HTTP Extensions for Distributed Authoring -- WEBDAV"">RFC2518</a>], [<a href="http://tools.ietf.org/html/rfc3253" title=""Versioning Extensions to WebDAV (Web Distributed Authoring and Versioning)"">RFC3253</a>],
+ [<a href="http://tools.ietf.org/html/rfc3744" title=""Web Distributed Authoring and Versioning (WebDAV) Access Control Protocol"">RFC3744</a>].
+
+<span class="h2"><h2><a name="section-12">12</a>. IANA Considerations</h2></span>
+
+ This document uses one new URN to identify a new XML namespace. The
+ URN conforms to a registry mechanism described in [<a href="http://tools.ietf.org/html/rfc3688" title=""The IETF XML Registry"">RFC3688</a>].
+
+<span class="h3"><h3><a name="section-12.1">12.1</a>. Namespace Registration</h3></span>
+
+ Registration request for the CalDAV namespace:
+
+ URI: urn:ietf:params:xml:ns:caldav
+
+ Registrant Contact: See the "Authors' Addresses" section of this
+ document.
+
+ XML: None. Namespace URIs do not represent an XML specification.
+
+<span class="h2"><h2><a name="section-13">13</a>. Acknowledgements</h2></span>
+
+ The authors would like to thank the following individuals for
+ contributing their ideas and support for writing this specification:
+ Michael Arick, Mario Bonin, Chris Bryant, Scott Carr, Andre
+ Courtemanche, Mike Douglass, Ted Hardie, Marten den Haring, Jeffrey
+ Harris, Sam Hartman, Helge Hess, Jeff McCullough, Alexey Melnikov,
+ Dan Mosedale, Brian Moseley, Francois Perrault, Kervin L. Pierre,
+ Julian F. Reschke, Wilfredo Sanchez Vega, Mike Shaver, Jari
+ Urpalainen, Simon Vaillancourt, and Jim Whitehead.
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 96]</span>
+</pre><pre class="newpage"><a name="page-97" id="page-97" href="#page-97" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ The authors would also like to thank the Calendaring and Scheduling
+ Consortium for advice with this specification, and for organizing
+ interoperability testing events to help refine it.
+
+<span class="h2"><h2><a name="section-14">14</a>. References</h2></span>
+
+<span class="h3"><h3><a name="section-14.1">14.1</a>. Normative References</h3></span>
+
+ [<a name="ref-RFC2119" id="ref-RFC2119">RFC2119</a>] Bradner, S., "Key words for use in RFCs to
+ Indicate Requirement Levels", <a href="http://tools.ietf.org/html/bcp14">BCP 14</a>,
+ <a href="http://tools.ietf.org/html/rfc2119">RFC 2119</a>, March 1997.
+
+ [<a name="ref-RFC2246" id="ref-RFC2246">RFC2246</a>] Dierks, T. and C. Allen, "The TLS Protocol
+ Version 1.0", <a href="http://tools.ietf.org/html/rfc2246">RFC 2246</a>, January 1999.
+
+ [<a name="ref-RFC2445" id="ref-RFC2445">RFC2445</a>] Dawson, F. and Stenerson, D., "Internet
+ Calendaring and Scheduling Core Object
+ Specification (iCalendar)", <a href="http://tools.ietf.org/html/rfc2445">RFC 2445</a>,
+ November 1998.
+
+ [<a name="ref-RFC2446" id="ref-RFC2446">RFC2446</a>] Silverberg, S., Mansour, S., Dawson, F., and
+ R. Hopson, "iCalendar Transport-Independent
+ Interoperability Protocol (iTIP) Scheduling
+ Events, BusyTime, To-dos and Journal
+ Entries", <a href="http://tools.ietf.org/html/rfc2446">RFC 2446</a>, November 1998.
+
+ [<a name="ref-RFC2518" id="ref-RFC2518">RFC2518</a>] Goland, Y., Whitehead, E., Faizi, A., Carter,
+ S., and D. Jensen, "HTTP Extensions for
+ Distributed Authoring -- WEBDAV", <a href="http://tools.ietf.org/html/rfc2518">RFC 2518</a>,
+ February 1999.
+
+ [<a name="ref-RFC2616" id="ref-RFC2616">RFC2616</a>] Fielding, R., Gettys, J., Mogul, J., Frystyk,
+ H., Masinter, L., Leach, P., and T. Berners-
+ Lee, "Hypertext Transfer Protocol --
+ HTTP/1.1", <a href="http://tools.ietf.org/html/rfc2616">RFC 2616</a>, June 1999.
+
+ [<a name="ref-RFC2818" id="ref-RFC2818">RFC2818</a>] Rescorla, E., "HTTP Over TLS", <a href="http://tools.ietf.org/html/rfc2818">RFC 2818</a>,
+ May 2000.
+
+ [<a name="ref-RFC3253" id="ref-RFC3253">RFC3253</a>] Clemm, G., Amsden, J., Ellison, T., Kaler,
+ C., and J. Whitehead, "Versioning Extensions
+ to WebDAV (Web Distributed Authoring and
+ Versioning)", <a href="http://tools.ietf.org/html/rfc3253">RFC 3253</a>, March 2002.
+
+ [<a name="ref-RFC3688" id="ref-RFC3688">RFC3688</a>] Mealling, M., "The IETF XML Registry",
+ <a href="http://tools.ietf.org/html/bcp81">BCP 81</a>, <a href="http://tools.ietf.org/html/rfc3688">RFC 3688</a>, January 2004.
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 97]</span>
+</pre><pre class="newpage"><a name="page-98" id="page-98" href="#page-98" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ [<a name="ref-RFC3744" id="ref-RFC3744">RFC3744</a>] Clemm, G., Reschke, J., Sedlar, E., and J.
+ Whitehead, "Web Distributed Authoring and
+ Versioning (WebDAV) Access Control Protocol",
+ <a href="http://tools.ietf.org/html/rfc3744">RFC 3744</a>, May 2004.
+
+ [<a name="ref-RFC4346" id="ref-RFC4346">RFC4346</a>] Dierks, T. and E. Rescorla, "The Transport
+ Layer Security (TLS) Protocol Version 1.1",
+ <a href="http://tools.ietf.org/html/rfc4346">RFC 4346</a>, April 2006.
+
+ [<a name="ref-RFC4790" id="ref-RFC4790">RFC4790</a>] Newman, C., Duerst, M., and A. Gulbrandsen,
+ "Internet Application Protocol Collation
+ Registry", <a href="http://tools.ietf.org/html/rfc4790">RFC 4790</a>, March 2007.
+
+ [<a name="ref-W3C.REC-xml-20060816" id="ref-W3C.REC-xml-20060816">W3C.REC-xml-20060816</a>] Paoli, J., Maler, E., Yergeau, F., Sperberg-
+ McQueen, C., and T. Bray, "Extensible Markup
+ Language (XML) 1.0 (Fourth Edition)", World
+ Wide Web Consortium Recommendation REC-xml-
+ 20060816, August 2006,
+ <<a href="http://www.w3.org/TR/2006/REC-xml-20060816">http://www.w3.org/TR/2006/REC-xml-20060816</a>>.
+
+<span class="h3"><h3><a name="section-14.2">14.2</a>. Informative References</h3></span>
+
+ [<a name="ref-RFC2426" id="ref-RFC2426">RFC2426</a>] Dawson, F. and T. Howes, "vCard MIME
+ Directory Profile", <a href="http://tools.ietf.org/html/rfc2426">RFC 2426</a>, September 1998.
+
+ [<a name="ref-RFC2739" id="ref-RFC2739">RFC2739</a>] Small, T., Hennessy, D., and F. Dawson,
+ "Calendar Attributes for vCard and LDAP",
+ <a href="http://tools.ietf.org/html/rfc2739">RFC 2739</a>, January 2000.
+
+ [<a name="ref-RFC4331" id="ref-RFC4331">RFC4331</a>] Korver, B. and L. Dusseault, "Quota and Size
+ Properties for Distributed Authoring and
+ Versioning (DAV) Collections", <a href="http://tools.ietf.org/html/rfc4331">RFC 4331</a>,
+ February 2006.
+
+ [<a name="ref-RFC4511" id="ref-RFC4511">RFC4511</a>] Sermersheim, J., "Lightweight Directory
+ Access Protocol (LDAP): The Protocol",
+ <a href="http://tools.ietf.org/html/rfc4511">RFC 4511</a>, June 2006.
+
+ [<a name="ref-rfc2518bis" id="ref-rfc2518bis">rfc2518bis</a>] Dusseault, L., <a style="text-decoration: none;" href="http://www.google.com/search?sitesearch=tools.ietf.org%2Fhtml%2F&q=inurl:draft-+%22HTTP+Extensions+for%0A+++++++++++++++++++++++++++Distributed+Authoring+-+WebDAV%22">"HTTP Extensions for
+ Distributed Authoring - WebDAV"</a>, Work
+ in Progress, December 2006.
+
+
+
+
+
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 98]</span>
+</pre><pre class="newpage"><a name="page-99" id="page-99" href="#page-99" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+<span class="h2"><h2><a name="appendix-A">Appendix A</a>. CalDAV Method Privilege Table (Normative)</h2></span>
+
+ The following table extends the WebDAV Method Privilege Table
+ specified in <a href="#appendix-B">Appendix B</a> of [<a href="http://tools.ietf.org/html/rfc3744" title=""Web Distributed Authoring and Versioning (WebDAV) Access Control Protocol"">RFC3744</a>].
+
+ +------------+------------------------------------------------------+
+ | METHOD | PRIVILEGES |
+ +------------+------------------------------------------------------+
+ | MKCALENDAR | DAV:bind |
+ | REPORT | DAV:read or CALDAV:read-free-busy (on all referenced |
+ | | resources) |
+ +------------+------------------------------------------------------+
+
+<span class="h2"><h2><a name="appendix-B">Appendix B</a>. Calendar Collections Used in the Examples</h2></span>
+
+ This appendix shows the calendar object resources contained in the
+ calendar collection queried in the examples throughout this document.
+
+ The content of the calendar collection is being shown as if it were
+ returned by a CALDAV:calendar-query REPORT request designed to return
+ all the calendar data in the collection:
+
+ >> Request <<
+
+ REPORT /bernard/work/ HTTP/1.1
+ Host: cal.example.com
+ Depth: 1
+ Content-Type: application/xml; charset="utf-8"
+ Content-Length: xxxx
+
+ <?xml version="1.0" encoding="utf-8" ?>
+ <C:calendar-query xmlns:D="DAV:"
+ xmlns:C="urn:ietf:params:xml:ns:caldav">
+ <D:prop>
+ <D:getetag/>
+ <C:calendar-data/>
+ </D:prop>
+ <C:filter>
+ <C:comp-filter name="VCALENDAR"/>
+ </C:filter>
+ </C:calendar-query>
+
+ >> Response <<
+
+ HTTP/1.1 207 Multi-Status
+ Content-Type: application/xml; charset="utf-8"
+ Content-Length: xxxx
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 99]</span>
+</pre><pre class="newpage"><a name="page-100" id="page-100" href="#page-100" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ <?xml version="1.0" encoding="utf-8" ?>
+ <D:multistatus xmlns:D="DAV:"
+ xmlns:C="urn:ietf:params:xml:ns:caldav">
+
+ <D:response>
+ <D:href>http://cal.example.com/bernard/work/abcd1.ics</D:href>
+ <D:propstat>
+ <D:prop>
+ <D:getetag>"fffff-abcd1"</D:getetag>
+ <C:calendar-data>BEGIN:VCALENDAR
+ VERSION:2.0
+ PRODID:-//Example Corp.//CalDAV Client//EN
+ BEGIN:VTIMEZONE
+ LAST-MODIFIED:20040110T032845Z
+ TZID:US/Eastern
+ BEGIN:DAYLIGHT
+ DTSTART:20000404T020000
+ RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+ TZNAME:EDT
+ TZOFFSETFROM:-0500
+ TZOFFSETTO:-0400
+ END:DAYLIGHT
+ BEGIN:STANDARD
+ DTSTART:20001026T020000
+ RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+ TZNAME:EST
+ TZOFFSETFROM:-0400
+ TZOFFSETTO:-0500
+ END:STANDARD
+ END:VTIMEZONE
+ BEGIN:VEVENT
+ DTSTAMP:20060206T001102Z
+ DTSTART;TZID=US/Eastern:20060102T100000
+ DURATION:PT1H
+ SUMMARY:Event #1
+ Description:Go Steelers!
+ UID:74855313FA803DA593CD579A@example.com
+ END:VEVENT
+ END:VCALENDAR
+ </C:calendar-data>
+ </D:prop>
+ <D:status>HTTP/1.1 200 OK</D:status>
+ </D:propstat>
+ </D:response>
+
+ <D:response>
+ <D:href>http://cal.example.com/bernard/work/abcd2.ics</D:href>
+ <D:propstat>
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 100]</span>
+</pre><pre class="newpage"><a name="page-101" id="page-101" href="#page-101" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ <D:prop>
+ <D:getetag>"fffff-abcd2"</D:getetag>
+ <C:calendar-data>BEGIN:VCALENDAR
+ VERSION:2.0
+ PRODID:-//Example Corp.//CalDAV Client//EN
+ BEGIN:VTIMEZONE
+ LAST-MODIFIED:20040110T032845Z
+ TZID:US/Eastern
+ BEGIN:DAYLIGHT
+ DTSTART:20000404T020000
+ RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+ TZNAME:EDT
+ TZOFFSETFROM:-0500
+ TZOFFSETTO:-0400
+ END:DAYLIGHT
+ BEGIN:STANDARD
+ DTSTART:20001026T020000
+ RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+ TZNAME:EST
+ TZOFFSETFROM:-0400
+ TZOFFSETTO:-0500
+ END:STANDARD
+ END:VTIMEZONE
+ BEGIN:VEVENT
+ DTSTAMP:20060206T001121Z
+ DTSTART;TZID=US/Eastern:20060102T120000
+ DURATION:PT1H
+ RRULE:FREQ=DAILY;COUNT=5
+ SUMMARY:Event #2
+ UID:00959BC664CA650E933C892C@example.com
+ END:VEVENT
+ BEGIN:VEVENT
+ DTSTAMP:20060206T001121Z
+ DTSTART;TZID=US/Eastern:20060104T140000
+ DURATION:PT1H
+ RECURRENCE-ID;TZID=US/Eastern:20060104T120000
+ SUMMARY:Event #2 bis
+ UID:00959BC664CA650E933C892C@example.com
+ END:VEVENT
+ END:VCALENDAR
+ </C:calendar-data>
+ </D:prop>
+ <D:status>HTTP/1.1 200 OK</D:status>
+ </D:propstat>
+ </D:response>
+
+ <D:response>
+ <D:href>http://cal.example.com/bernard/work/abcd3.ics</D:href>
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 101]</span>
+</pre><pre class="newpage"><a name="page-102" id="page-102" href="#page-102" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ <D:propstat>
+ <D:prop>
+ <D:getetag>"fffff-abcd3"</D:getetag>
+ <C:calendar-data>BEGIN:VCALENDAR
+ VERSION:2.0
+ PRODID:-//Example Corp.//CalDAV Client//EN
+ BEGIN:VTIMEZONE
+ LAST-MODIFIED:20040110T032845Z
+ TZID:US/Eastern
+ BEGIN:DAYLIGHT
+ DTSTART:20000404T020000
+ RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+ TZNAME:EDT
+ TZOFFSETFROM:-0500
+ TZOFFSETTO:-0400
+ END:DAYLIGHT
+ BEGIN:STANDARD
+ DTSTART:20001026T020000
+ RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+ TZNAME:EST
+ TZOFFSETFROM:-0400
+ TZOFFSETTO:-0500
+ END:STANDARD
+ END:VTIMEZONE
+ BEGIN:VEVENT
+ ATTENDEE;PARTSTAT=ACCEPTED;ROLE=CHAIR:mailto:cyrus@example.com
+ ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:lisa@example.com
+ DTSTAMP:20060206T001220Z
+ DTSTART;TZID=US/Eastern:20060104T100000
+ DURATION:PT1H
+ LAST-MODIFIED:20060206T001330Z
+ ORGANIZER:mailto:cyrus@example.com
+ SEQUENCE:1
+ STATUS:TENTATIVE
+ SUMMARY:Event #3
+ UID:DC6C50A017428C5216A2F1CD@example.com
+ END:VEVENT
+ END:VCALENDAR
+ </C:calendar-data>
+ </D:prop>
+ <D:status>HTTP/1.1 200 OK</D:status>
+ </D:propstat>
+ </D:response>
+
+ <D:response>
+ <D:href>http://cal.example.com/bernard/work/abcd4.ics</D:href>
+ <D:propstat>
+ <D:prop>
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 102]</span>
+</pre><pre class="newpage"><a name="page-103" id="page-103" href="#page-103" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ <D:getetag>"fffff-abcd4"</D:getetag>
+ <C:calendar-data>BEGIN:VCALENDAR
+ VERSION:2.0
+ PRODID:-//Example Corp.//CalDAV Client//EN
+ BEGIN:VTODO
+ DTSTAMP:20060205T235335Z
+ DUE;VALUE=DATE:20060104
+ STATUS:NEEDS-ACTION
+ SUMMARY:Task #1
+ UID:DDDEEB7915FA61233B861457@example.com
+ BEGIN:VALARM
+ ACTION:AUDIO
+ TRIGGER;RELATED=START:-PT10M
+ END:VALARM
+ END:VTODO
+ END:VCALENDAR
+ </C:calendar-data>
+ </D:prop>
+ <D:status>HTTP/1.1 200 OK</D:status>
+ </D:propstat>
+ </D:response>
+
+ <D:response>
+ <D:href>http://cal.example.com/bernard/work/abcd5.ics</D:href>
+ <D:propstat>
+ <D:prop>
+ <D:getetag>"fffff-abcd5"</D:getetag>
+ <C:calendar-data>BEGIN:VCALENDAR
+ VERSION:2.0
+ PRODID:-//Example Corp.//CalDAV Client//EN
+ BEGIN:VTODO
+ DTSTAMP:20060205T235300Z
+ DUE;VALUE=DATE:20060106
+ LAST-MODIFIED:20060205T235308Z
+ SEQUENCE:1
+ STATUS:NEEDS-ACTION
+ SUMMARY:Task #2
+ UID:E10BA47467C5C69BB74E8720@example.com
+ BEGIN:VALARM
+ ACTION:AUDIO
+ TRIGGER;RELATED=START:-PT10M
+ END:VALARM
+ END:VTODO
+ END:VCALENDAR
+ </C:calendar-data>
+ </D:prop>
+ <D:status>HTTP/1.1 200 OK</D:status>
+ </D:propstat>
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 103]</span>
+</pre><pre class="newpage"><a name="page-104" id="page-104" href="#page-104" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ </D:response>
+
+ <D:response>
+ <D:href>http://cal.example.com/bernard/work/abcd6.ics</D:href>
+ <D:propstat>
+ <D:prop>
+ <D:getetag>"fffff-abcd6"</D:getetag>
+ <C:calendar-data>BEGIN:VCALENDAR
+ VERSION:2.0
+ PRODID:-//Example Corp.//CalDAV Client//EN
+ BEGIN:VTODO
+ COMPLETED:20051223T122322Z
+ DTSTAMP:20060205T235400Z
+ DUE;VALUE=DATE:20051225
+ LAST-MODIFIED:20060205T235308Z
+ SEQUENCE:1
+ STATUS:COMPLETED
+ SUMMARY:Task #3
+ UID:E10BA47467C5C69BB74E8722@example.com
+ END:VTODO
+ END:VCALENDAR
+ </C:calendar-data>
+ </D:prop>
+ <D:status>HTTP/1.1 200 OK</D:status>
+ </D:propstat>
+ </D:response>
+
+ <D:response>
+ <D:href>http://cal.example.com/bernard/work/abcd7.ics</D:href>
+ <D:propstat>
+ <D:prop>
+ <D:getetag>"fffff-abcd7"</D:getetag>
+ <C:calendar-data>BEGIN:VCALENDAR
+ VERSION:2.0
+ PRODID:-//Example Corp.//CalDAV Client//EN
+ BEGIN:VTODO
+ DTSTAMP:20060205T235600Z
+ DUE;VALUE=DATE:20060101
+ LAST-MODIFIED:20060205T235308Z
+ SEQUENCE:1
+ STATUS:CANCELLED
+ SUMMARY:Task #4
+ UID:E10BA47467C5C69BB74E8725@example.com
+ END:VTODO
+ END:VCALENDAR
+ </C:calendar-data>
+ </D:prop>
+ <D:status>HTTP/1.1 200 OK</D:status>
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 104]</span>
+</pre><pre class="newpage"><a name="page-105" id="page-105" href="#page-105" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+ </D:propstat>
+ </D:response>
+
+ <D:response>
+ <D:href>http://cal.example.com/bernard/work/abcd8.ics</D:href>
+ <D:propstat>
+ <D:prop>
+ <D:getetag>"fffff-abcd8"</D:getetag>
+ <C:calendar-data>BEGIN:VCALENDAR
+ VERSION:2.0
+ PRODID:-//Example Corp.//CalDAV Client//EN
+ BEGIN:VFREEBUSY
+ ORGANIZER;CN="Bernard Desruisseaux":mailto:bernard@example.com
+ UID:76ef34-54a3d2@example.com
+ DTSTAMP:20050530T123421Z
+ DTSTART:20060101T000000Z
+ DTEND:20060108T000000Z
+ FREEBUSY:20050531T230000Z/20050601T010000Z
+ FREEBUSY;FBTYPE=BUSY-TENTATIVE:20060102T100000Z/20060102T120000Z
+ FREEBUSY:20060103T100000Z/20060103T120000Z
+ FREEBUSY:20060104T100000Z/20060104T120000Z
+ FREEBUSY;FBTYPE=BUSY-UNAVAILABLE:20060105T100000Z/20060105T120000Z
+ FREEBUSY:20060106T100000Z/20060106T120000Z
+ END:VFREEBUSY
+ END:VCALENDAR
+ </C:calendar-data>
+ </D:prop>
+ <D:status>HTTP/1.1 200 OK</D:status>
+ </D:propstat>
+ </D:response>
+
+ </D:multistatus>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 105]</span>
+</pre><pre class="newpage"><a name="page-106" id="page-106" href="#page-106" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+Authors' Addresses
+
+ Cyrus Daboo
+ Apple Inc.
+ 1 Infinite Loop
+ Cupertino, CA 95014
+ USA
+
+ EMail: cyrus@daboo.name
+ URI: <a href="http://www.apple.com/">http://www.apple.com/</a>
+
+
+ Bernard Desruisseaux
+ Oracle Corporation
+ 600 Blvd. de Maisonneuve West
+ Suite 1900
+ Montreal, QC H3A 3J2
+ CANADA
+
+ EMail: bernard.desruisseaux@oracle.com
+ URI: <a href="http://www.oracle.com/">http://www.oracle.com/</a>
+
+
+ Lisa Dusseault
+ CommerceNet
+ 169 University Ave.
+ Palo Alto, CA 94301
+ USA
+
+ EMail: ldusseault@commerce.net
+ URI: <a href="http://commerce.net/">http://commerce.net/</a>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<span class="grey">Daboo, et al. Standards Track [Page 106]</span>
+</pre><pre class="newpage"><a name="page-107" id="page-107" href="#page-107" class="invisible"> </a>
+<span class="grey"><a href="http://tools.ietf.org/html/rfc4791">RFC 4791</a> CalDAV March 2007</span>
+
+
+Full Copyright Statement
+
+ Copyright (C) The IETF Trust (2007).
+
+ This document is subject to the rights, licenses and restrictions
+ contained in <a href="http://tools.ietf.org/html/bcp78">BCP 78</a>, and except as set forth therein, the authors
+ retain all their rights.
+
+ This document and the information contained herein are provided on an
+ "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+ OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND
+ THE INTERNET ENGINEERING TASK FORCE DISCLAIM 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.
+
+Intellectual Property
+
+ The IETF takes no position regarding the validity or scope of any
+ Intellectual Property Rights or other rights that might be claimed to
+ pertain to the implementation or use of the technology described in
+ this document or the extent to which any license under such rights
+ might or might not be available; nor does it represent that it has
+ made any independent effort to identify any such rights. Information
+ on the procedures with respect to rights in RFC documents can be
+ found in <a href="http://tools.ietf.org/html/bcp78">BCP 78</a> and <a href="http://tools.ietf.org/html/bcp79">BCP 79</a>.
+
+ Copies of IPR disclosures made to the IETF Secretariat and any
+ assurances of licenses to be made available, or the result of an
+ attempt made to obtain a general license or permission for the use of
+ such proprietary rights by implementers or users of this
+ specification can be obtained from the IETF on-line IPR repository at
+ <a href="http://www.ietf.org/ipr">http://www.ietf.org/ipr</a>.
+
+ The IETF invites any interested party to bring to its attention any
+ copyrights, patents or patent applications, or other proprietary
+ rights that may cover technology that may be required to implement
+ this standard. Please address the information to the IETF at
+ ietf-ipr@ietf.org.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+Daboo, et al. Standards Track [Page 107]
+</pre><pre class="newpage">
+</pre><br>
+<span class="noprint"><small><small>Html markup produced by rfcmarkup 1.74, available from
+<a href="http://tools.ietf.org/tools/rfcmarkup/">http://tools.ietf.org/tools/rfcmarkup/</a>
+</small></small></span>
+</body></html>
\ No newline at end of file
--- /dev/null
+<?php
+/* $Id$ */
+
+ require_once 'caldavresource.class.php';
+
+ define ('FREQUENCE', 'HOURLY,DAILY,WEEKLY,MONTHLY,YEARLY');
+
+ /**
+ * Unsupported: SECONDLY, MINUTELY, YEARLY,
+ * BYSECOND, BYMINUTE, BYSETPOS, WKST
+ * Also preceeding where preceeding is allowed is not
+ * supported either.
+ */
+ class RRuleParser {
+
+ private $rules;
+ private $start;
+ private $end;
+ private $range_start;
+ private $range_end;
+ private $freq;
+
+ function __construct($rrule = NULL, $start = NULL, $end = NULL) {
+ $this->freq = preg_split("/[\s,]+/", FREQUENCE);
+ if ($rrule)
+ $this->setRule($rrule, $start, $end);
+ }
+
+ function setRule($rrule, $start, $end) {
+ if (!($start && $end))
+ throw new Exception("Missing values for DTSTART and/or DTEND");
+ //print "$start:$end<br/>";
+ //print var_export($rrule, TRUE) . "<br/>";
+ $this->start = CaldavRessource::iCal2Timestamp($start);
+ $this->end = CaldavRessource::iCal2Timestamp($end);
+ //print CaldavRessource::timestamp2ICal($this->start, TRUE).":".CaldavRessource::timestamp2ICal($this->end, TRUE)."<br/>";
+ $rules = explode(';', $rrule);
+ //print_r($rules);
+ if (count($rules) < 2) {
+ foreach ($rules as $rule) {
+ $pair = explode('=', $rule);
+ if (count($pair) < 2 || !in_array($pair[1], $this->freq)) {
+ $this->rules = array();
+ throw new Exception("$rrule: Invalid RRULE");
+ }
+ $this->rules[strtolower($pair[0])] = explode(',', $pair[1]);
+ }
+ }
+ else {
+ foreach ($rules as $rule) {
+ $pair = explode('=', $rule);
+ $this->rules[strtolower($pair[0])] = explode(',', $pair[1]);
+ }
+ }
+ if ($this->rules['until'][0] && $this->rules['count'][0]) {
+ $this->rules = array();
+ throw new Exception("COUNT and UNTIL cannot be present at the same time");
+ }
+ if (!in_array($this->rules['freq'][0], $this->freq)) {
+ trigger_error(
+ "[{$this->rules['freq'][0]}] Unsupported FREQ",
+ E_USER_NOTICE);
+ $this->rules = array();
+ }
+ }
+
+ private function getEnd($freq) {
+ $count = $this->getCount();
+ $until = $this->getUntil();
+ //print "$until<br/>";
+ if ($count) {
+ $int = $this->getInterval();
+ $count = ($int) ? $int * $count : $count;
+ switch ($freq) {
+ case 'HOURLY': $str = "+$count hour"; break;
+ case 'DAILY': $str = "+$count day"; break;
+ case 'WEEKLY': $str = "+$count week"; break;
+ case 'MONTHLY': $str = "+$count month"; break;
+ case 'YEARLY': $str = "+$count year"; break;
+ }
+ $end = strtotime($str, $this->start);
+ return ($this->range_end && $this->range_end < $end) ?
+ $this->range_end : $end;
+ }
+ else if ($until) {
+ /*
+ * UNTIL has first occurrence at end time and
+ * last ocurrence ending at start time
+ */
+ //print "$until:".$this->start."<br/>";
+ $u_s = explode("T", CaldavRessource::timestamp2ICal($this->end));
+ $time_s = (int) substr($u_s[1], 0, 2);
+ $u_e = explode("T", $until);
+ $time_e = (int) substr($u_e[1], 0, 2);
+ $until = ($time_s != $time_e) ? "{$u_e[0]}T{$u_s[1]}" : $until;
+ //print "$time_s:$time_e:$until<br/>";
+ $end = CaldavRessource::iCal2Timestamp($until);
+ //print CaldavRessource::timestamp2ICal($end)."<br/>";
+ return ($this->range_end && $this->range_end < $end) ?
+ $this->range_end : $end;
+ }
+ else
+ return $this->range_end;
+ }
+
+ private function except($ts) {
+ $byhour = $this->getByHour();
+ if ($byhour) {
+ $res = TRUE;
+ $match = gmdate('G', $ts);
+ foreach ($byhour as $hour) {
+ if ($match == $hour)
+ $res = FALSE;
+ if (! $res)
+ return FALSE;
+ }
+ return TRUE;
+ }
+ $byday = $this->getByDay();
+ if ($byday) {
+ $res = TRUE;
+ $match = substr(strtolower(gmdate('D', $ts)), 0, 2);
+ foreach ($byday as $day) {
+ //print "$match:$day\n";
+ if ($match == strtolower($day))
+ $res = FALSE;
+ if (! $res)
+ return FALSE;
+ }
+ return TRUE;
+ }
+ $bymonth = $this->getByMonth();
+ if ($bymonth) {
+ $res = TRUE;
+ $match = gmdate('n', $ts);
+ foreach ($bymonth as $month) {
+ if ($match == $month)
+ $res = FALSE;
+ if (! $res)
+ return FALSE;
+ }
+ return TRUE;
+ }
+ $bymonthday = $this->getByMonthDay();
+ if ($bymonthday) {
+ $res = TRUE;
+ $match = gmdate('j', $ts);
+ foreach ($bymonthday as $monthday) {
+ if ($match + 1 == $monthday)
+ $res = FALSE;
+ if (! $res)
+ return FALSE;
+ }
+ return TRUE;
+ }
+ $byweekno = $this->getByWeekNo();
+ if ($byweekno) {
+ $res = TRUE;
+ // Missing to handle Anglo week numbers
+ // (week start on Sunday)
+ $match = gmdate('W', $ts);
+ foreach ($byweekno as $weekno) {
+ if ($match == $weekno)
+ $res = FALSE;
+ if (! $res)
+ return FALSE;
+ }
+ return TRUE;
+ }
+ $byyearday = $this->getByYearDay();
+ if ($byyearday) {
+ $res = TRUE;
+ $match = gmdate('z', $ts);
+ foreach ($byyearday as $yearday) {
+ if ($match == $yearday)
+ $res = FALSE;
+ if (! $res)
+ return FALSE;
+ }
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+ private function hourly() {
+ $res = array();
+ $end = $this->getEnd('HOURLY');
+ if (! $end) {
+ /**
+ * we will maximum handle one month at a time unless
+ * a specific end date specifies otherwise
+ */
+ $end = strtotime('+1 month', $this->start);
+ }
+ $int = ($this->getInterval()) ? $this->getInterval() : 1;
+ $c = $this->start;
+ for (; $c < $end; $c = strtotime("+$int hour", $c)) {
+ if (! $this->except($c))
+ array_push($res, CaldavRessource::timestamp2ICal($c));
+ }
+ return $res;
+ }
+
+ private function daily() {
+ $res = array();
+ $end = $this->getEnd('DAILY');
+ if (! $end) {
+ /**
+ * we will maximum handle one month at a time unless
+ * a specific end date specifies otherwise
+ */
+ $end = strtotime('+1 month', $this->start);
+ }
+ $int = ($this->getInterval()) ? $this->getInterval() : 1;
+ $c = $this->start;
+ for (; $c < $end; $c = strtotime("+$int day", $c)) {
+ if (! $this->except($c))
+ array_push($res, CaldavRessource::timestamp2ICal($c));
+ }
+ return $res;
+ }
+
+ private function weekly() {
+ $res = array();
+ $end = $this->getEnd('WEEKLY');
+ //print "start: ".CaldavRessource::timestamp2ICal($this->start)." end: ".CaldavRessource::timestamp2ICal($end)."\n";
+ if (! $end) {
+ /**
+ * we will maximum handle 12 weeks at a time unless
+ * a specific end date specifies otherwise
+ */
+ $end = strtotime('+12 week', $this->start);
+ }
+ $int = ($this->getInterval()) ? $this->getInterval() : 1;
+ $c = $this->start;
+ for (; $c < $end; $c = strtotime("+$int week", $c)) {
+ //print CaldavRessource::timestamp2ICal($c)."<br/>";
+ if (! $this->except($c))
+ array_push($res, CaldavRessource::timestamp2ICal($c));
+ }
+ //print_r($res);
+ return $res;
+ }
+
+ private function monthly() {
+ $res = array();
+ $end = $this->getEnd('MONTHLY');
+ if (! $end) {
+ /**
+ * we will maximum handle 12 months at a time unless
+ * a specific end date specifies otherwise
+ */
+ $end = strtotime('+12 month', $this->start);
+ }
+ $int = ($this->getInterval()) ? $this->getInterval() : 1;
+ $c = $this->start;
+ for (; $c < $end; $c = strtotime("+$int month", $c)) {
+ if (! $this->except($c))
+ array_push($res, CaldavRessource::timestamp2ICal($c));
+ }
+ return $res;
+ }
+
+ private function yearly() {
+ $res = array();
+ $end = $this->getEnd('YEARLY');
+ if (! $end) {
+ /**
+ * we will maximum handle 12 years at a time unless
+ * a specific end date specifies otherwise
+ */
+ $end = strtotime('+12 year', $this->start);
+ }
+ $int = ($this->getInterval()) ? $this->getInterval() : 1;
+ $c = $this->start;
+ for (; $c < $end; $c = strtotime("+$int year", $c)) {
+ if (! $this->except($c))
+ array_push($res, CaldavRessource::timestamp2ICal($c));
+ }
+ return $res;
+ }
+
+ private function limitRange($dates) {
+ $res = array();
+ if (!$this->range_start && !$this->range_end) {
+ $res = $dates;
+ }
+ else if ($this->range_start && !$this->range_end) {
+ $start = CaldavRessource::timestamp2ICal($this->range_start);
+ foreach ($dates as $date) {
+ if (CaldavRessource::datecmp($start, $date) < 0)
+ array_push($res, $date);
+ }
+ }
+ else {
+ $start = CaldavRessource::timestamp2ICal($this->range_start);
+ $end = CaldavRessource::timestamp2ICal($this->range_end);
+ foreach ($dates as $date) {
+ if (CaldavRessource::datecmp($start, $date) < 0 &&
+ CaldavRessource::datecmp($end, $date) > 0)
+ array_push($res, $date);
+ }
+ }
+ return $res;
+ }
+
+ function getFreq() {
+ return strtoupper($this->rules['freq'][0]);
+ }
+
+ function getUntil() {
+ return strtoupper($this->rules['until'][0]);
+ }
+
+ function getCount() {
+ return strtoupper($this->rules['count'][0]);
+ }
+
+ function getInterval() {
+ return strtoupper($this->rules['interval'][0]);
+ }
+
+ function getBySecond() {
+ $l = $this->rules['bysecond'];
+ if ($l) {
+ foreach ($l as $val)
+ $list[] = strtoupper($val);
+ }
+ return $list;
+ }
+
+ function getByMinute() {
+ $l = $this->rules['byminute'];
+ if ($l) {
+ foreach ($l as $val)
+ $list[] = strtoupper($val);
+ }
+ return $list;
+ }
+
+ function getByHour() {
+ $l = $this->rules['byhour'];
+ if ($l) {
+ foreach ($l as $val)
+ $list[] = strtoupper($val);
+ }
+ return $list;
+ }
+
+ function getByDay() {
+ $l = $this->rules['byday'];
+ if ($l) {
+ foreach ($l as $val)
+ $list[] = strtoupper($val);
+ }
+ return $list;
+ }
+
+ function getByMonthDay() {
+ $l = $this->rules['bymonthday'];
+ if ($l) {
+ foreach ($l as $val)
+ $list[] = strtoupper($val);
+ }
+ return $list;
+ }
+
+ function getByYearDay() {
+ $l = $this->rules['byyearday'];
+ if ($l) {
+ foreach ($l as $val)
+ $list[] = strtoupper($val);
+ }
+ return $list;
+ }
+
+ function getByWeekNo() {
+ $l = $this->rules['byweekno'];
+ if ($l) {
+ foreach ($l as $val)
+ $list[] = strtoupper($val);
+ }
+ return $list;
+ }
+
+ function getByMonth() {
+ $l = $this->rules['bymonth'];
+ if ($l) {
+ foreach ($l as $val)
+ $list[] = strtoupper($val);
+ }
+ return $list;
+ }
+
+ function getBySetPos() {
+ return strtoupper($this->rules['bysetpos'][0]);
+ }
+
+ function getWKST() {
+ return strtoupper($this->rules['wkst'][0]);
+ }
+
+ function getAll() {
+ return $this->rules;
+ }
+
+ function getEventDates($startDate = NULL, $endDate = NULL) {
+ $dates = array();
+
+ $freq = $this->getFreq();
+ //print "$freq\n";
+ if (! in_array($freq, $this->freq))
+ return $dates;
+ if ($startDate && $endDate) {
+ $this->range_start = CaldavRessource::iCal2Timestamp($startDate);
+ $this->range_end = CaldavRessource::iCal2Timestamp($endDate);
+ if ($this->start > $this->range_end)
+ return $dates;
+ }
+ else if ($startDate) {
+ $this->range_start = CaldavRessource::iCal2Timestamp($startDate);
+ $this->range_end = NULL;
+ }
+ else {
+ $this->range_start = NULL;
+ $this->range_end = NULL;
+ }
+ switch ($freq) {
+ case 'HOURLY': $dates = $this->hourly(); break;
+ case 'DAILY': $dates = $this->daily(); break;
+ case 'WEEKLY': $dates = $this->weekly(); break;
+ case 'MONTHLY': $dates = $this->monthly(); break;
+ case 'YEARLY': $dates = $this->yearly(); break;
+ default: break;
+ }
+ //print_r($dates);
+ return (count($dates) > 0) ? $this->limitRange($dates) : $dates;
+ }
+
+ function getStartAndEnd() {
+ $res['start'] = $this->start;
+ $res['end'] = $this->end;
+
+ return $res;
+ }
+
+ function __toString() {
+ $str = "FREQ=" . $this->getFreq();
+ $until = $this->getUntil();
+ $count = $this->getCount();
+ if ($until)
+ $str .= ';UNTIL=' . $until;
+ if ($count)
+ $str .= ';COUNT=' . $count;
+ foreach ($this->rules as $k => $v) {
+ if ($k == 'freq' || $k == 'count' || $k == 'until')
+ continue;
+ $str .= ';' . strtoupper($k) . '=';
+ foreach($v as $rule) {
+ if ($str[strlen($str) - 1] != '=')
+ $str .= ',';
+ $str .= strtoupper($rule);
+ }
+ }
+ return $str;
+ }
+
+ }
--- /dev/null
+<?php
+/* $Id$ */
+
+ require_once 'awl/iCalendar.php';
+ require_once 'caldavresource.class.php';
+ require_once 'icomponent.class.php';
+ require_once 'rruleparser.class.php';
+
+ class VEvent extends IComponent {
+
+ private $rulesParser;
+
+ function __construct($etag, $url, VTYPE $type, iCalendar $item, $new) {
+ parent::__construct($etag, $url, $type, $item, $new);
+ $this->rulesParser = new RRuleParser();
+ }
+
+ function isActive($start, $end) {
+ $res = FALSE;
+ if (!($start && $end))
+ return TRUE;
+ if (! CaldavRessource::isDateTime($start) ||
+ ! CaldavRessource::isDateTime($end))
+ throw new Exception(
+ "[$start,$end] Invalid CalDAV DateTime format");
+ $event = $this->getBaseComponent();
+ if ($start && !$end) {
+ if (CaldavRessource::datecmp(
+ $start, $event->GetPValue('DTSTART')) < 0)
+ $res = TRUE;
+ }
+ else {
+ if (CaldavRessource::datecmp(
+ $start, $event->GetPValue('DTSTART')) < 0 &&
+ CaldavRessource::datecmp(
+ $end, $event->GetPValue('DTEND')) > 0)
+ $res = TRUE;
+ }
+ return $res;
+ }
+
+ function getActiveDates($range_start = NULL, $range_end = NULL) {
+ $res = array();
+ $event = $this->getBaseComponent();
+ //print_r($event);
+ $start = $event->GetPValue('DTSTART');
+ $end = $event->GetPValue('DTEND');
+ //print "$start:$end<br/>";
+ if (! ($start && $end))
+ return $res;
+ $rrule = $event->GetPValue('RRULE');
+ if ($rrule) {
+ $this->rulesParser->setRule($rrule, $start, $end);
+ //print $this->rulesParser->__toString()."\n";
+ $res = $this->rulesParser->getEventDates(
+ $range_start, $range_end);
+ //print_r($res);
+ }
+ else {
+ if ($this->isActive($range_start, $range_end))
+ array_push($res, $start);
+ }
+ //var_dump($res);
+ return $res;
+ }
+
+ function getRRule() {
+ return $this->rulesParser;
+ }
+
+ function getAlarm() {
+ $alarm = $this->getComponent(VTYPE::VALARM);
+// print_r($alarm);
+ if ($alarm)
+ $alarm = $alarm[0];
+ return $alarm;
+ }
+
+ function setProperty($name, $value) {
+ $component = $this->getBaseComponent();
+ $properties = $component->GetProperties();
+ $match = FALSE;
+ $update = FALSE;
+
+ if (count($properties) > 0) {
+ foreach ($properties as $property) {
+ //echo "B: " . $property->Name(). ":" . $property->Value() . "<br/>";
+ $test1 = explode(';', $name);
+ $test2 = explode(';', $property->Name());
+ if (strcasecmp($test1[0], $test2[0]) === 0) {
+ if (strcmp($property->Value(), $value) !== 0) {
+ $property->Value($value);
+ //echo "B: " . $property->Name(). ":" . $property->Value() . "<br/>";
+ $update = TRUE;
+ }
+ $match = TRUE;
+ }
+ }
+ }
+ if ($match == FALSE) {
+ $component->AddProperty(strtoupper($name), $value);
+ $update = TRUE;
+ }
+ else {
+ if ($update)
+ $component->SetProperties($properties);
+ }
+ if ($update) {
+ $this->addDefault($component);
+ $this->setDirty();
+ }
+ //$properties = $component->GetProperties();
+ //foreach ($properties as $property) {
+ // echo "A: " . $property->Name(). ":" . $property->Value() . "<br/>";
+ //}
+ //echo "<br/>";
+ //exit;
+ }
+
+ private function AddDefault(iCalComponent $component) {
+ $properties = $component->GetProperties();;
+ $now = gmdate("Ymd\THis\Z");
+ $a = array(1,1,1);
+ foreach ($properties as $property) {
+ //echo "D: " . $property->Name(). ":" . $property->Value() . "<br/>";
+ if (strcasecmp('DTSTAMP', $property->Name()) === 0) {
+ $property->Value($now);
+ $a[0] = 0;
+ }
+ if (strcasecmp('LAST-MODIFIED', $property->Name()) === 0) {
+ $property->Value($now);
+ $a[1] = 0;
+ }
+ if (strcasecmp('X-WEBCAL-GENERATION', $property->Name()) === 0) {
+ $property->Value('1');
+ $a[2] = 0;
+ }
+ }
+ for ($i = 0; $i < count($a); $i++) {
+ //echo $i.':'.$a[$i]."<br/>";
+ if ($a[$i]) {
+ switch ($i) {
+ case 0: $c['DTSTAMP'] = $now; break;
+ case 1: $c['LAST-MODIFIED'] = $now; break;
+ case 2: $c['X-WEBCAL-GENERATION'] = 1; break;
+ default: continue;
+ }
+ $key = key($c);
+ $val = $c[$key];
+ $component->AddProperty($key, $val);
+ $c = NULL;
+ }
+ }
+ }
+ }
--- /dev/null
+/* $Id$ */
+
+body {
+ background-color: #FAFAFA;
+ color: #000000;
+ font-family: 'bitstream vera sans', 'vera sans', sans-serif;
+ font-size: 0.8em;
+}
+
+a:link {
+ color: #000099;
+ text-decoration: none;
+}
+
+a:visited {
+ color: #000099;
+ text-decoration: none;
+}
+
+a:active {
+ color: black;
+ text-decoration: none;
+}
+
+a:hover {
+ color: #000099;
+}
+
+img.floatleft {
+ float: left;
+ margin: 2px;
+}
+
+img.floatright {
+ float: right;
+ margin: 2px;
+}
+
+#menu {
+ background-color: #FFFFC4;
+ color: inherit;
+ margin-top: 0px;
+ font-size: 0.8em;
+}
+
+#menu table {
+ width: 100%;
+}
+
+#menu td {
+ width: 25px;
+ text-align: center;
+}
+
+#menu img {
+ border: 0;
+ display: block;
+ margin-right: auto;
+ margin-left: auto;
+}
+
+#ui {
+/* background-color: transparent;*/
+ background-color: #F1F9FF;
+ color: #000000;
+ margin: 20px;
+ border: 2px ridge #1D388C;
+ padding: 1%;
+ min-height: 450px;
+ height: auto;
+/* <!--[if lt IE 7]>
+ _height: 450px;
+ <![endif]-->*/
+}
+
+#ui a:link {
+ color: green;
+ text-decoration: none;
+}
+
+#ui a:visited {
+ color: green;
+ text-decoration: none;
+}
+
+#ui a:active {
+ color: green;
+ text-decoration: none;
+}
+
+#ui a:hover {
+ color: green;
+ text-decoration: underline;
+}
+
+#ui table.config {
+ border-width: 1px;
+ border-style: solid;
+ margin-right: auto;
+ margin-left: auto;
+}
+
+#ui th {
+ border-bottom: 3px solid;
+}
+
+#ui td.config {
+ padding: 2px;
+}
+
+#ui p.usermanage {
+ text-align: center;
+}
+
+#footer {
+ text-align: left;
+ font-size: 0.8em;
+}
+
+#footer img {
+ border: 0;
+ float: right;
+}
+
+#cal {
+ font-family: 'bitstream vera sans', 'vera sans', sans-serif;
+ font-size: 1em;
+}
+
+#cal input {
+ font-size: 1em;
+}
+
+#cal td {
+ font-size: 1em;
+}
+
+#cal table {
+ border-width: 1px;
+ border-style: solid;
+ margin-right: auto;
+ margin-left: auto;
+}
+
+#events {
+}
+
+#events th {
+ text-align: center;
+ border-width: 1px 1px 1px 1px;
+ padding: 2px 2px 2px 2px;
+ border-style: solid solid solid solid;
+ border-color: #2C9185 #2C9185 #2C9185 #2C9185;
+ background-color: #CEFFFA;
+}
+
+#events th.event {
+ width: 13.5%;
+}
+
+#events th.day_event {
+ width: 90%;
+}
+
+#events td {
+ border-width: 1px 1px 1px 1px;
+ padding: 2px 2px 2px 2px;
+ border-style: solid solid solid solid;
+ border-color: #2C9185 #2C9185 #2C9185 #2C9185;
+ background-color: #FFFFFF;
+}
+
+#events td.weeknum, td.time {
+ background-color: #8FCDC7;
+ text-align: center;
+ font-weight: bold;
+}
+
+#events td.notused {
+ background-color: #BFBFBF;
+}
+
+#events td.today {
+ background-color: #FAF8D2;
+}
+
+#events .date {
+ border-left-width: 1px;
+ border-bottom-width: 0px;
+ border-right-width: 0px;
+ border-top-width: 1px;
+ border-style: solid;
+ padding: 1px;
+ font-size: x-small;
+ float: right;
+}
+
+#events table {
+ width: 100%;
+ border-width: 2px 2px 2px 2px;
+ border-spacing: 0px;
+ border-style: solid solid solid solid;
+ border-color: #2C9185 #2C9185 #2C9185 #2C9185;
+ border-collapse: separate;
+ background-color: transparent;
+}
+
+#error_msg {
+ display: block;
+ margin-right: auto;
+ margin-left: auto;
+ margin-top: 10%;
+ padding: 5px;
+ width: 400px;
+ border-width: 5px;
+ border-spacing: 0px;
+ border-style: solid solid solid solid;
+ border-color: black;
+ border-collapse: separate;
+ background-color: red;
+ color: black;
+}
+
+#update_msg {
+ display: block;
+ margin-right: auto;
+ margin-left: auto;
+ margin-top: 10%;
+ padding: 5px;
+ width: 400px;
+ border-width: 5px;
+ border-spacing: 0px;
+ border-style: solid solid solid solid;
+ border-color: black;
+ border-collapse: separate;
+ background-color: yellow;
+ color: black;
+}
+
+#login_msg {
+ display: block;
+ margin-right: auto;
+ margin-left: auto;
+ margin-top: 10%;
+ padding: 5px;
+ width: 400px;
+ border-width: 5px;
+ border-spacing: 0px;
+ border-style: solid solid solid solid;
+ border-color: black;
+ border-collapse: separate;
+ background-color: #F1F9FF;
+ color: black;
+}
+
+#login_msg table {
+ margin-right: auto;
+ margin-left: auto;
+}
+
+#event {
+ padding: 1%;
+}
+
+#event input, select {
+ font-family: 'bitstream vera sans', 'vera sans', sans-serif;
+ font-size: 1.0em;
+}
+
+#event table {
+ margin-right: auto;
+ margin-left: auto;
+}
+
+.bold {
+ font-weight: bold;
+}
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- $Id$ -->
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+ <head>
+ <title>Web Calendar</title>
+ <link rel="stylesheet" type="text/css" href="css/top_level.css" />
+ <link rel="shortcut icon" href="pixmaps/favicon.ico" />
+ </head>
+ <body>
+ <div id="error_msg">
+ <h1 style="text-align: center">Redirecting Error occured</h1>
+ <p style="text-align: center">
+ Your session has expired<br/>
+ or you have tried to by-pass the login system.<br/>
+ You can increase your session timeout in the config menu.
+ </p>
+ <p style="text-align: center">
+ Please login <a href="login.php">here</a>
+ </p>
+ </div>
+ </body>
+</html>
--- /dev/null
+<?php
+require_once 'calendar.class.php';
+require_once 'user_validate.php';
+require_once 'helper.php';
+
+valid_user();
+
+include_once 'config.inc.php';
+
+if (! defined($_SESSION['__ROOT__']) && empty($_SESSION['__ROOT__'])) {
+ session_destroy();
+ header('Location: ' . WEB_ROOT . 'error.html');
+ exit;
+}
+
+$query = construct_URL($_SERVER['QUERY_STRING'],
+ array('etag', 'referer', 'cal'));
+//print_r($query);
+//echo '<br/>';
+//print_r($_SESSION['all_events']);
+//exit;
+if (isset($query['cal']) && ! empty($query['cal']) &&
+ isset($query['etag']) && ! empty($query['etag'])) {
+ $_SESSION['calendar'] = $_SESSION['all_events'][$query['cal']];
+ if (! is_object($_SESSION['calendar']))
+ throw new Exception("Missing calendar object");
+
+ foreach ($_SESSION['calendar'] as $vevent) {
+ if ($vevent->getEtag() == $query['etag']) {
+ $res = $_SESSION['calendar']->delete($vevent->getUrl(), $vevent->getEtag());
+ }
+ }
+ //print $query['referer'];
+ header('Location: '. urldecode($query['referer']));
+ exit;
+}
+else {
+ $text = '<h3 style="text-align: center">Choose an event from one of the listed calendars</h3>';
+ $text .= '<p>';
+ $text .= '<form id="cals" style="text-align: center" action="'.
+ $_SERVER['PHP_SELF'].'" method="get">';
+ $text .= '<input type="hidden" name="referer" value="'.urldecode($query['referer']).'" />';
+ $text .= '<input type="hidden" id="cal" name="cal" value="" />';
+ $calendar = '';
+ foreach ($_SESSION['all_events'] as $name => $cal) {
+ //$calendar .= "$name<br/>".var_export($cal, true)."<br/>";
+ $text .= $name.': <select name="etag"
+ onchange="setCalendar(\'cals\', \'cal\', '."'$name'".')">';
+ $text .= '<option selected="selected"></option>';
+ foreach ($cal as $vevent) {
+ $calendar .= $vevent->getEtag()."<br/>";
+ $text .= '<option value="'.$vevent->getEtag().'">'.
+ $vevent->getDetails().'</option>';
+ }
+ $text .= '</select><br/><br/>';
+ }
+ $text .= '<input type="submit" value="Continue" />';
+ $text .= '</form></p>';
+ //print urldecode($query['referer']);
+ //exit;
+ print popup_window($text, $query['referer']);
+ exit;
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+/* $Id$ */
+
+require_once 'calendar.class.php';
+require_once 'user_validate.php';
+require_once 'helper.php';
+
+valid_user();
+
+include_once 'config.inc.php';
+include_once 'eventgui.class.php';
+
+if (! defined($_SESSION['__ROOT__']) && empty($_SESSION['__ROOT__'])) {
+ session_destroy();
+ header('Location: ' . WEB_ROOT . 'error.html');
+ exit;
+}
+
+if (isset($_SESSION['authenticate']) && $_SESSION['authenticate']->validUser()) {
+ $view_style = ($_SESSION['user_settings']->getViewStyle()) ?
+ $_SESSION['user_settings']->getViewStyle() : VIEW_STYLE;
+// $timeout = ($_SESSION['user_settings']->getTimeout()) ?
+// (int) $_SESSION['user_settings']->getTimeout() : TIMEOUT;
+ $week_start_sunday = ($_SESSION['user_settings']->getStartWeek() !== NULL) ?
+ $_SESSION['user_settings']->getStartWeek() : WEEK_START_SUNDAY;
+ $start_hour = ($_SESSION['user_settings']->getStartHour()) ?
+ (int) $_SESSION['user_settings']->getStartHour() : START_HOUR;
+ $end_hour = ($_SESSION['user_settings']->getEndHour()) ?
+ (int) $_SESSION['user_settings']->getEndHour() : END_HOUR;
+}
+
+$pwd = WEB_ROOT;
+if ($pwd[strlen($pwd)-1] == '/')
+ $pwd = substr($pwd, 0, -1);
+
+if (isset($_POST) && count($_POST) > 0) {
+ $exclude = array('tzid','range','times','untildate');
+ $start = array('date' => NULL, 'time' => NULL);
+ $end = array('date' => NULL, 'time' => NULL);
+ $referer = $_POST['referer'];
+ $allDay = false;
+
+ foreach ($_POST as $key => $value) {
+ //echo "$key => $value<br/>";
+ if (strcmp($key, 'referer') == 0)
+ continue;
+ if (in_array($key, $exclude))
+ continue;
+ if (strcasecmp($key, 'startdate') == 0) {
+ $start['date'] = join('', explode('-',$value));
+ continue;
+ }
+ if (strcasecmp($key, 'starttime') == 0) {
+ $start['time'] = $value;
+ if (strlen($start['time']) < 5)
+ $start['time'] .= '00';
+ continue;
+ }
+ if (strcasecmp($key, 'enddate') == 0) {
+ $end['date'] = join('', explode('-',$value));
+ continue;
+ }
+ if (strcasecmp($key, 'endtime') == 0) {
+ $end['time'] = $value;
+ if (strlen($end['time']) < 5)
+ $end['time'] .= '00';
+ continue;
+ }
+ if (strcasecmp("allDay", $key) == 0) {
+ $allDay = true;
+ continue;
+ }
+ if (strcasecmp("recurrence", $key) == 0) {
+ $value = "FREQ=$value";
+ $key = "RRULE";
+ }
+ //echo "$key => $value<br/>";
+ $_SESSION['current_event']->setProperty($key, $value);
+ }
+ //echo 'DTSTART: '. $start['date'].'T'.$start['time'];
+ //echo '<br/>DTEND: '. $end['date'].'T'.$end['time'];
+ //exit;
+ if ($allDay) {
+ $_SESSION['current_event']->setProperty(
+ 'DTSTART;VALUE=DATE', $start['date']);
+ $_SESSION['current_event']->setProperty(
+ 'DTEND;VALUE=DATE', $end['date']);
+ //echo "<br/>".$start['date']."<br/>";
+ //echo $end['date']."<br/>";
+ }
+ else {
+ $start = strtotime($start['date'].'T'.$start['time']);
+ $end = strtotime($end['date'].'T'.$end['time']);
+ //echo "<br/>".Calendar::timestamp2ICal($start, FALSE)."<br/>";
+ //echo Calendar::timestamp2ICal($end, FALSE)."<br/>";
+ //exit;
+ $_SESSION['current_event']->setProperty('DTSTART',
+ Calendar::timestamp2ICal($start, FALSE));
+ $_SESSION['current_event']->setProperty('DTEND',
+ Calendar::timestamp2ICal($end, FALSE));
+ }
+ //exit;
+ if (isset($_SESSION['calendar'])) {
+ $res = $_SESSION['calendar']->update(
+ $_SESSION['current_event']->getUrl(),
+ $_SESSION['current_event']->getEtag());
+ //print_r($res);
+ //exit;
+ unset($_SESSION['current_event']);
+ unset($_SESSION['calendar']);
+ unset($_SESSION['EVENT_ACTION']);
+ if (count($res) == 0) {
+ header('Location: ' . $referer);
+ exit;
+ }
+ $msg = '';
+ foreach ($res as $elem) {
+ $k = key($elem);
+ $msg .= "$k: " . $elem[$k];
+ }
+ }
+ else
+ throw new Exception("Error updating event");
+ //print "$msg\n";
+ $msg = join("", explode("\n", $msg));
+ $title = TITLE;
+ $pwd = WEB_ROOT;
+$head = <<<__HEAD
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<title>$title</title>
+<meta http-equiv="content-type" content="application/xhtml+xml; charset=UTF-8"/>
+<meta http-equiv="content-style-type" content="text/css"/>
+<link rel="stylesheet" type="text/css" href="$pwd/css/top_level.css" />
+<link rel="shortcut icon" href="$pwd/pixmaps/favicon.ico" />
+<script type="text/javascript" src="$pwd/js/helper.js"></script>
+</head>
+<body onload="error('$msg')">
+<table style="width: 100%;">
+<tr>
+<td style="width: 33%"><img src="$pwd/pixmaps/calendar.png" alt="calendar.png" /></td>
+<td style="width: 33%; text-align: center;"><a href="$pwd/logout.php"><img style="border: 0" src="$pwd/pixmaps/exit.png" width="32" height="32" alt="Logout" /><br/>Logout</a></td>
+<td style="text-align: right"><span style="font-size: 1.6em">DAViCal Web Calendar</span><br/> - A Web Interface for <a href="javascript: newwin('http://www.davical.org/');">DAViCal</a></td>
+</tr>
+</table>
+__HEAD;
+ print "$head";
+ include TOP_FOLDER.'/include/menu.inc.php';
+ print "<div id=\"ui\"></div>";
+ include TOP_FOLDER.'/include/footer.inc.php';
+ exit;
+}
+else {
+ $query = construct_URL($_SERVER['QUERY_STRING'],
+ array('etag', 'referer', 'cal'));
+ //print_r($_SESSION['all_events'][$query['cal']]);
+ //exit;
+ if (isset($query['cal']) && ! empty($query['cal'])) {
+ $_SESSION['calendar'] = $_SESSION['all_events'][$query['cal']];
+ if (! is_object($_SESSION['calendar']))
+ throw new Exception("Missing calendar object");
+
+ if ($_SESSION['EVENT_ACTION'] == 'NEW') {
+ $event = $_SESSION['calendar']->newComponent('VEVENT');
+ $_SESSION['current_event'] = $event;
+ }
+ else {
+ foreach ($_SESSION['calendar'] as $vevent) {
+ if ($vevent->getEtag() == $query['etag']) {
+ $event = $vevent;
+ break;
+ }
+ }
+ $_SESSION['current_event'] = $event;
+ }
+ //print $query['referer'];
+ //exit;
+ $gui = new EventGUI($event, $query['referer'], $query['cal']);
+ //unset($_GET['referer']);
+ $calendar = $gui->getView();
+ }
+ else {
+ $text = '<h3 style="text-align: center">Choose an event from one of the listed calendars</h3>';
+ $text .= '<p>';
+ $text .= '<form id="cals" style="text-align: center" action="'.
+ $_SERVER['PHP_SELF'].'" method="get">';
+ $text .= '<input type="hidden" name="referer" value="'.urldecode($query['referer']).'" />';
+ $text .= '<input type="hidden" id="cal" name="cal" value="" />';
+ $calendar = '';
+ foreach ($_SESSION['all_events'] as $name => $cal) {
+ //$calendar .= "$name<br/>".var_export($cal, true)."<br/>";
+ $text .= $name.': <select name="etag"
+ onchange="setCalendar(\'cals\', \'cal\', '."'$name'".')">';
+ $text .= '<option selected="selected"></option>';
+ foreach ($cal as $vevent) {
+ $calendar .= $vevent->getEtag()."<br/>";
+ $text .= '<option value="'.$vevent->getEtag().'">'.
+ $vevent->getDetails().'</option>';
+ }
+ $text .= '</select><br/><br/>';
+ }
+ $text .= '<input type="submit" value="Continue" />';
+ $text .= '</form></p>';
+ //print "{$_GET['referer']}";
+ //exit;
+ print popup_window($text, $query['referer']);
+ exit;
+ }
+}
+include TOP_FOLDER.'/include/header.inc.php';
+include TOP_FOLDER.'/include/menu.inc.php';
+
+print "<div id=\"ui\">$calendar</div>";
+include TOP_FOLDER.'/include/footer.inc.php';
+?>
--- /dev/null
+<?php
+/* $Id$ */
+
+include_once 'config.inc.php';
+include_once 'dateformat.class.php';
+include_once 'caldavresource.class.php';
+require_once 'calendar.class.php';
+require_once 'helper.php';
+
+class EventGUI {
+
+ private $event;
+ private $referer;
+ private $summary;
+ private $location;
+ private $description;
+ private $start;
+ private $end;
+ private $timezone;
+ private $dates;
+ private $rrule;
+ private $startdate;
+ private $enddate;
+ private $until;
+ private $cal;
+
+ function __construct(VEvent $event = NULL, $referer = '', $cal = NULL) {
+ $this->event = $event;
+ $this->referer = urldecode($referer);
+ $this->cal = $cal;
+ //print $this->referer;
+ //exit;
+ $this->summary = '';
+ $this->location = '';
+ $this->description = '';
+ $this->start = '';
+ $this->end = '';
+ $this->timezone = '';
+ $this->localtime = ($_SESSION['user_settings']->getTimeZone() !== NULL) ?
+ $_SESSION['user_settings']->getTimeZone() : TIMEZONE;
+ $root = WEB_ROOT;
+ $week_start_sunday = ($_SESSION['user_settings']->getStartWeek() !== NULL) ?
+ $_SESSION['user_settings']->getStartWeek() : WEEK_START_SUNDAY;
+ $week_start_sunday = ($week_start_sunday) ? 0 : 1;
+ $this->startdate = <<< __CAL1
+ <script type="text/javascript">
+ A_TCALDEF['imgpath'] = '{$root}js/img/';
+ A_TCALDEF['weekstart'] = $week_start_sunday;
+ new tcal ({
+ 'formname': 'event_data',
+ 'controlname': 'startdate'
+ });
+ </script>
+__CAL1;
+ $this->enddate = <<< __CAL1
+ <script type="text/javascript">
+ A_TCALDEF['imgpath'] = '{$root}js/img/';
+ A_TCALDEF['weekstart'] = $week_start_sunday;
+ new tcal ({
+ 'formname': 'event_data',
+ 'controlname': 'enddate'
+ });
+ </script>
+__CAL1;
+ $this->until = <<< __CAL1
+ <script type="text/javascript">
+ A_TCALDEF['imgpath'] = '{$root}js/img/';
+ A_TCALDEF['weekstart'] = $week_start_sunday;
+ new tcal ({
+ 'formname': 'event_data',
+ 'controlname': 'untildate'
+ });
+ </script>
+__CAL1;
+ }
+
+ private function parseEvent() {
+ if (! $this->event)
+ return FALSE;
+ $comp = $this->event->getBaseComponent();
+ $this->summary = $comp->GetPValue('SUMMARY');
+ $this->location = $comp->GetPValue('LOCATION');
+ $this->description = $comp->GetPValue('DESCRIPTION');
+ $this->start = $comp->GetPValue('DTSTART');
+ $this->end = $comp->GetPValue('DTEND');
+ $this->timezone = $this->event->getTZID();
+ $rrule = $this->event->getRRule();
+ $this->dates = $rrule->getEventDates();
+ $this->rrule = $rrule->getAll();
+ //echo $this->start .':'. $this->end .'<br/>';
+ return TRUE;
+ }
+
+ private function createDT($elem, $name) {
+ $res = array();
+
+ //print_r($elem);
+ //echo '<br/>';
+ if (count($elem) > 1) {
+ $date = $elem[0];
+ $time = substr($elem[1], 0, 4);
+ }
+ else {
+ $date = $elem[0];
+ $time = '2359';
+ }
+ for ($i = 0; $i < substr($time, 2); $i += 15);
+ if ($i < 10)
+ $i = "0$i";
+ $time = substr($time, 0, 2) . $i;
+ //echo "$time<br/>";
+ $options = array();
+ for ($i = 0; $i < 24; $i++) {
+ $h = ($i < 10) ? "0$i" : $i;
+ $stop = ($i == 23) ? 61 : 60;
+ for ($j = 0; $j < $stop; $j += 15) {
+ $m = ($j < 10) ? "0$j" : $j;
+ if ($m == 60)
+ $m = 59;
+ $hm = "$h$m";
+ //echo "$hm<br/>";
+ $option = "<option value=\"$hm\"";
+ if ($hm == $time)
+ $option .= ' selected="selected"';
+ $option .= ">$hm</option>";
+ array_push($options, $option);
+ }
+ }
+ $select = "<select name=\"$name\" id=\"$name\">";
+ foreach ($options as $option)
+ $select .= $option;
+ $select .= '</select>';
+ $date = substr($date, 0, 4).'-'.substr($date, 4, 2).'-'.substr($date, 6);
+ //echo "$date<br/>";
+ $res['date'] = $date;
+ $res['time'] = $select;
+ return $res;
+ }
+
+ private function createTime() {
+ include_once 'timezone.php';
+
+ if ($this->start == '' || $this->end == '') {
+ $this->start = date("Ymd\THis");
+ $this->end = date("Ymd\THis", strtotime("+1 hour"));
+ $this->timezone = $_SESSION['user_settings']->getTimeZone();
+ }
+ //echo $this->start .':'. $this->end .'<br/>';
+ $tz = '<select name="tzid">';
+ foreach ($timezones as $timezone) {
+ $tz .= "<option value=\"$timezone\"";
+ if ($this->localtime == $timezone)
+ $tz .= ' selected="selected"';
+ $tz .= ">$timezone</option>";
+ }
+ $tz .= "</select>";
+ $dateFormat = new DateFormat();
+ $UTCStart = $dateFormat->UTC2Client($this->start);
+ $UTCEnd = $dateFormat->UTC2Client($this->end);
+ //echo $UTCStart .':'. $UTCEnd .'<br/>';
+ $startArray = explode('T', $UTCStart);
+ //echo "Client: ".$dateFormat->client2UTC($dateFormat->UTC2Client($this->start))."<br/>";
+ //echo "Local: ".$dateFormat->UTC2Local($this->start)."<br/>";
+ $start = $this->createDT($startArray, 'starttime');
+ $endArray = explode('T', $UTCEnd);
+ $end = $this->createDT($endArray, 'endtime');
+ $allDay = CaldavRessource::allDayEvent($UTCStart, $UTCEnd);
+ $allDay = ($allDay) ? 'checked="checked"' : '';
+ $datetime = "<table><caption style=\"font-weight: bold\">Date & Time</caption>
+ <tr>
+ <td>All Day Event</td>
+ <td>
+ <script type=\"text/javascript\">
+ var observable1 = ['starttime', 'tcalico_1', 'enddate', 'endtime'];
+ document.write('<input type=\"checkbox\" name=\"allDay\" $allDay' +
+ 'id=\"allDay\" onchange=\"stateSwitch(this, observable1, 0)\"/>');
+ </script>
+ </td>
+ <td> </td>
+ </tr>
+ <tr>
+ <td>Start</td>
+ <td>
+ <script type=\"text/javascript\">
+ document.write('<input type=\"text\" name=\"startdate\" ' +
+ 'id=\"startdate\" size=\"12\" onchange=\"dateAlign(' +
+ 'this)\" value=\"{$start['date']}\"/>');
+ </script>
+ $this->startdate
+ <!--{$start['date']}-->
+ </td>
+ <td>{$start['time']}</td>
+ <td rowspan=\"2\">$tz</td>
+ </tr>
+ <tr>
+ <td>End</td>
+ <td>
+ <script type=\"text/javascript\">
+ document.write('<input name=\"enddate\" type=\"text\" ' +
+ 'id=\"enddate\" size=\"12\" onchange=\"dateAlign(' +
+ 'this)\" value=\"{$end['date']}\"/>');
+ </script>
+ $this->enddate
+ <!--{$end['date']}-->
+ </td>
+ <td>
+ {$end['time']}
+ <script type=\"text/javascript\">
+ var observable4 = ['starttime', 'tcalico_1', 'enddate', 'endtime'];
+ stateSwitch(document.getElementById('allDay'), observable4, 1);
+ </script>
+ </td>
+ </tr>
+ </table>";
+ return $datetime;
+ }
+
+ private function recurRule($checked) {
+ $choices = array('DAILY', 'WEEKLY', 'MONTHLY', 'YEARLY');
+ $rule = '<span style="font-weight: bold">Recurrence Types</span><br/>';
+ foreach ($choices as $choice) {
+ $rule .= "<input type=\"radio\" name=\"recurrence\" value=\"$choice\"";
+ if (strtoupper($checked) == $choice)
+ $rule .= ' checked="checked"';
+ $rule .= "/>$choice<br/>";
+ }
+ return $rule;
+ }
+
+ private function rangeRule($rules) {
+ $until = '';
+ $times = '';
+ $count_check = '';
+ $until_check = '';
+ $no_check = '';
+
+ $range = $rules['until'][0];
+ if (! $range) {
+ $range = $rules['count'][0];
+ if ($range) {
+ $times = $range;
+ $count_check = 'checked="checked"';
+ }
+ else {
+ $no_check = 'checked="checked"';
+ }
+ }
+ else {
+ $until = substr($range, 0, 4).'-'.substr($range, 4, 2).
+ '-'.substr($range, 6, 2);
+ $until_check = 'checked="checked"';
+ }
+ $rule = <<<_RULE
+ <span style="font-weight: bold">Recurrence Range</span><br/>
+ <input type="radio" name="range" value="UNLIMITED" $no_check/>
+ No ending date<br/>
+ <input type="radio" name="range" value="COUNT" $count_check/>
+ End after
+ <input type="text" name="times" size="4"
+ value="$times"/> Occurrence(s)<br/>
+ <input type="radio" name="range" value="UNTIL" $until_check/>
+ End on
+ <input type="text" name="untildate" size="12" value="$until"/>
+ {$this->until}
+_RULE;
+ return $rule;
+ }
+
+ private function createRecur() {
+ $recur = NULL;
+ $rrule = NULL;
+ if ($this->rrule) {
+ $rrule = array_diff_key($this->rrule, array('freq' => ''));
+ switch ($this->rrule['freq'][0]) {
+ case 'DAILY': $recur = 'DAILY'; break;
+ case 'WEEKLY': $recur = 'WEEKLY'; break;
+ case 'MONTHLY': $recur = 'MONTHLY'; break;
+ case 'YEARLY': $recur = 'YEARLY'; break;
+ }
+ }
+ $recur = $this->recurRule($recur);
+ $range = $this->rangeRule($rrule);
+ //print htmlentities($recur);
+ $res = <<<_TABLE
+ <table cellpadding="10">
+ <caption style="font-weight: bold">Recurrence Rule</caption>
+ <tr>
+ <td valign="top">$recur</td>
+ <td valign="top">$range</td>
+ </tr>
+ </table>
+_TABLE;
+ return $res;
+ }
+
+ function getView() {
+ $title = '<input name="summary" size="53" value="_SUM_"/>';
+ $location = '<input name="location" size="53" value="_LOC_"/>';
+ $description =
+ '<textarea name="description" cols="60" rows="5">_DESC_</textarea>';
+ if ($this->parseEvent()) {
+ $title = str_replace('_SUM_', $this->summary, $title);
+ $location = str_replace('_LOC_', $this->location, $location);
+ $description = str_replace('_DESC_', $this->description, $description);
+ }
+ else {
+ $title = str_replace('_SUM_', '', $title);
+ $location = str_replace('_LOC_', '', $location);
+ $description = str_replace('_DESC_', '', $description);
+ }
+ $btn_label = ($_SESSION['EVENT_ACTION'] == 'NEW') ? "Create" : "Update";
+ unset($_SESSION['EVENT_ACTION']);
+ // for delete button
+ $etag = $this->event->getEtag();
+ $url = $this->event->getUrl();
+ $view = dirname($_SERVER['PHP_SELF']).'/delete_event.php';
+ //['starttime', 'enddate', 'endtime']
+ $view = "<div id=\"event\">
+ <form id=\"event_data\" method=\"post\" action=\"{$_SERVER['PHP_SELF']}\"
+ onsubmit=\"return enableAll(['starttime', 'enddate', 'endtime'])\">
+ <table>
+ <caption style=\"font-weight: bold\">General</caption>
+ <tr>
+ <td>Title</td><td>$title</td>
+ </tr>
+ <tr>
+ <td>Location</td><td>$location</td>
+ </tr>
+ <tr>
+ <td>Description</td><td>$description</td>
+ </tr>
+ </table><p/>".
+ $this->createTime()."<p/>".
+ $this->createRecur().
+ "<p style=\"text-align: center\">
+ <input type=\"hidden\" value=\"$this->referer\" name=\"referer\"/>
+ <input type=\"button\" value=\"Cancel\"
+ onclick=\"document.location.href='$this->referer'\"/>
+ <input type=\"submit\" value=\"$btn_label\"/>
+ <!--onclick=\"document.getElementById('event_data').submit()\"/>-->
+ <input type=\"button\" value=\"Delete\"
+ onclick=\"document.location.href='$view?etag=$etag&url=$url'+
+ '&cal=$this->cal&referer=$this->referer'\"/>
+ <!--onclick=\"javascript: alert('Update not available')\"/>-->
+ <!--<input type=\"submit\" name=\"update\" value=\"Update\"/>-->
+ </p>
+ </form>
+ </div>";
+ return $view;
+ }
+
+}
+
+?>
--- /dev/null
+<?php
+require_once 'calendar.class.php';
+require_once 'user_validate.php';
+
+valid_user();
+
+include_once 'config.inc.php';
+require_once 'helper.php';
+
+if (! defined($_SESSION['__ROOT__']) && empty($_SESSION['__ROOT__'])) {
+ session_destroy();
+ header('Location: ' . WEB_ROOT . 'error.html');
+ exit;
+}
+$path = dirname($_SERVER['PHP_SELF']);
+$url = "$path/edit_event.php";
+$_SESSION['EVENT_ACTION'] = 'NEW';
+$calendars = $_SESSION['user_settings']->getCalendars();
+$query = construct_URL($_SERVER['QUERY_STRING'],
+ array('etag', 'referer', 'cal'));
+
+if (count($calendars) < 1) {
+ header('Location: ' . WEB_ROOT . "utils/configure.php");
+ exit;
+}
+else if (count($calendars) == 1) {
+ $options = "?referer=".$query['referer'];
+ $options .= "&cal=" . current($calendars)->name;
+ header('Location: ' . $url . $options);
+ //print "$url$options<br/>";
+ exit;
+}
+else {
+ $cal = current($calendars)->name;
+ $text = '<p>';
+ $text .= '<form style="text-align: center" action="'.$url.'" method="get">';
+ $text .= '<input type="hidden" name="referer" value="'.$query['referer'].'" />';
+ $text .= 'Choose Calender: ';
+ $text .= '<select name="cal">';
+ foreach ($calendars as $calendar) {
+ $text .= '<option value="'.$calendar->name.'">'.$calendar->name.'</option>';
+ }
+ $text .= '</select><br/><br/>';
+ $text .= '<input type="submit" value="Continue" />';
+ $text .= '</form></p>';
+ print popup_window($text, $query['referer']."?cal=$cal");
+ exit;
+}
+?>
\ No newline at end of file
--- /dev/null
+<?php
+require_once 'calendar.class.php';
+require_once 'user_validate.php';
+require_once 'helper.php';
+
+valid_user();
+
+include_once 'config.inc.php';
+
+if (! defined($_SESSION['__ROOT__']) && empty($_SESSION['__ROOT__'])) {
+ session_destroy();
+ header('Location: ' . WEB_ROOT . 'error.html');
+ exit;
+}
+$calendars = $_SESSION['user_settings']->getCalendars();
+$query = construct_URL($_SERVER['QUERY_STRING'],
+ array('etag', 'referer', 'cal'));
+//print_r(urldecode($query['referer']));
+//exit;
+$url = $query['referer'].'?';
+foreach ($query as $key => $value) {
+ if (strcasecmp($key, 'referer') === 0)
+ continue;
+ if ($url[strlen($url) - 1] == '?')
+ $url .= "$key=$value";
+ else
+ $url .= "&$key=$value";
+}
+if ($url[strlen($url) - 1] == '?')
+ $url = substr($url, 0, -1);
+header('Location: ' . urldecode($url));
+exit;
+?>
\ No newline at end of file
--- /dev/null
+<?php
+/* $Id$ */
+require_once 'config.inc.php';
+require_once 'persistens.php';
+require_once 'helper.php';
+
+$con = Persistens::getInstance(DBDRIVER);
+if (! is_array($res = $con->getVersion())) {
+ ErrorReport($res);
+}
+$title = TITLE;
+$foot = <<<_FOOTER
+<div id="footer">
+<p>
+ $title {$res[0]} - © 2010, 2011 Michael Rasmussen<br/>Released under GPLv3
+ <a href="http://validator.w3.org/check?uri=referer">
+ <img src="http://www.w3.org/Icons/valid-xhtml10-blue.png"
+ alt="Valid XHTML 1.0 Strict" height="31" width="88" />
+ </a>
+ <a href="http://jigsaw.w3.org/css-validator/check/referer">
+ <img src="http://www.w3.org/Icons/valid-css2-blue.png"
+ alt="Valid CSS 2.0" height="31" width="88" />
+ </a>
+</p>
+</div>
+</body>
+</html>
+_FOOTER;
+
+//file_put_contents('/tmp/davical.log', $foot, FILE_APPEND);
+print $foot;
--- /dev/null
+<?php
+/* $Id$ */
+require_once 'config.inc.php';
+require_once 'helper.php';
+
+$pwd = WEB_ROOT;
+if ($pwd[strlen($pwd)-1] == '/')
+ $pwd = substr($pwd, 0, -1);
+$title = TITLE;
+
+$head = <<<_HEAD
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<title>$title</title>
+<meta name="generator" content="Bluefish 1.0.7"/>
+<meta name="author" content="Michael Rasmussen"/>
+<meta name="date" content="2009-03-23T20:45:48+0100"/>
+<meta name="copyright" content="© 2007, Michael Rasmussen. Licensed under GPL"/>
+<meta name="keywords" content=""/>
+<meta name="description" content=""/>
+<meta name="ROBOTS" content="NOINDEX, NOFOLLOW"/>
+<meta http-equiv="content-type" content="application/xhtml+xml; charset=UTF-8"/>
+<meta http-equiv="content-style-type" content="text/css"/>
+<meta http-equiv="expires" content="-1"/>
+<meta http-equiv="Pragma" content="no-cache"/>
+<link rel="stylesheet" type="text/css" href="$pwd/css/top_level.css" />
+<link rel="shortcut icon" href="$pwd/pixmaps/favicon.ico" />
+<script type="text/javascript" src="$pwd/js/calendar_db.js"></script>
+<link rel="stylesheet" type="text/css" href="$pwd/js/calendar.css" />
+<script type="text/javascript" src="$pwd/js/helper.js"></script>
+</head>
+<body>
+<table style="width: 100%;">
+<tr>
+<td style="width: 33%"><img src="$pwd/pixmaps/calendar.png" alt="calendar.png" /></td>
+<td style="width: 33%; text-align: center;"><a href="$pwd/logout.php">
+ <img onclick="window.location.href='$pwd/logout.php'" style="border: 0" src="$pwd/pixmaps/exit.png" width="32" height="32" alt="Logout" /><br/>Logout</a></td>
+<td style="text-align: right"><span style="font-size: 1.6em">DAViCal Web Calendar</span><br/> - A Web Interface for <a href="javascript: newwin('http://www.davical.org/');">DAViCal</a></td>
+</tr>
+</table>
+_HEAD;
+
+//file_put_contents('/tmp/davical.log', $head);
+
+print $head;
+
--- /dev/null
+<?php
+/* $Id$ */
+require_once 'config.inc.php';
+require_once 'helper.php';
+
+$pwd = WEB_ROOT;
+if ($pwd[strlen($pwd)-1] == '/')
+ $pwd = substr($pwd, 0, -1);
+$pix = $pwd.'/pixmaps';
+
+$history = $_SERVER['PHP_SELF'];
+$query = construct_URL($_SERVER['QUERY_STRING'], array('etag', 'referer', 'cal'));
+if (count($query) > 0) {
+ $part = '';
+ foreach ($query as $key => $value) {
+ if (strcasecmp($key, 'referer') === 0)
+ continue;
+ $part .= "&$key=$value";
+ }
+ //$history .= substr($part, 0, -1);
+ $history .= $part;
+}
+//print $history;
+//exit;
+$menu = <<<_MENU
+<div id="menu">
+<table>
+<tr>
+ <td><a href="$pwd/events/new_event.php?referer=$history">
+ <img src="$pix/add-event.png" width="21" height="19" alt="new event" />New</a></td>
+ <td><a href="$pwd/events/edit_event.php?referer=$history">
+ <img src="$pix/edit-event.png" width="21" height="19"
+ alt="Edit event" />Edit</a></td>
+ <td><a href="$pwd/events/delete_event.php?referer=$history">
+ <img src="$pix/delete-event.png" width="21" height="19"
+ alt="Delete event" />Delete</a></td>
+ <td colspan="2"></td>
+ <td></td>
+ <td><a href="$pwd/navigate/goto_today.php"><img src="$pix/goto-today.png" width="21" height="19" alt="Goto today" />Today</a></td>
+ <td><a href="$pwd/navigate/show_day.php"><img src="$pix/day.png" width="21" height="19" alt="Show one day" />Day</a></td>
+ <td><a href="$pwd/navigate/show_week.php"><img src="$pix/week.png" width="21" height="19" alt="Show one week" />Week</a></td>
+ <td><a href="$pwd/navigate/show_month.php"><img src="$pix/month.png" width="21" height="19" alt="Show one month" />Month</a></td>
+ <td></td>
+ <td colspan="2"></td>
+ <td><a href="$pwd/utils/print.php" onclick="javascript: alert('Printing not available'); return false;">
+ <img src="$pix/print.png" width="21" height="19" alt="Print" />Print</a></td>
+ <td><a href="$pwd/events/update.php?referer=$history">
+ <img src="$pix/reload.png" width="21" height="19"
+ alt="Update events" />Update</a></td>
+ <td><a href="$pwd/utils/configure.php"><img src="$pix/configuration.png" width="21" height="19" alt="Configure Web Calendar" />Config</a></td>
+</tr>
+</table>
+</div>
+_MENU;
+
+//file_put_contents('/tmp/davical.log', $menu, FILE_APPEND);
+print $menu;
+
--- /dev/null
+<?php
+/* $Id$ */
+require_once 'helper.php';
+
+class CalendarInfo {
+ public $name;
+ public $color;
+ public $config;
+}
+
+class UserSettings {
+ private $calendars;
+ private $uid;
+ private $viewStyle;
+ private $startHour;
+ private $endHour;
+ private $startWeek;
+ private $role;
+ private $timeout;
+ private $timezone;
+ private $session_start;
+
+ public function __construct($uid) {
+ $this->calendars = array();
+ $this->uid = $uid;
+ $this->session_start = time();
+ }
+
+ public function setCalendars($calendars) {
+ $this->calendars = $calendars;
+ }
+
+ public function addCalendar($id, CalendarInfo $calendar) {
+ $this->calendars[$id] = $calendar;
+ }
+
+ public function removeCalendar($id) {
+ unset($this->calendars[$id]);
+ }
+
+ public function setSettings($settings) {
+ //file_put_contents('/tmp/davical.log',
+ // __FILE__ . ": " . var_export($settings, TRUE), FILE_APPEND);
+ $first = TRUE;
+ foreach ($settings as $row) {
+ if ($first) {
+ $this->viewStyle = $row['userview'];
+ $this->startWeek = ($row['weekstart']) ? TRUE : FALSE;
+ $this->startHour = $row['daystart'];
+ $this->endHour = $row['dayend'];
+ $this->role = (int) $row['userrole'];
+ $this->timeout = (int) $row['timeout'];
+ $this->timezone = $row['timezone'];
+ $first = FALSE;
+ }
+ if (isset($row['id']) && $row['id'] >= 0) {
+ $calendar = new CalendarInfo();
+ $calendar->name = $row['name'];
+ $calendar->color = $row['color'];
+ $calendar->config = $row['config'];
+ $this->calendars[$row['id']] = $calendar;
+ }
+ }
+ $this->isTimeout(TRUE);
+ }
+
+ public function getCalendars() {
+ return $this->calendars;
+ }
+
+ public function getCalendar($name) {
+ foreach ($this->calendars as $calendar) {
+ if ($calendar->name == $name)
+ return $calendar->config;
+ }
+ return NULL;
+ }
+
+ public function getViewStyle() {
+ return $this->viewStyle;
+ }
+
+ public function getStartWeek() {
+ return $this->startWeek;
+ }
+
+ public function getStartHour() {
+ return $this->startHour;
+ }
+
+ public function getEndHour() {
+ return $this->endHour;
+ }
+
+ public function getRole() {
+ return (int) $this->role;
+ }
+
+ public function getTimeout() {
+ return $this->timeout;
+ }
+
+ public function isTimeout($reset = FALSE) {
+ $terminate = TRUE;
+ $now = time();
+
+ if ($reset)
+ $this->session_start = $now;
+
+ //echo "$this->session_start -> $this->timeout -> $now<br/>";
+ $_SESSION['isTimeout'] = TRUE;
+ if ($this->session_start + $this->timeout > $now) {
+ $this->session_start = $now;
+ $terminate = FALSE;
+ $remain = $this->timeout / 60;
+ setcookie('WEBCAL_EXPIRE', $remain, 0, $_SESSION['WEB_ROOT']);
+ }
+ else {
+ header('Location: ' . $_SESSION['WEB_ROOT'] . 'logout.php');
+ exit;
+ }
+ }
+
+ public function getUid() {
+ return $this->uid;
+ }
+
+ public function getTimezone() {
+ return $this->timezone;
+ }
+
+}
--- /dev/null
+<?php
+/* $Id$ */
+if (! file_exists('config.inc.php') || filesize('config.inc.php') == 0) {
+ header("Location: install/install.php");
+ exit();
+}
+
+/* remove pgsql.php from root. Accidentally placed there in release 0.7.4 */
+$cwd = dirname(__FILE__);
+if (file_exists("$cwd/pgsql.php")) {
+ if (! unlink("$cwd/pgsql.php")) {
+ echo "An unrecoverable error has occured call the administrator an inform
+ him that he should read the error log file for further assistans";
+ error_log("$cwd/pgsql.php: Must be deleted.\nI tried but it failed due to
+ missing permissions. You must delete it manually");
+ exit;
+ }
+}
+
+$timezone_offset = date("Z");
+
+include_once 'config.inc.php';
+require_once 'user_validate.php';
+require_once 'utils/helper.php';
+
+$_SESSION['timezone_offset'] = $timezone_offset;
+
+$_SESSION['__ROOT__'] = TOP_FOLDER;
+
+if (PHP_VERSION < 5.1) {
+ die("PHP >= 5.1 is required to run this application");
+}
+
+valid_user();
+
+if (strtoupper($_SESSION['user_settings']->getUid()) == 'ADMIN' && newUpdates()) {
+ $pwd = WEB_ROOT;
+ if ($pwd[strlen($pwd)-1] == '/')
+ $pwd = substr($pwd, 0, -1);
+
+ print '<?xml version="1.0" encoding="utf-8"?>
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+ <head>
+ <title>Web Calendar</title>
+ <link rel="stylesheet" type="text/css"
+ href="'.$pwd.'/css/top_level.css" />
+ <link rel="shortcut icon"
+ href="'.$pwd.'/pixmaps/favicon.ico" />
+ <script type="text/javascript" src="'.$pwd.'/js/helper.js"></script>
+ </head>
+ <body>
+ <div id="update_msg">
+ <h3 style="text-align: center">
+ New updates available for the database
+ </h3>
+ <div style="text-align: center">
+ <button type="button" name="cancel"
+ onclick="javascript:redirect('."'navigate/goto_today.php'".')">Skip</button>
+ <button type="button" value="upgrade"
+ onclick="javascript:redirect('."'utils/upgrade_db.php'".')">Upgrade</button>
+ </div>
+ </div>
+ </body>
+ </html>';
+}
+else
+ include 'navigate/goto_today.php';
+?>
--- /dev/null
+--- ../0.7.4/config.inc.php 2011-03-03 02:26:11.565256656 +0100
++++ ../config.inc.php 2011-03-11 21:57:11.855624358 +0100
+@@ -35,15 +35,17 @@
+ require_once 'utils/authenticate.php';
+ require_once 'utils/helper.php';
+
++ session_cache_limiter('private');
++ if (isset($_COOKIE['WEBCAL_EXPIRE'])) {
++ $expire = $_COOKIE['WEBCAL_EXPIRE'];
++ session_cache_expire($expire);
++ unset($_COOKIE['WEBCAL_EXPIRE']);
++ setcookie('WEBCAL_EXPIRE', FALSE);
++ }
++ else
++ session_cache_expire(TIMEOUT);
+ session_start();
+-
+- if (isset($_SESSION['user_settings']))
+- $timeout = $_SESSION['user_settings']->getTimeout();
+-
+- if (isset($timeout))
+- ini_set('session.gc_maxlifetime', $timeout);
+- else if (defined('TIMEOUT'))
+- ini_set('session.gc_maxlifetime', TIMEOUT);
++ $_SESSION['WEB_ROOT'] = WEB_ROOT;
+
+ error_reporting(E_ALL ^ E_NOTICE ^ E_USER_NOTICE);
+
+@@ -69,4 +71,11 @@
+ ini_set('log_errors', 'on');
+ ini_set('error_log', LOG_FILE);
+ }
+-?>
++
++ if (! isset($_SESSION['isTimeout'])) {
++ if (isset($_SESSION['user_settings']))
++ $_SESSION['user_settings']->isTimeout();
++ }
++ else
++ unset($_SESSION['isTimeout']);
++?>
+\ No newline at end of file
--- /dev/null
+--- ../../0.8.0/config.inc.php 2011-03-19 17:23:46.950510408 +0100
++++ ../config.inc.php 2011-03-22 00:57:37.957420952 +0100
+@@ -45,6 +45,7 @@
+ else
+ session_cache_expire(TIMEOUT);
+ session_start();
++ header('Cache-Control: private');
+ $_SESSION['WEB_ROOT'] = WEB_ROOT;
+
+ error_reporting(E_ALL ^ E_NOTICE ^ E_USER_NOTICE);
+@@ -78,4 +79,3 @@
+ }
+ else
+ unset($_SESSION['isTimeout']);
+-?>
--- /dev/null
+<?php
+/* $Id$ */
+
+if (version_compare(PHP_VERSION, '5.1.3') === -1) {
+ die("PHP >= 5.1.3 is required to run this application");
+}
+
+error_reporting(E_ALL);
+ini_set('display_errors', 0);
+
+session_start();
+
+$root = getcwd();
+chdir('..');
+$top = getcwd();
+chdir($root);
+
+ini_set('include_path', "$top:$top/navigate:$top/utils:$top/include:$top/caldav:$top/caldav/awl:$top/templates:$top/events");
+
+include_once "$top/utils/timezone.php";
+include_once "$top/utils/helper.php";
+
+$db_drivers = array('sqlite','pgsql');
+
+/* Test for an existing config.inc.php */
+function remove_config() {
+ if (file_exists("../config.inc.php")) {
+ $postfix = date("c");
+ copy("../config.inc.php", "../$postfix-config.inc.php");
+ unlink("../config.inc.php");
+ }
+}
+
+$config_inc = <<<_CONFIG
+ /*******************************************************************
+ * Change only below this line.
+ * But in generel you should not changes these settings
+ * except via the setup script.
+ ******************************************************************/
+
+ define('TITLE', __TITLE__);
+ define('TIMEZONE', __TIMEZONE__);
+ define('ERROR_DISPLAY', __ERROR_DISPLAY__);
+ define('ERROR_LOG', __ERROR_LOG__);
+ define('LOG_FILE', __LOG_FILE__);
+ define('TOP_FOLDER', __TOP_FOLDER__);
+ /* / at the end of WEB_ROOT is mandatory */
+ define('WEB_ROOT', __WEB_ROOT__);
+ define('DBDRIVER', __DBDRIVER__);
+ define('DNS', __DNS__);
+ define('ADMIN_MAIL', __ADMIN_MAIL__);
+
+ /* Settings which can be change by individual users.
+ * Settings are change in config from the menu
+ */
+ define('VIEW_STYLE', __VIEW_STYLE__);
+ define('TIMEOUT', __TIMEOUT__);
+ define('WEEK_START_SUNDAY', __WEEK_START_SUNDAY__);
+ define('START_HOUR', __START_HOUR__);
+ define('END_HOUR', __END_HOUR__);
+
+ /*******************************************************************
+ * Do not change below this line
+ * All changes should be done above
+ ******************************************************************/
+
+ require_once 'include/user_settings.inc.php';
+ require_once 'utils/authenticate.php';
+ require_once 'utils/helper.php';
+
+ session_cache_limiter('private');
+ if (isset(\$_COOKIE['WEBCAL_EXPIRE'])) {
+ \$expire = \$_COOKIE['WEBCAL_EXPIRE'];
+ session_cache_expire(\$expire);
+ unset(\$_COOKIE['WEBCAL_EXPIRE']);
+ setcookie('WEBCAL_EXPIRE', FALSE);
+ }
+ else
+ session_cache_expire(TIMEOUT);
+ session_start();
+ header('Cache-Control: private');
+ \$_SESSION['WEB_ROOT'] = WEB_ROOT;
+
+ error_reporting(E_ALL ^ E_NOTICE ^ E_USER_NOTICE);
+
+ if (isset(\$_SESSION['user_settings'])) {
+ ini_set('date.timezone', \$_SESSION['user_settings']->getTimezone());
+ }
+ else if (defined('TIMEZONE')) {
+ ini_set('date.timezone', TIMEZONE);
+ }
+ else {
+ ini_set('date.timezone', 'Etc/UTC');
+ }
+
+ if (defined('ERROR_DISPLAY')) {
+ if (ERROR_DISPLAY) {
+ ini_set('display_errors', 'on');
+ }
+ else {
+ ini_set('display_errors', 'off');
+ }
+ }
+ if (defined('ERROR_LOG') && ERROR_LOG) {
+ ini_set('log_errors', 'on');
+ ini_set('error_log', LOG_FILE);
+ }
+
+ if (! isset(\$_SESSION['isTimeout'])) {
+ if (isset(\$_SESSION['user_settings']))
+ \$_SESSION['user_settings']->isTimeout();
+ }
+ else
+ unset(\$_SESSION['isTimeout']);
+_CONFIG;
+
+$config_apache = <<<_CONFIG
+ Alias __ALIAS__ "__TOP__"
+ <Directory "__TOP__">
+ Options Multiviews SymLinksIfOwnerMatch
+ php_value include_path '.:__TOP__:__TOP__navigate:__TOP__utils:__TOP__include:__TOP__caldav:__TOP__caldav/awl:__TOP__templates:__TOP__events'
+ </Directory>
+_CONFIG;
+
+$htaccess = <<<_HTACCESS
+ Options None
+ Order deny,allow
+ Deny from all
+ Allow from 127.0.0.1/32 ::1/128
+_HTACCESS;
+
+$head = <<<_HEAD
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<title>Web Calendar Installation</title>
+<meta name="generator" content="Bluefish 1.0.7"/>
+<meta name="author" content="Michael Rasmussen"/>
+<meta name="date" content="2009-03-23T20:45:48+0100"/>
+<meta name="copyright" content="© 2007, Michael Rasmussen. Licensed under GPL"/>
+<meta name="keywords" content=""/>
+<meta name="description" content=""/>
+<meta name="ROBOTS" content="NOINDEX, NOFOLLOW"/>
+<meta http-equiv="content-type" content="application/xhtml+xml; charset=UTF-8"/>
+<meta http-equiv="content-style-type" content="text/css"/>
+<meta http-equiv="expires" content="-1"/>
+<meta http-equiv="Pragma" content="no-cache"/>
+<link rel="stylesheet" type="text/css" href="../css/top_level.css" />
+<link rel="shortcut icon" href="../pixmaps/favicon.ico" />
+</head>
+<body>
+<table style="width: 100%;">
+<tr>
+<td style="width: 33%"><img src="../pixmaps/calendar.png" alt="calendar.png" /></td>
+<td style="width: 33%; text-align: center;"><img style="border: 0" src="../pixmaps/stock_init.png" width="48" height="48" alt="Setup"/></td>
+<td style="text-align: right"><span style="font-size: 1.6em">DAViCal Web Calendar</span><br/> - A Web Interface for <a href="javascript: newwin('http://rscds.sourceforge.net/');">DAViCal</a></td>
+</tr>
+</table>
+_HEAD;
+
+$foot = <<<_FOOTER
+<div id="footer">
+<p>
+ <a href="http://validator.w3.org/check?uri=referer">
+ <img src="http://www.w3.org/Icons/valid-xhtml10-blue.png"
+ alt="Valid XHTML 1.0 Strict" height="31" width="88" />
+ </a>
+ <a href="http://jigsaw.w3.org/css-validator/check/referer">
+ <img src="http://www.w3.org/Icons/valid-css2-blue.png"
+ alt="Valid CSS 2.0" height="31" width="88" />
+ </a>
+</p>
+</div>
+</body>
+</html>
+_FOOTER;
+
+function shutdown() {
+ global $head, $foot;
+
+ $isError = false;
+ if ($error = error_get_last()) {
+ switch($error['type']) {
+ case E_ERROR:
+ case E_CORE_ERROR:
+ case E_COMPILE_ERROR:
+ case E_USER_ERROR:
+ $isError = true;
+ break;
+ }
+ }
+
+ if ($isError) {
+ print $head;
+ print '<div id=\"ui\">';
+ if ($error['message'] == "Class 'PDO' not found") {
+ echo '<p style="text-align: center; font-size: 1.5em">
+ This install cannot continue because the module PDO is not installed</p>';
+ }
+ else
+ echo "<p style=\"text-align: center; font-size: 1.5em\">Script execution halted ({$error['message']})</p>";
+ print '</div>';
+ print $foot;
+ }
+ remove_config();
+}
+
+register_shutdown_function('shutdown');
+
+function get_server_timezone() {
+ $tz_abbr = date('T');
+ return timezone_name_from_abbr($tz_abbr);
+}
+
+function stage_1() {
+ switch ($_POST['driver']) {
+ case 'sqlite':
+ $dns = <<<_DNS
+ <tr>
+ <td class="config">Database file</td>
+ <td class="config">
+ <input type="text" name="dns"/>
+ <input type="hidden" name="driver" value="{$_POST['driver']}"/>
+ </td>
+ </tr>
+_DNS;
+ break;
+ case 'pgsql':
+ $dns = <<<_DNS
+ <tr>
+ <td class="config" colspan="3">
+ Below you will find reasonable default values for most.<br/>
+ <span style="font-weight: bold">database name</span>: Name of an exiting database used as template<br/>
+ on Postgresql this database is normally named template1<br/>
+ You should normally not need any other information than the following:<br/>
+ <span style="font-weight: bold">postgresql dba</span>: An existing postgresql user with permission to create<br/>
+ new databases and users.<br/>
+ <span style="font-weight: bold">postgresql dba password</span>: Password for this user<br/>
+ <span style="font-weight: bold">Password for webcal admin</span>: Password for the webcal admin user<br/>
+ </td>
+ </tr>
+ <tr>
+ <td class="config">host</td>
+ <td class="config">
+ <input type="text" name="dns[]" value="localhost"/>
+ </td>
+ </tr>
+ <tr>
+ <td class="config">port</td>
+ <td class="config">
+ <input type="text" name="dns[]" value="5432"/>
+ </td>
+ </tr>
+ <tr>
+ <td class="config">database name</td>
+ <td class="config">
+ <input type="text" name="dns[]" value="template1"/>
+ </td>
+ </tr>
+ <tr>
+ <td class="config">postgresql dba</td>
+ <td class="config">
+ <input type="text" name="dns[]" value="root"/>
+ </td>
+ </tr>
+ <tr>
+ <td class="config">postgresql dba password</td>
+ <td class="config">
+ <input type="password" name="dns[]" value="password"/>
+ <input type="hidden" name="driver" value="{$_POST['driver']}"/>
+ </td>
+ </tr>
+_DNS;
+ break;
+ }
+ return <<<__FORM
+ <h1 style="text-align: center">Setup: Stage 1/4</h1>
+ <form action="{$_SERVER['PHP_SELF']}" method="post">
+ <table class="config">
+ $dns
+ <tr>
+ <td class="config">Password for webcal admin</td>
+ <td class="config"><input name="pwd1" type="password"/></td>
+ </tr>
+ <tr>
+ <td class="config">Repeat Password</td>
+ <td class="config"><input name="pwd2" type="password"/></td>
+ </tr>
+ <tr>
+ <td class="config" colspan="2" style="text-align: center">
+ <input type="hidden" name="stage" value="2"/>
+ <input type="submit" name="action" value=">> Next"/>
+ </td>
+ </tr>
+ </table>
+ </form>
+__FORM;
+}
+
+function stage_2($top, $root) {
+ include_once "$top/utils/persistens.php";
+ global $timezones, $VERSION;
+ $dns = '';
+ $tz = '';
+
+ try {
+ if ($_POST['pwd1'] != $_POST['pwd2'])
+ throw new Exception("Password does not compare");
+ if ($_POST['driver'] == 'sqlite') {
+ $dns = $_POST['dns'];
+ $db = Persistens::getInstance($_POST['driver'], "$top/$dns");
+ $name = NULL;
+ $pwd = NULL;
+ }
+ else {
+ $dns = "host={$_POST['dns'][0]} port={$_POST['dns'][1]} dbname={$_POST['dns'][2]} user={$_POST['dns'][3]} password={$_POST['dns'][4]}";
+ $db = Persistens::getInstance($_POST['driver'], $dns);
+ $name = "webcal";
+ $user = "webcal";
+ $pwd = $_POST['pwd1'];
+ $db->initDatabase($name, $pwd);
+ $db = NULL;
+ $dns = "host={$_POST['dns'][0]} port={$_POST['dns'][1]} dbname=$name user=$user password=$pwd";
+ $db = Persistens::getInstance($_POST['driver'], $dns);
+ //throw new Exception(var_export($dns, true));
+ }
+ $db->createDatabase($name);
+ $db->execute("insert into about (version) values ('$VERSION')");
+ $data['uid'] = 'admin';
+ $data['pwd'] = sha1($_POST['pwd1']);
+ $data['timezone'] = get_server_timezone();
+ $data['userrole'] = 0;
+ $data['seckey'] = '';
+ $data['pubkey'] = '';
+ $data['timeout'] = 15 * 60;
+ $data['view'] = 'week';
+ $data['week_start'] = false;
+ $data['start'] = 8;
+ $data['end'] = 17;
+ $db->newUser($data);
+ }
+ catch (Exception $ex) {
+ remove_config();
+ $result = "<p style=\"text-align: center\">stage2: {$ex->getMessage()}</p>";
+ $result .= "<p style=\"text-align: center\">
+ <input type=\"button\" value=\"Back\"
+ onclick=\"javascript: history.back()\"/></p>";
+ return $result;
+ }
+ $config['DBDRIVER'] = $_POST['driver'];
+ $config['DNS'] = $dns;
+ $_SESSION['config'] = $config;
+ foreach ($timezones as $timezone) {
+ $tz .= "<option value=\"$timezone\"";
+ if ($timezone == get_server_timezone())
+ $tz .= ' selected="true"';
+ $tz .= ">$timezone</option>";
+ }
+ return <<<__FORM
+ <h1 style="text-align: center">Setup: Stage 2/4</h1>
+ <form action="{$_SERVER['PHP_SELF']}" method="post">
+ <table class="config">
+ <tr>
+ <td class="config">Application web root</td>
+ <td class="config"><input name="web_root" type="text"/></td>
+ </tr>
+ <tr>
+ <td class="config">Application title</td>
+ <td class="config"><input name="title" type="text"/></td>
+ </tr>
+ <tr>
+ <td class="config">Server timezone</td>
+ <td class="config"><select name="timezone">$tz</select></td>
+ </tr>
+ <tr>
+ <td class="config">Display errors in browser</td>
+ <td class="config">
+ <select name="display_error">
+ <option value="no">No</option>
+ <option value="yes">Yes</option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td class="config">Log errors</td>
+ <td class="config">
+ <select name="log_error">
+ <option value="no">No</option>
+ <option value="yes">Yes</option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td class="config">Log file</td>
+ <td class="config"><input name="log_file" type="text"/></td>
+ </tr>
+ <tr>
+ <td class="config">Administrator email</td>
+ <td class="config"><input name="admin_email" type="text"/></td>
+ </tr>
+ <tr>
+ <td class="config" colspan="2" style="text-align: center">
+ <input type="hidden" name="stage" value="3"/>
+ <input type="submit" name="action" value=">> Next"/>
+ </td>
+ </tr>
+ </table>
+ </form>
+__FORM;
+}
+
+function stage_3($top, $root) {
+ $config = $_SESSION['config'];
+ $config['WEB_ROOT'] = $_POST['web_root'];
+ $config['TITLE'] = $_POST['title'];
+ $config['TIMEZONE'] = $_POST['timezone'];
+ $config['ERROR_DISPLAY'] = ($_POST['display_error'] == 'yes')? 'TRUE' : 'FALSE';
+ $config['ERROR_LOG'] = ($_POST['log_error'] == 'yes')? 'TRUE' : 'FALSE';
+ $config['LOG_FILE'] = $_POST['log_file'];
+ $config['ADMIN_MAIL'] = $_POST['admin_email'];
+ $_SESSION['config'] = $config;
+ return <<<__FORM
+ <h1 style="text-align: center">Setup: Stage 3/4</h1>
+ <form action="{$_SERVER['PHP_SELF']}" method="post">
+ <table class="config">
+ <tr>
+ <td class="config">Default view</td>
+ <td class="config">
+ <select name="view_style">
+ <option value="day">Day</option>
+ <option value="week" selected="true">Week</option>
+ <option value="month">Month</option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td class="config">Default session timeout in minuts</td>
+ <td class="config"><input name="timeout" type="text" value="60"/></td>
+ </tr>
+ <tr>
+ <td class="config">Default start of week Sunday</td>
+ <td class="config">
+ <select name="week_start_sunday">
+ <option value="no" selected="true">No</option>
+ <option value="yes">Yes</option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td class="config">Default day start</td>
+ <td class="config"><input name="start_day" type="text" value="8"/></td>
+ </tr>
+ <tr>
+ <td class="config">Default day end</td>
+ <td class="config"><input name="end_day" type="text" value="17"/></td>
+ </tr>
+ <tr>
+ <td class="config" colspan="2" style="text-align: center">
+ <input type="hidden" name="stage" value="4"/>
+ <input type="submit" name="action" value=">> Next"/>
+ </td>
+ </tr>
+ </table>
+ </form>
+__FORM;
+}
+
+function stage_4($top, $root) {
+ include_once "$top/utils/persistens.php";
+ global $config_inc, $config_apache, $htaccess;
+
+ $config = $_SESSION['config'];
+ $config['VIEW_STYLE'] = $_POST['view_style'];
+ $config['TIMEOUT'] = $_POST['timeout'] * 60;
+ $config['WEEK_START_SUNDAY'] =
+ ($_POST['week_start_sunday'] == 'yes')? 'TRUE' : 'FALSE';
+ $config['START_HOUR'] = $_POST['start_day'];
+ $config['END_HOUR'] = $_POST['end_day'];
+ $config['TOP_FOLDER'] = $top;
+ $start = strpos($config['WEB_ROOT'], "/");
+ if ($start != 0 || $start === FALSE)
+ $config['WEB_ROOT'] = '/'.$config['WEB_ROOT'];
+ $end = strrpos($config['WEB_ROOT'], "/");
+ if ($end != strlen($config['WEB_ROOT']) - 1 || $end == FALSE)
+ $config['WEB_ROOT'] = $config['WEB_ROOT'].'/';
+ foreach ($config as $key => $value) {
+ if ($value !== 'TRUE' && $value !== 'FALSE')
+ $value = "'$value'";
+ $config_inc = str_replace('__'.$key.'__', $value, $config_inc);
+ }
+ // Create config.inc.php
+ $file = "<?php\n" . $config_inc . "\n?>\n";
+ file_put_contents("$top/config.inc.php", $file);
+ // Create .htaccess in install
+ if (! file_exists("$root/.htaccess"))
+ file_put_contents("$root/.htaccess", $htaccess);
+ // Create webcal in conf.d
+ $root = $config['WEB_ROOT'];
+ $root = substr($root, 0, -1);
+ $config_apache = str_replace('__ALIAS__', $root, $config_apache);
+ $config_apache =
+ str_replace('__TOP__', $config['TOP_FOLDER'].'/', $config_apache);
+ $result = '<p style="text-align: center">If you haven\'t done basic setup
+ by executing the setup script you must Copy/paste the following
+ to /etc/[apache config]/conf.d/webcal.conf and restart apache<br/>';
+ $result .= '<textarea rows="10" cols="60">';
+ $result .= htmlspecialchars($config_apache);
+ $result .= '</textarea></p>';
+ $result .= '<p style="text-align: center">After restart of
+ apache follow this link to webcal';
+ $url = getServerUrl($config['WEB_ROOT']);
+ $webroot = getServerUrl($config['WEB_ROOT'], $root);
+ $result .= " <a href=\"$url\">webcal</a></p>";
+ $result .= '<p style="text-align: center">Remember to disable ' .
+ 'write access to ' . "$top/install";
+ // update database
+ if ($config['DBDRIVER'] == 'sqlite') {
+ $db = Persistens::getInstance($config['DBDRIVER'], $top."/".$config['DNS']);
+ }
+ else {
+ $db = Persistens::getInstance($config['DBDRIVER'], $config['DNS']);
+ }
+ $db->changeDefault($config);
+ $_SESSION = array();
+ if (isset($_COOKIE[session_name()])) {
+ setcookie(session_name(), '', time()-42000, '/');
+ }
+ session_destroy();
+ return $result;
+}
+
+if (count($_POST) > 0) {
+ if (isset($_POST['stage'])) {
+ switch ($_POST['stage']) {
+ case '1': $page = stage_1(); break;
+ case '2': $page = stage_2($top, $root); break;
+ case '3': $page = stage_3($top, $root); break;
+ case '4': $page = stage_4($top, $root); break;
+ case '5': $page = stage_4($top, $root); break;
+ default: trigger_error("Unknown stage", E_USER_ERROR);
+ }
+ }
+ else {
+ remove_config();
+ trigger_error("Unknown stage", E_USER_ERROR);
+ }
+}
+else {
+ remove_config();
+
+ $error = FALSE;
+ $page = '<h1 style="text-align: center">Setup: Stage 0/4</h1>';
+ $page .= '<table class="config">';
+ $page .= '<tr><td>Checking if module mcrypt is available</td>';
+ try {
+ $mcrypt = MCRYPT_ENCRYPT;
+ if (is_integer($mcrypt)) {
+ $page .= '<td><span style="font-size: 1.2em; font-weight: bold;
+ background: green">OK</span></td></tr>';
+ }
+ else {
+ $page .= '<td><span style="font-size: 1.2em; font-weight: bold;
+ background: red">NO</span></td></tr>';
+ $error = TRUE;
+ }
+ } catch (ErrorException $ex) {
+ $page .= '<td><span style="font-size: 1.2em; font-weight: bold;
+ background: red">NO</span></td></tr>';
+ $error = TRUE;
+ }
+ $page .= '<tr><td>Checking if module PDO is available</td>';
+ try {
+ $avail = PDO::getAvailableDrivers();
+ $page .= '<td><span style="font-size: 1.2em; font-weight: bold;
+ background: green">OK</span></td></tr>';
+ }
+ catch (PDOException $ex) {
+ $page .= '<td><span style="font-size: 1.2em; font-weight: bold;
+ background: red">NO</span></td></tr>';
+ $error = TRUE;
+ }
+ //$page .= "<tr><td cols=\"2\">".var_export($avail, true)."</td></tr>";
+ $page .= "<tr><td>Checking if a suitable PDO driver is available</td>";
+ $dbms = NULL;
+ foreach ($db_drivers as $driver) {
+ $driver = strtolower($driver);
+ if (in_array($driver, $avail))
+ $dbms .= "<option value=\"$driver\">$driver</option>";
+ }
+ if ($dbms)
+ $page .= '<td><span style="font-size: 1.2em; font-weight: bold;
+ background: green">OK</span></td></tr>';
+ else {
+ $page .= '<td><span style="font-size: 1.2em; font-weight: bold;
+ background: red">NO</span></td></tr>';
+ $error = TRUE;
+ }
+ $page .= "<tr><td>Checking if application root is writeable</td>";
+ try {
+ if (@file_put_contents("$top/config.inc.php", "") === FALSE)
+ throw new Exception();
+ $page .= '<td><span style="font-size: 1.2em; font-weight: bold;
+ background: green">OK</span></td></tr>';
+ }
+ catch (Exception $ex) {
+ $page .= '<td><span style="font-size: 1.2em; font-weight: bold;
+ background: red">NO</span></td></tr>';
+ $error = TRUE;
+ }
+ $page .= "<tr><td>Checking if install folder is writeable</td>";
+ try {
+ $test_file = hash("md5", date("r", time()));
+ if (@file_put_contents("$root/$test_file", "") === FALSE)
+ throw new Exception();
+ if (unlink("$root/$test_file") === FALSE)
+ throw new Exception();
+ $page .= '<td><span style="font-size: 1.2em; font-weight: bold;
+ background: green">OK</span></td></tr>';
+ }
+ catch (Exception $ex) {
+ $page .= '<td><span style="font-size: 1.2em; font-weight: bold;
+ background: red">NO</span></td></tr>';
+ $error = TRUE;
+ }
+ $page .= '</table><br/><br/>';
+
+ if (! $error) {
+ $page .= <<<__FORM
+ <form action="{$_SERVER['PHP_SELF']}" method="post">
+ <table class="config">
+ <tr>
+ <td class="config">
+ Choose Database system
+ </td>
+ <td class="config">
+ <select name="driver">
+ $dbms
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td class="config" colspan="2" style="text-align: center">
+ <input type="hidden" name="stage" value="1"/>
+ <input type="submit" name="action" value=">> Next"/>
+ </td>
+ </tr>
+ </table>
+ </form>
+__FORM;
+ }
+ else {
+ remove_config();
+ $page .= '<p style="text-align: center">Install missing modules or correct
+ errors marked by
+ <span style="font-size: 1.2em; font-weight: bold;background: red">NO</span> to
+ continue installation</p>';
+ }
+}
+
+print $head;
+
+echo "<div id=\"ui\">$page</div>";
+
+print $foot;
+?>
--- /dev/null
+-- db_upgrade_0_7_3.sql
+-- $Id$
+
+create table about (
+ id integer default 1,
+ version varchar(256) default ''
+);
+insert into about (version) values ('0.7.3');
+
+alter table calendar alter column config type varchar(4000);
+alter table calendar alter column config set default '';
--- /dev/null
+-- db_upgrade_0_7_4.sql
+-- $Id$
+
+update about set version='0.7.4';
+
--- /dev/null
+-- db_upgrade_0_7_5.sql
+-- $Id$
+
+create table ldap (
+ enable integer default 0,
+ dns varchar(256) default '',
+ tls integer default 0,
+ base_dn varchar(256) default '',
+ user_attr varchar(256) default 'uid');
+
+update about set version='0.7.5';
+
--- /dev/null
+-- db_upgrade_0_8_0.sql
+-- $Id$
+
+update about set version='0.8.0';
+
--- /dev/null
+-- db_upgrade_0_8_1.sql
+-- $Id$
+
+update about set version='0.8.1';
+
--- /dev/null
+#!/usr/bin/env perl
+# $Id$
+
+use strict;
+use warnings;
+
+BEGIN {
+ eval {
+ use File::Basename;
+ use File::Copy;
+ use File::Find;
+ use File::Path;
+ use Cwd;
+ }; die $@ if $@;
+}
+
+die "Only root may run this" if $> != 0;
+die "Script must be executed from its own folder"
+ unless -e getcwd.'/install.php';
+
+my (@apache_dir, @application);
+
+find(\&find_apache, '/etc', '/usr/local/etc');
+
+sub find_apache {
+ return unless -d;
+ return unless $File::Find::name =~ /\.*etc\/([apache2|httpd]+\/conf.d)\.*/;
+ my $path = "$File::Find::dir";
+ push @apache_dir, $path;
+}
+
+sub find_appl {
+ push @application, $File::Find::name;
+}
+
+sub copy_files {
+ my $path = shift;
+ if (-e $path) {
+ print "Directory exists. Continue [y/n]? ";
+ my $continue = <STDIN>;
+ chomp $continue;
+ exit unless $continue eq 'y';
+ }
+ else {
+ umask 022;
+ mkpath ($path) or die $!;
+ }
+ find(\&find_appl, '..');
+ foreach (@application) {
+ next if /^..$/;
+ my $from = $_;
+ /^..\/(.+)/;
+ do {
+ mkdir ("$path/$1");
+ next;
+ } if -d $from;
+ my ($file, $dir) = fileparse($1);
+ $dir = '' if $dir =~ /^.\//;
+ print STDERR "Copying: $from -> $path/$dir\n";
+ copy($from, "$path/$dir") or die "Copy failed: $!";
+ }
+}
+
+my $config = <<__CONF;
+ Alias __ALIAS__ "__TOP__"
+ <Directory "__TOP__">
+ Options Multiviews SymLinksIfOwnerMatch
+ php_value include_path '.:__TOP__:__TOP__navigate:__TOP__utils:__TOP__include:__TOP__caldav:__TOP__caldav/awl:__TOP__templates:__TOP__events'
+ </Directory>
+__CONF
+
+print <<__HELP;
+Davical Web Calender (C) 2009, Michael Rasmussen.
+Released under GNU General Public License version 3+.
+This license applies to all files except where a different license
+state otherwise.
+
+This script will create the basic installation of Davical web calendar.
+You only need to run this script if you want to install the application
+outside the Apache's web scope.
+
+You will be asked a number of questions which must all be answered.
+The script will try to figure out must of the answers for you and
+present the found information inside []. Should the script not find
+the answers for you (you will see []) or you disaggree to the suggested
+setting you must provide the required setting yourself. If you aggree
+to the found setting you simply press enter.
+
+__HELP
+
+print "Apache2 configuration folder [";
+print $apache_dir[0] if scalar @apache_dir > 0;
+print "]? ";
+my $folder = <STDIN>;
+chomp $folder;
+$folder = $apache_dir[0] unless $folder;
+die "Missing Apache configuration folder\n" unless $folder;
+
+my $url = 'webcal';
+print "Application URL [$url]? ";
+my $url1 = <STDIN>;
+chomp $url1;
+$url1 = $url unless $url1;
+die "Missing application web root\n" unless $url1;
+
+my $cwd = getcwd;
+my ($file, $dir) = fileparse($cwd);
+$cwd = ($dir =~ /(.*)\/$/) ? $1 : $dir;
+print "Application web root [$cwd]? ";
+my $root = <STDIN>;
+chomp $root;
+do {
+ my $home = $ENV{'HOME'};
+ $root =~ /^~(.*)$/;
+ $root = $home.$1;
+} if $root =~ m/^~/;
+$root = $cwd unless $root;
+die "Missing application web root\n" unless $root;
+
+$config =~ s/__TOP__/$root\//g;
+$config =~ s/__ALIAS__/\/$url1/;
+
+print <<_RESULT;
+
+This setup will be used:
+Apache configuration folder:\t$folder
+Application URL:\t\t/$url1
+Application top folder:\t\t$root
+
+Installing this configuration in Apache:
+$config
+_RESULT
+
+print "Continue [Y/n]? ";
+my $continue = <STDIN>;
+chomp $continue unless $continue =~ m/^\n$/;
+exit unless $continue =~ m/^[Yy\n]$/;
+
+copy_files($root) unless $root eq $cwd;
+
+my $config_file = "$folder/conf.d/webcal.conf";
+do {
+ print "$config_file: File exists, overwrite [y/n]? ";
+ my $continue = <STDIN>;
+ chomp $continue unless $continue =~ m/^\n$/;
+ exit unless $continue =~ m/^[Yy\n]$/;
+} if -e $config_file;
+
+open CONF, "> $config_file" or die $!;
+print CONF $config;
+close CONF;
+
+print <<_INFO;
+
+Setup has completed. You need to restart Apache before
+you continue with the installation of WebCal.
+
+After Apache has been restarted point your web browser
+to this address: http://localhost/$url1
+Then simply follow the wizard.
+
+For securety reasons I strongly advice you to only allow
+access to the application via secure HTTP.
+
+Happy hacking:-)
+_INFO
+
+exit 0;
--- /dev/null
+-- db_upgrade_0_7_3.sql
+-- $Id$
+
+create table about (
+ id integer default 1,
+ version text default ''
+);
+insert into about (version) values ('0.7.3');
+
--- /dev/null
+-- db_upgrade_0_7_4.sql
+-- $Id$
+
+update about set version='0.7.4';
+
--- /dev/null
+-- db_upgrade_0_7_5.sql
+-- $Id$
+
+create table ldap (
+ enable integer default 0,
+ dns text default '',
+ tls integer default 0,
+ base_dn text default '',
+ user_attr text default 'uid');
+
+update about set version='0.7.5';
+
--- /dev/null
+-- db_upgrade_0_8_0.sql
+-- $Id$
+
+update about set version='0.8.0';
+
--- /dev/null
+-- db_upgrade_0_8_1.sql
+-- $Id$
+
+update about set version='0.8.1';
+
--- /dev/null
+ { "Africa/Abidjan" , 0x000000 },
+ { "Africa/Accra" , 0x000055 },
+ { "Africa/Addis_Ababa" , 0x0000FD },
+ { "Africa/Algiers" , 0x000153 },
+ { "Africa/Asmara" , 0x00027E },
+ { "Africa/Asmera" , 0x0002D4 },
+ { "Africa/Bamako" , 0x00032A },
+ { "Africa/Bangui" , 0x000395 },
+ { "Africa/Banjul" , 0x0003EA },
+ { "Africa/Bissau" , 0x000461 },
+ { "Africa/Blantyre" , 0x0004C7 },
+ { "Africa/Brazzaville" , 0x00051C },
+ { "Africa/Bujumbura" , 0x000571 },
+ { "Africa/Cairo" , 0x0005B5 },
+ { "Africa/Casablanca" , 0x00097C },
+ { "Africa/Ceuta" , 0x000A58 },
+ { "Africa/Conakry" , 0x000D5F },
+ { "Africa/Dakar" , 0x000DCA },
+ { "Africa/Dar_es_Salaam" , 0x000E30 },
+ { "Africa/Djibouti" , 0x000E9D },
+ { "Africa/Douala" , 0x000EF2 },
+ { "Africa/El_Aaiun" , 0x000F47 },
+ { "Africa/Freetown" , 0x000FAD },
+ { "Africa/Gaborone" , 0x0010BC },
+ { "Africa/Harare" , 0x001117 },
+ { "Africa/Johannesburg" , 0x00116C },
+ { "Africa/Kampala" , 0x0011DA },
+ { "Africa/Khartoum" , 0x001259 },
+ { "Africa/Kigali" , 0x00136C },
+ { "Africa/Kinshasa" , 0x0013C1 },
+ { "Africa/Lagos" , 0x00141C },
+ { "Africa/Libreville" , 0x001471 },
+ { "Africa/Lome" , 0x0014C6 },
+ { "Africa/Luanda" , 0x00150A },
+ { "Africa/Lubumbashi" , 0x00155F },
+ { "Africa/Lusaka" , 0x0015BA },
+ { "Africa/Malabo" , 0x00160F },
+ { "Africa/Maputo" , 0x001675 },
+ { "Africa/Maseru" , 0x0016CA },
+ { "Africa/Mbabane" , 0x001732 },
+ { "Africa/Mogadishu" , 0x001788 },
+ { "Africa/Monrovia" , 0x0017E3 },
+ { "Africa/Nairobi" , 0x001849 },
+ { "Africa/Ndjamena" , 0x0018C8 },
+ { "Africa/Niamey" , 0x001934 },
+ { "Africa/Nouakchott" , 0x0019A7 },
+ { "Africa/Ouagadougou" , 0x001A12 },
+ { "Africa/Porto-Novo" , 0x001A67 },
+ { "Africa/Sao_Tome" , 0x001ACD },
+ { "Africa/Timbuktu" , 0x001B22 },
+ { "Africa/Tripoli" , 0x001B8D },
+ { "Africa/Tunis" , 0x001C87 },
+ { "Africa/Windhoek" , 0x001EB1 },
+ { "America/Adak" , 0x0020F8 },
+ { "America/Anchorage" , 0x00246E },
+ { "America/Anguilla" , 0x0027E2 },
+ { "America/Antigua" , 0x002837 },
+ { "America/Araguaina" , 0x00289D },
+ { "America/Argentina/Buenos_Aires" , 0x0029F8 },
+ { "America/Argentina/Catamarca" , 0x002CC3 },
+ { "America/Argentina/ComodRivadavia" , 0x002E84 },
+ { "America/Argentina/Cordoba" , 0x00302A },
+ { "America/Argentina/Jujuy" , 0x00331C },
+ { "America/Argentina/La_Rioja" , 0x0034D0 },
+ { "America/Argentina/Mendoza" , 0x003688 },
+ { "America/Argentina/Rio_Gallegos" , 0x003848 },
+ { "America/Argentina/Salta" , 0x0039FD },
+ { "America/Argentina/San_Juan" , 0x003BA9 },
+ { "America/Argentina/San_Luis" , 0x003D61 },
+ { "America/Argentina/Tucuman" , 0x004035 },
+ { "America/Argentina/Ushuaia" , 0x00430E },
+ { "America/Aruba" , 0x0044C9 },
+ { "America/Asuncion" , 0x00452F },
+ { "America/Atikokan" , 0x004814 },
+ { "America/Atka" , 0x0048EA },
+ { "America/Bahia" , 0x004C50 },
+ { "America/Barbados" , 0x004DD9 },
+ { "America/Belem" , 0x004E73 },
+ { "America/Belize" , 0x004F6E },
+ { "America/Blanc-Sablon" , 0x0050EA },
+ { "America/Boa_Vista" , 0x00519E },
+ { "America/Bogota" , 0x0052A7 },
+ { "America/Boise" , 0x005313 },
+ { "America/Buenos_Aires" , 0x0056AA },
+ { "America/Cambridge_Bay" , 0x005960 },
+ { "America/Campo_Grande" , 0x005C88 },
+ { "America/Cancun" , 0x005F77 },
+ { "America/Caracas" , 0x0061B9 },
+ { "America/Catamarca" , 0x006220 },
+ { "America/Cayenne" , 0x0063C6 },
+ { "America/Cayman" , 0x006428 },
+ { "America/Chicago" , 0x00647D },
+ { "America/Chihuahua" , 0x006994 },
+ { "America/Coral_Harbour" , 0x006BE3 },
+ { "America/Cordoba" , 0x006C75 },
+ { "America/Costa_Rica" , 0x006F38 },
+ { "America/Cuiaba" , 0x006FC2 },
+ { "America/Curacao" , 0x0072A0 },
+ { "America/Danmarkshavn" , 0x007306 },
+ { "America/Dawson" , 0x00744A },
+ { "America/Dawson_Creek" , 0x007767 },
+ { "America/Denver" , 0x007941 },
+ { "America/Detroit" , 0x007CC7 },
+ { "America/Dominica" , 0x008026 },
+ { "America/Edmonton" , 0x00807B },
+ { "America/Eirunepe" , 0x008433 },
+ { "America/El_Salvador" , 0x008546 },
+ { "America/Ensenada" , 0x0085BB },
+ { "America/Fort_Wayne" , 0x008A62 },
+ { "America/Fortaleza" , 0x008924 },
+ { "America/Glace_Bay" , 0x008CCC },
+ { "America/Godthab" , 0x009043 },
+ { "America/Goose_Bay" , 0x009307 },
+ { "America/Grand_Turk" , 0x0097C4 },
+ { "America/Grenada" , 0x009A73 },
+ { "America/Guadeloupe" , 0x009AC8 },
+ { "America/Guatemala" , 0x009B1D },
+ { "America/Guayaquil" , 0x009BA6 },
+ { "America/Guyana" , 0x009C03 },
+ { "America/Halifax" , 0x009C84 },
+ { "America/Havana" , 0x00A19A },
+ { "America/Hermosillo" , 0x00A50D },
+ { "America/Indiana/Indianapolis" , 0x00A5EB },
+ { "America/Indiana/Knox" , 0x00A87C },
+ { "America/Indiana/Marengo" , 0x00AC13 },
+ { "America/Indiana/Petersburg" , 0x00AEB9 },
+ { "America/Indiana/Tell_City" , 0x00B406 },
+ { "America/Indiana/Vevay" , 0x00B69F },
+ { "America/Indiana/Vincennes" , 0x00B8DA },
+ { "America/Indiana/Winamac" , 0x00BB8E },
+ { "America/Indianapolis" , 0x00B19C },
+ { "America/Inuvik" , 0x00BE47 },
+ { "America/Iqaluit" , 0x00C13E },
+ { "America/Jamaica" , 0x00C460 },
+ { "America/Jujuy" , 0x00C525 },
+ { "America/Juneau" , 0x00C6CF },
+ { "America/Kentucky/Louisville" , 0x00CA4D },
+ { "America/Kentucky/Monticello" , 0x00CE6B },
+ { "America/Knox_IN" , 0x00D1F0 },
+ { "America/La_Paz" , 0x00D561 },
+ { "America/Lima" , 0x00D5C8 },
+ { "America/Los_Angeles" , 0x00D670 },
+ { "America/Louisville" , 0x00DA81 },
+ { "America/Maceio" , 0x00DE76 },
+ { "America/Managua" , 0x00DFB0 },
+ { "America/Manaus" , 0x00E063 },
+ { "America/Marigot" , 0x00E165 },
+ { "America/Martinique" , 0x00E1BA },
+ { "America/Mazatlan" , 0x00E226 },
+ { "America/Mendoza" , 0x00E493 },
+ { "America/Menominee" , 0x00E647 },
+ { "America/Merida" , 0x00E9C8 },
+ { "America/Mexico_City" , 0x00EC03 },
+ { "America/Miquelon" , 0x00EE7E },
+ { "America/Moncton" , 0x00F0F0 },
+ { "America/Monterrey" , 0x00F587 },
+ { "America/Montevideo" , 0x00F7CE },
+ { "America/Montreal" , 0x00FAE0 },
+ { "America/Montserrat" , 0x00FFF6 },
+ { "America/Nassau" , 0x01004B },
+ { "America/New_York" , 0x010390 },
+ { "America/Nipigon" , 0x01089B },
+ { "America/Nome" , 0x010BEC },
+ { "America/Noronha" , 0x010F6A },
+ { "America/North_Dakota/Center" , 0x01109A },
+ { "America/North_Dakota/New_Salem" , 0x01142E },
+ { "America/Panama" , 0x0117D7 },
+ { "America/Pangnirtung" , 0x01182C },
+ { "America/Paramaribo" , 0x011B62 },
+ { "America/Phoenix" , 0x011BF4 },
+ { "America/Port-au-Prince" , 0x011CA2 },
+ { "America/Port_of_Spain" , 0x011EBD },
+ { "America/Porto_Acre" , 0x011DBE },
+ { "America/Porto_Velho" , 0x011F12 },
+ { "America/Puerto_Rico" , 0x012008 },
+ { "America/Rainy_River" , 0x012073 },
+ { "America/Rankin_Inlet" , 0x0123AB },
+ { "America/Recife" , 0x012691 },
+ { "America/Regina" , 0x0127BB },
+ { "America/Resolute" , 0x012979 },
+ { "America/Rio_Branco" , 0x012C72 },
+ { "America/Rosario" , 0x012D75 },
+ { "America/Santarem" , 0x013038 },
+ { "America/Santiago" , 0x01313D },
+ { "America/Santo_Domingo" , 0x0134E6 },
+ { "America/Sao_Paulo" , 0x0135AC },
+ { "America/Scoresbysund" , 0x0138BB },
+ { "America/Shiprock" , 0x013BA9 },
+ { "America/St_Barthelemy" , 0x013F38 },
+ { "America/St_Johns" , 0x013F8D },
+ { "America/St_Kitts" , 0x0144E0 },
+ { "America/St_Lucia" , 0x014535 },
+ { "America/St_Thomas" , 0x01458A },
+ { "America/St_Vincent" , 0x0145DF },
+ { "America/Swift_Current" , 0x014634 },
+ { "America/Tegucigalpa" , 0x014755 },
+ { "America/Thule" , 0x0147D4 },
+ { "America/Thunder_Bay" , 0x014A1B },
+ { "America/Tijuana" , 0x014D64 },
+ { "America/Toronto" , 0x0150D9 },
+ { "America/Tortola" , 0x0155F0 },
+ { "America/Vancouver" , 0x015645 },
+ { "America/Virgin" , 0x015A82 },
+ { "America/Whitehorse" , 0x015AD7 },
+ { "America/Winnipeg" , 0x015DF4 },
+ { "America/Yakutat" , 0x016234 },
+ { "America/Yellowknife" , 0x01659F },
+ { "Antarctica/Casey" , 0x0168AF },
+ { "Antarctica/Davis" , 0x016923 },
+ { "Antarctica/DumontDUrville" , 0x0169A0 },
+ { "Antarctica/Mawson" , 0x016A32 },
+ { "Antarctica/McMurdo" , 0x016AA1 },
+ { "Antarctica/Palmer" , 0x016DA3 },
+ { "Antarctica/Rothera" , 0x0170BF },
+ { "Antarctica/South_Pole" , 0x017135 },
+ { "Antarctica/Syowa" , 0x01743D },
+ { "Antarctica/Vostok" , 0x0174AB },
+ { "Arctic/Longyearbyen" , 0x017520 },
+ { "Asia/Aden" , 0x017852 },
+ { "Asia/Almaty" , 0x0178A7 },
+ { "Asia/Amman" , 0x017A26 },
+ { "Asia/Anadyr" , 0x017CE6 },
+ { "Asia/Aqtau" , 0x017FD4 },
+ { "Asia/Aqtobe" , 0x0181D3 },
+ { "Asia/Ashgabat" , 0x01838B },
+ { "Asia/Ashkhabad" , 0x0184A8 },
+ { "Asia/Baghdad" , 0x0185C5 },
+ { "Asia/Bahrain" , 0x01873A },
+ { "Asia/Baku" , 0x0187A0 },
+ { "Asia/Bangkok" , 0x018A88 },
+ { "Asia/Beirut" , 0x018ADD },
+ { "Asia/Bishkek" , 0x018DEA },
+ { "Asia/Brunei" , 0x018F96 },
+ { "Asia/Calcutta" , 0x018FF8 },
+ { "Asia/Choibalsan" , 0x019071 },
+ { "Asia/Chongqing" , 0x0191EA },
+ { "Asia/Chungking" , 0x0192D9 },
+ { "Asia/Colombo" , 0x019388 },
+ { "Asia/Dacca" , 0x019424 },
+ { "Asia/Damascus" , 0x0194B3 },
+ { "Asia/Dhaka" , 0x019803 },
+ { "Asia/Dili" , 0x019892 },
+ { "Asia/Dubai" , 0x01991B },
+ { "Asia/Dushanbe" , 0x019970 },
+ { "Asia/Gaza" , 0x019A73 },
+ { "Asia/Harbin" , 0x019DBC },
+ { "Asia/Ho_Chi_Minh" , 0x019EA3 },
+ { "Asia/Hong_Kong" , 0x019F1B },
+ { "Asia/Hovd" , 0x01A0D1 },
+ { "Asia/Irkutsk" , 0x01A249 },
+ { "Asia/Istanbul" , 0x01A530 },
+ { "Asia/Jakarta" , 0x01A91D },
+ { "Asia/Jayapura" , 0x01A9C7 },
+ { "Asia/Jerusalem" , 0x01AA4B },
+ { "Asia/Kabul" , 0x01AD7A },
+ { "Asia/Kamchatka" , 0x01ADCB },
+ { "Asia/Karachi" , 0x01B0B0 },
+ { "Asia/Kashgar" , 0x01B165 },
+ { "Asia/Kathmandu" , 0x01B236 },
+ { "Asia/Katmandu" , 0x01B29C },
+ { "Asia/Kolkata" , 0x01B302 },
+ { "Asia/Krasnoyarsk" , 0x01B37B },
+ { "Asia/Kuala_Lumpur" , 0x01B664 },
+ { "Asia/Kuching" , 0x01B721 },
+ { "Asia/Kuwait" , 0x01B80F },
+ { "Asia/Macao" , 0x01B864 },
+ { "Asia/Macau" , 0x01B99F },
+ { "Asia/Magadan" , 0x01BADA },
+ { "Asia/Makassar" , 0x01BDBD },
+ { "Asia/Manila" , 0x01BE76 },
+ { "Asia/Muscat" , 0x01BEFB },
+ { "Asia/Nicosia" , 0x01BF50 },
+ { "Asia/Novosibirsk" , 0x01C238 },
+ { "Asia/Omsk" , 0x01C52C },
+ { "Asia/Oral" , 0x01C814 },
+ { "Asia/Phnom_Penh" , 0x01C9E4 },
+ { "Asia/Pontianak" , 0x01CA5C },
+ { "Asia/Pyongyang" , 0x01CB1D },
+ { "Asia/Qatar" , 0x01CB8A },
+ { "Asia/Qyzylorda" , 0x01CBF0 },
+ { "Asia/Rangoon" , 0x01CDC6 },
+ { "Asia/Riyadh" , 0x01CE3E },
+ { "Asia/Saigon" , 0x01CE93 },
+ { "Asia/Sakhalin" , 0x01CF0B },
+ { "Asia/Samarkand" , 0x01D20B },
+ { "Asia/Seoul" , 0x01D341 },
+ { "Asia/Shanghai" , 0x01D3E5 },
+ { "Asia/Singapore" , 0x01D4C5 },
+ { "Asia/Taipei" , 0x01D57C },
+ { "Asia/Tashkent" , 0x01D694 },
+ { "Asia/Tbilisi" , 0x01D7C5 },
+ { "Asia/Tehran" , 0x01D97F },
+ { "Asia/Tel_Aviv" , 0x01DBED },
+ { "Asia/Thimbu" , 0x01DF1C },
+ { "Asia/Thimphu" , 0x01DF82 },
+ { "Asia/Tokyo" , 0x01DFE8 },
+ { "Asia/Ujung_Pandang" , 0x01E071 },
+ { "Asia/Ulaanbaatar" , 0x01E0ED },
+ { "Asia/Ulan_Bator" , 0x01E248 },
+ { "Asia/Urumqi" , 0x01E395 },
+ { "Asia/Vientiane" , 0x01E45C },
+ { "Asia/Vladivostok" , 0x01E4D4 },
+ { "Asia/Yakutsk" , 0x01E7C1 },
+ { "Asia/Yekaterinburg" , 0x01EAA7 },
+ { "Asia/Yerevan" , 0x01EDB3 },
+ { "Atlantic/Azores" , 0x01F0B7 },
+ { "Atlantic/Bermuda" , 0x01F5BA },
+ { "Atlantic/Canary" , 0x01F89B },
+ { "Atlantic/Cape_Verde" , 0x01FB71 },
+ { "Atlantic/Faeroe" , 0x01FBEA },
+ { "Atlantic/Faroe" , 0x01FE8E },
+ { "Atlantic/Jan_Mayen" , 0x020132 },
+ { "Atlantic/Madeira" , 0x020464 },
+ { "Atlantic/Reykjavik" , 0x02096D },
+ { "Atlantic/South_Georgia" , 0x020B26 },
+ { "Atlantic/St_Helena" , 0x020E3E },
+ { "Atlantic/Stanley" , 0x020B6A },
+ { "Australia/ACT" , 0x020E93 },
+ { "Australia/Adelaide" , 0x0211B0 },
+ { "Australia/Brisbane" , 0x0214DC },
+ { "Australia/Broken_Hill" , 0x0215A3 },
+ { "Australia/Canberra" , 0x0218E1 },
+ { "Australia/Currie" , 0x021BFE },
+ { "Australia/Darwin" , 0x021F31 },
+ { "Australia/Eucla" , 0x021FB7 },
+ { "Australia/Hobart" , 0x02208C },
+ { "Australia/LHI" , 0x0223EA },
+ { "Australia/Lindeman" , 0x022685 },
+ { "Australia/Lord_Howe" , 0x022766 },
+ { "Australia/Melbourne" , 0x022A11 },
+ { "Australia/North" , 0x022D36 },
+ { "Australia/NSW" , 0x022DAA },
+ { "Australia/Perth" , 0x0230C7 },
+ { "Australia/Queensland" , 0x02319F },
+ { "Australia/South" , 0x02324B },
+ { "Australia/Sydney" , 0x023568 },
+ { "Australia/Tasmania" , 0x0238A5 },
+ { "Australia/Victoria" , 0x023BEA },
+ { "Australia/West" , 0x023F07 },
+ { "Australia/Yancowinna" , 0x023FBD },
+ { "Brazil/Acre" , 0x0242DF },
+ { "Brazil/DeNoronha" , 0x0243DE },
+ { "Brazil/East" , 0x0244FE },
+ { "Brazil/West" , 0x0247DB },
+ { "Canada/Atlantic" , 0x0248D3 },
+ { "Canada/Central" , 0x024DBB },
+ { "Canada/East-Saskatchewan" , 0x0256C5 },
+ { "Canada/Eastern" , 0x0251D5 },
+ { "Canada/Mountain" , 0x02584E },
+ { "Canada/Newfoundland" , 0x025BC4 },
+ { "Canada/Pacific" , 0x0260EF },
+ { "Canada/Saskatchewan" , 0x026508 },
+ { "Canada/Yukon" , 0x026691 },
+ { "CET" , 0x026994 },
+ { "Chile/Continental" , 0x026C9D },
+ { "Chile/EasterIsland" , 0x027038 },
+ { "CST6CDT" , 0x02737A },
+ { "Cuba" , 0x0276CB },
+ { "EET" , 0x027A3E },
+ { "Egypt" , 0x027CF1 },
+ { "Eire" , 0x0280B8 },
+ { "EST" , 0x0285C9 },
+ { "EST5EDT" , 0x02860D },
+ { "Etc/GMT" , 0x02895E },
+ { "Etc/GMT+0" , 0x028A2A },
+ { "Etc/GMT+1" , 0x028AB4 },
+ { "Etc/GMT+10" , 0x028B41 },
+ { "Etc/GMT+11" , 0x028BCF },
+ { "Etc/GMT+12" , 0x028C5D },
+ { "Etc/GMT+2" , 0x028D78 },
+ { "Etc/GMT+3" , 0x028E04 },
+ { "Etc/GMT+4" , 0x028E90 },
+ { "Etc/GMT+5" , 0x028F1C },
+ { "Etc/GMT+6" , 0x028FA8 },
+ { "Etc/GMT+7" , 0x029034 },
+ { "Etc/GMT+8" , 0x0290C0 },
+ { "Etc/GMT+9" , 0x02914C },
+ { "Etc/GMT-0" , 0x0289E6 },
+ { "Etc/GMT-1" , 0x028A6E },
+ { "Etc/GMT-10" , 0x028AFA },
+ { "Etc/GMT-11" , 0x028B88 },
+ { "Etc/GMT-12" , 0x028C16 },
+ { "Etc/GMT-13" , 0x028CA4 },
+ { "Etc/GMT-14" , 0x028CEB },
+ { "Etc/GMT-2" , 0x028D32 },
+ { "Etc/GMT-3" , 0x028DBE },
+ { "Etc/GMT-4" , 0x028E4A },
+ { "Etc/GMT-5" , 0x028ED6 },
+ { "Etc/GMT-6" , 0x028F62 },
+ { "Etc/GMT-7" , 0x028FEE },
+ { "Etc/GMT-8" , 0x02907A },
+ { "Etc/GMT-9" , 0x029106 },
+ { "Etc/GMT0" , 0x0289A2 },
+ { "Etc/Greenwich" , 0x029192 },
+ { "Etc/UCT" , 0x0291D6 },
+ { "Etc/Universal" , 0x02921A },
+ { "Etc/UTC" , 0x02925E },
+ { "Etc/Zulu" , 0x0292A2 },
+ { "Europe/Amsterdam" , 0x0292E6 },
+ { "Europe/Andorra" , 0x029724 },
+ { "Europe/Athens" , 0x0299A0 },
+ { "Europe/Belfast" , 0x029CE3 },
+ { "Europe/Belgrade" , 0x02A21A },
+ { "Europe/Berlin" , 0x02A4E3 },
+ { "Europe/Bratislava" , 0x02A839 },
+ { "Europe/Brussels" , 0x02AB6B },
+ { "Europe/Bucharest" , 0x02AFA2 },
+ { "Europe/Budapest" , 0x02B2CC },
+ { "Europe/Chisinau" , 0x02B63F },
+ { "Europe/Copenhagen" , 0x02B9CD },
+ { "Europe/Dublin" , 0x02BCD7 },
+ { "Europe/Gibraltar" , 0x02C1E8 },
+ { "Europe/Guernsey" , 0x02C63F },
+ { "Europe/Helsinki" , 0x02CB76 },
+ { "Europe/Isle_of_Man" , 0x02CE2C },
+ { "Europe/Istanbul" , 0x02D363 },
+ { "Europe/Jersey" , 0x02D750 },
+ { "Europe/Kaliningrad" , 0x02DC87 },
+ { "Europe/Kiev" , 0x02DFEA },
+ { "Europe/Lisbon" , 0x02E301 },
+ { "Europe/Ljubljana" , 0x02E805 },
+ { "Europe/London" , 0x02EACE },
+ { "Europe/Luxembourg" , 0x02F005 },
+ { "Europe/Madrid" , 0x02F45B },
+ { "Europe/Malta" , 0x02F821 },
+ { "Europe/Mariehamn" , 0x02FBDA },
+ { "Europe/Minsk" , 0x02FE90 },
+ { "Europe/Monaco" , 0x03019B },
+ { "Europe/Moscow" , 0x0305D6 },
+ { "Europe/Nicosia" , 0x030928 },
+ { "Europe/Oslo" , 0x030C10 },
+ { "Europe/Paris" , 0x030F42 },
+ { "Europe/Podgorica" , 0x031388 },
+ { "Europe/Prague" , 0x031651 },
+ { "Europe/Riga" , 0x031983 },
+ { "Europe/Rome" , 0x031CC8 },
+ { "Europe/Samara" , 0x03208B },
+ { "Europe/San_Marino" , 0x0323B7 },
+ { "Europe/Sarajevo" , 0x03277A },
+ { "Europe/Simferopol" , 0x032A43 },
+ { "Europe/Skopje" , 0x032D6E },
+ { "Europe/Sofia" , 0x033037 },
+ { "Europe/Stockholm" , 0x03333F },
+ { "Europe/Tallinn" , 0x0335EE },
+ { "Europe/Tirane" , 0x033928 },
+ { "Europe/Tiraspol" , 0x033C2E },
+ { "Europe/Uzhgorod" , 0x033FBC },
+ { "Europe/Vaduz" , 0x0342D3 },
+ { "Europe/Vatican" , 0x034566 },
+ { "Europe/Vienna" , 0x034929 },
+ { "Europe/Vilnius" , 0x034C56 },
+ { "Europe/Volgograd" , 0x034F95 },
+ { "Europe/Warsaw" , 0x03529E },
+ { "Europe/Zagreb" , 0x03567F },
+ { "Europe/Zaporozhye" , 0x035948 },
+ { "Europe/Zurich" , 0x035C89 },
+ { "Factory" , 0x035F38 },
+ { "GB" , 0x035FA9 },
+ { "GB-Eire" , 0x0364E0 },
+ { "GMT" , 0x036A17 },
+ { "GMT+0" , 0x036AE3 },
+ { "GMT-0" , 0x036A9F },
+ { "GMT0" , 0x036A5B },
+ { "Greenwich" , 0x036B27 },
+ { "Hongkong" , 0x036B6B },
+ { "HST" , 0x036D21 },
+ { "Iceland" , 0x036D65 },
+ { "Indian/Antananarivo" , 0x036F1E },
+ { "Indian/Chagos" , 0x036F92 },
+ { "Indian/Christmas" , 0x036FF4 },
+ { "Indian/Cocos" , 0x037038 },
+ { "Indian/Comoro" , 0x03707C },
+ { "Indian/Kerguelen" , 0x0370D1 },
+ { "Indian/Mahe" , 0x037126 },
+ { "Indian/Maldives" , 0x03717B },
+ { "Indian/Mauritius" , 0x0371D0 },
+ { "Indian/Mayotte" , 0x037373 },
+ { "Indian/Reunion" , 0x0373C8 },
+ { "Iran" , 0x03741D },
+ { "Israel" , 0x03768B },
+ { "Jamaica" , 0x0379BA },
+ { "Japan" , 0x037A7F },
+ { "Kwajalein" , 0x037B08 },
+ { "Libya" , 0x037B6B },
+ { "MET" , 0x037C65 },
+ { "Mexico/BajaNorte" , 0x037F6E },
+ { "Mexico/BajaSur" , 0x0382D7 },
+ { "Mexico/General" , 0x03851C },
+ { "MST" , 0x03877A },
+ { "MST7MDT" , 0x0387BE },
+ { "Navajo" , 0x038B0F },
+ { "NZ" , 0x038E88 },
+ { "NZ-CHAT" , 0x039206 },
+ { "Pacific/Apia" , 0x0394EE },
+ { "Pacific/Auckland" , 0x039555 },
+ { "Pacific/Chatham" , 0x0398E1 },
+ { "Pacific/Easter" , 0x039BD8 },
+ { "Pacific/Efate" , 0x039F36 },
+ { "Pacific/Enderbury" , 0x039FFC },
+ { "Pacific/Fakaofo" , 0x03A06A },
+ { "Pacific/Fiji" , 0x03A0AE },
+ { "Pacific/Funafuti" , 0x03A124 },
+ { "Pacific/Galapagos" , 0x03A168 },
+ { "Pacific/Gambier" , 0x03A1E0 },
+ { "Pacific/Guadalcanal" , 0x03A245 },
+ { "Pacific/Guam" , 0x03A29A },
+ { "Pacific/Honolulu" , 0x03A2F0 },
+ { "Pacific/Johnston" , 0x03A384 },
+ { "Pacific/Kiritimati" , 0x03A3D6 },
+ { "Pacific/Kosrae" , 0x03A441 },
+ { "Pacific/Kwajalein" , 0x03A49E },
+ { "Pacific/Majuro" , 0x03A50A },
+ { "Pacific/Marquesas" , 0x03A569 },
+ { "Pacific/Midway" , 0x03A5D0 },
+ { "Pacific/Nauru" , 0x03A65A },
+ { "Pacific/Niue" , 0x03A6D2 },
+ { "Pacific/Norfolk" , 0x03A730 },
+ { "Pacific/Noumea" , 0x03A785 },
+ { "Pacific/Pago_Pago" , 0x03A815 },
+ { "Pacific/Palau" , 0x03A89E },
+ { "Pacific/Pitcairn" , 0x03A8E2 },
+ { "Pacific/Ponape" , 0x03A937 },
+ { "Pacific/Port_Moresby" , 0x03A98C },
+ { "Pacific/Rarotonga" , 0x03A9D0 },
+ { "Pacific/Saipan" , 0x03AAAC },
+ { "Pacific/Samoa" , 0x03AB0F },
+ { "Pacific/Tahiti" , 0x03AB98 },
+ { "Pacific/Tarawa" , 0x03ABFD },
+ { "Pacific/Tongatapu" , 0x03AC51 },
+ { "Pacific/Truk" , 0x03ACDD },
+ { "Pacific/Wake" , 0x03AD36 },
+ { "Pacific/Wallis" , 0x03AD86 },
+ { "Pacific/Yap" , 0x03ADCA },
+ { "Poland" , 0x03AE0F },
+ { "Portugal" , 0x03B1F0 },
+ { "PRC" , 0x03B6EC },
+ { "PST8PDT" , 0x03B79D },
+ { "ROC" , 0x03BAEE },
+ { "ROK" , 0x03BC06 },
+ { "Singapore" , 0x03BCAA },
+ { "Turkey" , 0x03BD61 },
+ { "UCT" , 0x03C14E },
+ { "Universal" , 0x03C192 },
+ { "US/Alaska" , 0x03C1D6 },
+ { "US/Aleutian" , 0x03C53F },
+ { "US/Arizona" , 0x03C8A5 },
+ { "US/Central" , 0x03C933 },
+ { "US/East-Indiana" , 0x03D33D },
+ { "US/Eastern" , 0x03CE3E },
+ { "US/Hawaii" , 0x03D5A7 },
+ { "US/Indiana-Starke" , 0x03D635 },
+ { "US/Michigan" , 0x03D9A6 },
+ { "US/Mountain" , 0x03DCDD },
+ { "US/Pacific" , 0x03E056 },
+ { "US/Pacific-New" , 0x03E45B },
+ { "US/Samoa" , 0x03E860 },
+ { "UTC" , 0x03E8E9 },
+ { "W-SU" , 0x03EBE0 },
+ { "WET" , 0x03E92D },
+ { "Zulu" , 0x03EF1B },
--- /dev/null
+#!/usr/bin/env perl
+use strict;
+use warnings;
+my ($tz, @zones);
+
+open FILE, "timezone.txt" or die $!;
+while (<FILE>) {
+ if ($_ =~ /"(\w*\/?\w*)"/) {
+ push @zones, $1;
+ }
+}
+close FILE;
+
+my $size = scalar @zones;
+$tz = "<?php\n\$timezone = array(\n";
+foreach (@zones) {
+ $size--;
+ $tz .= "\t\"$_\"";
+ $tz .= ($size) ? ",\n" : "\n";
+}
+$tz .= ");\n?>\n";
+
+open FILE, ">timezone.php" or die $!;
+print FILE $tz;
+
+exit 0;
--- /dev/null
+#!/bin/sh
+
+PATH=/usr/bin:/usr/sbin:/bin:/sbin
+DIR=/tmp
+USR=user.sql
+CAL=calendar.sql
+USR_DUMP=".mode insert user\n.output user.sql"
+CAL_DUMP=".mode insert calendar\n.output calendar.sql"
+
+function export_db() {
+ echo -n 'Please enter name of database to export from: '
+ read DB
+ if [ ! -e "$DB" ]; then
+ echo $DB: File does not exist
+ exit 1
+ fi
+
+ echo -e $USR_DUMP > "$DIR/$USR"
+ sqlite3 -init "$DIR/$USR" "$DB" 'select * from user where id <> 1'
+ rm -f "$DIR/$USR"
+
+ echo -e $CAL_DUMP > "$DIR/$CAL"
+ sqlite3 -init "$DIR/$CAL" "$DB" 'select * from calendar'
+ rm -f "$DIR/$CAL"
+}
+
+function import_db() {
+ echo -n 'Please enter name of database to import into: '
+ read DB
+ if [ ! -e "$DB" ]; then
+ echo $DB: File does not exist
+ exit 1
+ fi
+ if [ ! -e "./$USR" ]; then
+ echo $USR: File does not exist
+ exit 1
+ fi
+ if [ ! -e "./$CAL" ]; then
+ echo $CAL: File does not exist
+ exit 1
+ fi
+
+ sqlite3 "$DB" < "./$USR"
+ sqlite3 "$DB" < "./$CAL"
+
+ echo -n "Delete files containing backup [y/N]: "
+ read DEL
+ if [ ! -z "$DEL" ]; then
+ if [ "$DEL" = "y" -o "$DEL" = "Y" ]; then
+ rm -f "./$USR"
+ rm -f "./$CAL"
+ fi
+ fi
+}
+
+if [ $UID -ne '0' ]; then
+ echo You must run this script as root
+ exit 1
+fi
+
+case "$1" in
+ export)
+ export_db
+ echo Database was succesfully exported
+ echo You should now perform standard install
+ echo and run this script with command import
+ exit 0
+ ;;
+ import)
+ import_db
+ echo Database was succesfully imported
+ exit 0
+ ;;
+ *)
+ echo -e "usage: $0 CMD\n
+CMD is:
+\texport\texport data from a database
+\timport\timport data to a database"
+ exit 0
+ ;;
+esac
--- /dev/null
+var url = "http://localhost/~mir/test.php?name=";
+var output = new Array();
+var httpRequest;
+var fields = new Object();
+
+/**
+* Get the XMLHttpRequest Object
+* \return XMLHttpRequst, or <i>false</i> if fail
+*/
+function getXMLHttpRequest() {
+ if (window.XMLHttpRequest) { // Mozilla, Safari, ...
+ httpRequest = new XMLHttpRequest();
+ if (httpRequest.overrideMimeType) {
+ httpRequest.overrideMimeType('text/xml');
+ }
+ }
+ else if (window.ActiveXObject) { // IE
+ try {
+ httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
+ }
+ catch (e) {
+ try {
+ httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
+ }
+ catch (e) {}
+ }
+ }
+ if (!httpRequest) {
+ alert('Giving up :( Cannot create an XMLHTTP instance');
+ return false;
+ }
+ return true;
+}
+
+function handleHttpResponse(response, xml) {
+ if (xml == true) {
+ var text = response.getElementsByTagName('param')[0].firstChild.data
+ text = text + " : " + response.getElementsByTagName('greeting')[0].firstChild.data
+ document.getElementById("textarea").value = text
+ }
+ else {
+ document.getElementById("textarea").value = response.value
+ }
+}
+
+function setField(field, value) {
+ fields[field] = value
+}
+
+function getContactByName(name) {
+ if (httpRequest == null) {
+ alert("Could not initiate AJAX Session")
+ return null
+ }
+ httpRequest.onreadystatechange = function() {
+ if (httpRequest.readyState == 4) {
+ if (httpRequest.status == 200)
+ handleHttpResponse(httpRequest.responseXML, true)
+ }
+ }
+ httpRequest.open("GET", url + name, true)
+ httpRequest.send(null)
+}
+
+function handleEvent(field) {
+ try {
+ var f = fields[field]
+ if (f == "search_name") {
+ var name = document.getElementById(f).value
+ getContactByName(name)
+ }
+ }
+ catch (e) {
+ return false
+ }
+}
+
+if (!getXMLHttpRequest()) {
+ document.location = 'error.html';
+}
+window.onload = setField("name", "search_name");
+
+
--- /dev/null
+/* calendar icon */\r
+img.tcalIcon {\r
+ cursor: pointer;\r
+ margin-left: 1px;\r
+ vertical-align: middle;\r
+}\r
+/* calendar container element */\r
+div#tcal {\r
+ position: absolute;\r
+ visibility: hidden;\r
+ z-index: 100;\r
+ width: 158px;\r
+ padding: 2px 0 0 0;\r
+}\r
+/* all tables in calendar */\r
+div#tcal table {\r
+ width: 100%;\r
+ border: 1px solid silver;\r
+ border-collapse: collapse;\r
+ background-color: white;\r
+}\r
+/* navigation table */\r
+div#tcal table.ctrl {\r
+ border-bottom: 0;\r
+}\r
+/* navigation buttons */\r
+div#tcal table.ctrl td {\r
+ width: 15px;\r
+ height: 20px;\r
+}\r
+/* month year header */\r
+div#tcal table.ctrl th {\r
+ background-color: white;\r
+ color: black;\r
+ border: 0;\r
+}\r
+/* week days header */\r
+div#tcal th {\r
+ border: 1px solid silver;\r
+ border-collapse: collapse;\r
+ text-align: center;\r
+ padding: 3px 0;\r
+ font-family: tahoma, verdana, arial;\r
+ font-size: 10px;\r
+ background-color: gray;\r
+ color: white;\r
+}\r
+/* date cells */\r
+div#tcal td {\r
+ border: 0;\r
+ border-collapse: collapse;\r
+ text-align: center;\r
+ padding: 2px 0;\r
+ font-family: tahoma, verdana, arial;\r
+ font-size: 11px;\r
+ width: 22px;\r
+ cursor: pointer;\r
+}\r
+/* date highlight\r
+ in case of conflicting settings order here determines the priority from least to most important */\r
+div#tcal td.othermonth {\r
+ color: silver;\r
+}\r
+div#tcal td.weekend {\r
+ background-color: #ACD6F5;\r
+}\r
+div#tcal td.today {\r
+ border: 1px solid red;\r
+}\r
+div#tcal td.selected {\r
+ background-color: #FFB3BE;\r
+}\r
+/* iframe element used to suppress windowed controls in IE5/6 */\r
+iframe#tcalIF {\r
+ position: absolute;\r
+ visibility: hidden;\r
+ z-index: 98;\r
+ border: 0;\r
+}\r
+/* transparent shadow */\r
+div#tcalShade {\r
+ position: absolute;\r
+ visibility: hidden;\r
+ z-index: 99;\r
+}\r
+div#tcalShade table {\r
+ border: 0;\r
+ border-collapse: collapse;\r
+ width: 100%;\r
+}\r
+div#tcalShade table td {\r
+ border: 0;\r
+ border-collapse: collapse;\r
+ padding: 0;\r
+}\r
--- /dev/null
+// Tigra Calendar v4.0.2 (2009-01-12) Database (yyyy-mm-dd)\r
+// http://www.softcomplex.com/products/tigra_calendar/\r
+// Public Domain Software... You're welcome.\r
+\r
+// default settins\r
+var A_TCALDEF = {\r
+ 'months' : ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],\r
+ 'weekdays' : ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'],\r
+ 'yearscroll': true, // show year scroller\r
+ 'weekstart': 0, // first day of week: 0-Su or 1-Mo\r
+ 'centyear' : 70, // 2 digit years less than 'centyear' are in 20xx, othewise in 19xx.\r
+ 'imgpath' : 'img/' // directory with calendar images\r
+}\r
+// date parsing function\r
+function f_tcalParseDate (s_date) {\r
+\r
+ var re_date = /^\s*(\d{2,4})\-(\d{1,2})\-(\d{1,2})\s*$/;\r
+ if (!re_date.exec(s_date))\r
+ return alert ("Invalid date: '" + s_date + "'.\nAccepted format is yyyy-mm-dd.")\r
+ var n_day = Number(RegExp.$3),\r
+ n_month = Number(RegExp.$2),\r
+ n_year = Number(RegExp.$1);\r
+ \r
+ if (n_year < 100)\r
+ n_year += (n_year < this.a_tpl.centyear ? 2000 : 1900);\r
+ if (n_month < 1 || n_month > 12)\r
+ return alert ("Invalid month value: '" + n_month + "'.\nAllowed range is 01-12.");\r
+ var d_numdays = new Date(n_year, n_month, 0);\r
+ if (n_day > d_numdays.getDate())\r
+ return alert("Invalid day of month value: '" + n_day + "'.\nAllowed range for selected month is 01 - " + d_numdays.getDate() + ".");\r
+\r
+ return new Date (n_year, n_month - 1, n_day);\r
+}\r
+// date generating function\r
+function f_tcalGenerDate (d_date) {\r
+ return (\r
+ d_date.getFullYear() + "-"\r
+ + (d_date.getMonth() < 9 ? '0' : '') + (d_date.getMonth() + 1) + "-"\r
+ + (d_date.getDate() < 10 ? '0' : '') + d_date.getDate()\r
+ );\r
+}\r
+\r
+// implementation\r
+function tcal (a_cfg, a_tpl) {\r
+\r
+ // apply default template if not specified\r
+ if (!a_tpl)\r
+ a_tpl = A_TCALDEF;\r
+\r
+ // register in global collections\r
+ if (!window.A_TCALS)\r
+ window.A_TCALS = [];\r
+ if (!window.A_TCALSIDX)\r
+ window.A_TCALSIDX = [];\r
+ \r
+ this.s_id = a_cfg.id ? a_cfg.id : A_TCALS.length;\r
+ window.A_TCALS[this.s_id] = this;\r
+ window.A_TCALSIDX[window.A_TCALSIDX.length] = this;\r
+ \r
+ // assign methods\r
+ this.f_show = f_tcalShow;\r
+ this.f_hide = f_tcalHide;\r
+ this.f_toggle = f_tcalToggle;\r
+ this.f_update = f_tcalUpdate;\r
+ this.f_relDate = f_tcalRelDate;\r
+ this.f_parseDate = f_tcalParseDate;\r
+ this.f_generDate = f_tcalGenerDate;\r
+ \r
+ // create calendar icon\r
+ this.s_iconId = 'tcalico_' + this.s_id;\r
+ this.e_icon = f_getElement(this.s_iconId);\r
+ if (!this.e_icon) {\r
+ document.write('<img src="' + a_tpl.imgpath + 'cal.gif" id="' + this.s_iconId + '" onclick="A_TCALS[\'' + this.s_id + '\'].f_toggle()" class="tcalIcon" alt="Open Calendar" />');\r
+ this.e_icon = f_getElement(this.s_iconId);\r
+ }\r
+ // save received parameters\r
+ this.a_cfg = a_cfg;\r
+ this.a_tpl = a_tpl;\r
+}\r
+\r
+function f_tcalShow (d_date) {\r
+\r
+ // find input field\r
+ if (!this.a_cfg.controlname)\r
+ throw("TC: control name is not specified");\r
+ if (this.a_cfg.formname) {\r
+ var e_form = document.forms[this.a_cfg.formname];\r
+ if (!e_form)\r
+ throw("TC: form '" + this.a_cfg.formname + "' can not be found");\r
+ this.e_input = e_form.elements[this.a_cfg.controlname];\r
+ }\r
+ else\r
+ this.e_input = f_getElement(this.a_cfg.controlname);\r
+\r
+ if (!this.e_input || !this.e_input.tagName || this.e_input.tagName != 'INPUT')\r
+ throw("TC: element '" + this.a_cfg.controlname + "' does not exist in "\r
+ + (this.a_cfg.formname ? "form '" + this.a_cfg.controlname + "'" : 'this document'));\r
+\r
+ // dynamically create HTML elements if needed\r
+ this.e_div = f_getElement('tcal');\r
+ if (!this.e_div) {\r
+ this.e_div = document.createElement("DIV");\r
+ this.e_div.id = 'tcal';\r
+ document.body.appendChild(this.e_div);\r
+ }\r
+ this.e_shade = f_getElement('tcalShade');\r
+ if (!this.e_shade) {\r
+ this.e_shade = document.createElement("DIV");\r
+ this.e_shade.id = 'tcalShade';\r
+ document.body.appendChild(this.e_shade);\r
+ }\r
+ this.e_iframe = f_getElement('tcalIF')\r
+ if (b_ieFix && !this.e_iframe) {\r
+ this.e_iframe = document.createElement("IFRAME");\r
+ this.e_iframe.style.filter = 'alpha(opacity=0)';\r
+ this.e_iframe.id = 'tcalIF';\r
+ this.e_iframe.src = this.a_tpl.imgpath + 'pixel.gif';\r
+ document.body.appendChild(this.e_iframe);\r
+ }\r
+ \r
+ // hide all calendars\r
+ f_tcalHideAll();\r
+\r
+ // generate HTML and show calendar\r
+ this.e_icon = f_getElement(this.s_iconId);\r
+ if (!this.f_update())\r
+ return;\r
+\r
+ this.e_div.style.visibility = 'visible';\r
+ this.e_shade.style.visibility = 'visible';\r
+ if (this.e_iframe)\r
+ this.e_iframe.style.visibility = 'visible';\r
+\r
+ // change icon and status\r
+ this.e_icon.src = this.a_tpl.imgpath + 'no_cal.gif';\r
+ this.e_icon.title = 'Close Calendar';\r
+ this.b_visible = true;\r
+}\r
+\r
+function f_tcalHide (n_date) {\r
+ if (n_date) {\r
+ this.e_input.value = this.f_generDate(new Date(n_date));\r
+ if (this.e_input.onchange) {\r
+ this.e_input.onchange(this.e_input);\r
+ }\r
+ }\r
+\r
+ // no action if not visible\r
+ if (!this.b_visible)\r
+ return;\r
+\r
+ // hide elements\r
+ if (this.e_iframe)\r
+ this.e_iframe.style.visibility = 'hidden';\r
+ if (this.e_shade)\r
+ this.e_shade.style.visibility = 'hidden';\r
+ this.e_div.style.visibility = 'hidden';\r
+ \r
+ // change icon and status\r
+ this.e_icon = f_getElement(this.s_iconId);\r
+ this.e_icon.src = this.a_tpl.imgpath + 'cal.gif';\r
+ this.e_icon.title = 'Open Calendar';\r
+ this.b_visible = false;\r
+}\r
+\r
+function f_tcalToggle () {\r
+ return this.b_visible ? this.f_hide() : this.f_show();\r
+}\r
+\r
+function f_tcalUpdate (d_date) {\r
+ \r
+ var d_client = new Date();\r
+ d_client.setHours(0);\r
+ d_client.setMinutes(0);\r
+ d_client.setSeconds(0);\r
+ d_client.setMilliseconds(0);\r
+ \r
+ var d_today = this.a_cfg.today ? this.f_parseDate(this.a_cfg.today) : d_client;\r
+ var d_selected = this.e_input.value == ''\r
+ ? (this.a_cfg.selected ? this.f_parseDate(this.a_cfg.selected) : d_today)\r
+ : this.f_parseDate(this.e_input.value);\r
+\r
+ // figure out date to display\r
+ if (!d_date)\r
+ // selected by default\r
+ d_date = d_selected;\r
+ else if (typeof(d_date) == 'number')\r
+ // get from number\r
+ d_date = new Date(d_date);\r
+ else if (typeof(d_date) == 'string')\r
+ // parse from string\r
+ this.f_parseDate(d_date);\r
+ \r
+ if (!d_date) return false;\r
+\r
+ // first date to display\r
+ var d_firstday = new Date(d_date);\r
+ d_firstday.setDate(1);\r
+ d_firstday.setDate(1 - (7 + d_firstday.getDay() - this.a_tpl.weekstart) % 7);\r
+ \r
+ var a_class, s_html = '<table class="ctrl"><tbody><tr>'\r
+ + (this.a_tpl.yearscroll ? '<td' + this.f_relDate(d_date, -1, 'y') + ' title="Previous Year"><img src="' + this.a_tpl.imgpath + 'prev_year.gif" /></td>' : '')\r
+ + '<td' + this.f_relDate(d_date, -1) + ' title="Previous Month"><img src="' + this.a_tpl.imgpath + 'prev_mon.gif" /></td><th>'\r
+ + this.a_tpl.months[d_date.getMonth()] + ' ' + d_date.getFullYear()\r
+ + '</th><td' + this.f_relDate(d_date, 1) + ' title="Next Month"><img src="' + this.a_tpl.imgpath + 'next_mon.gif" /></td>'\r
+ + (this.a_tpl.yearscroll ? '<td' + this.f_relDate(d_date, 1, 'y') + ' title="Next Year"><img src="' + this.a_tpl.imgpath + 'next_year.gif" /></td></td>' : '')\r
+ + '</tr></tbody></table><table><tbody><tr class="wd">';\r
+\r
+ // print weekdays titles\r
+ for (var i = 0; i < 7; i++)\r
+ s_html += '<th>' + this.a_tpl.weekdays[(this.a_tpl.weekstart + i) % 7] + '</th>';\r
+ s_html += '</tr>' ;\r
+\r
+ // print calendar table\r
+ var d_current = new Date(d_firstday);\r
+ while (d_current.getMonth() == d_date.getMonth() ||\r
+ d_current.getMonth() == d_firstday.getMonth()) {\r
+ \r
+ // print row heder\r
+ s_html +='<tr>';\r
+ for (var n_wday = 0; n_wday < 7; n_wday++) {\r
+\r
+ a_class = [];\r
+ // other month\r
+ if (d_current.getMonth() != d_date.getMonth())\r
+ a_class[a_class.length] = 'othermonth';\r
+ // weekend\r
+ if (d_current.getDay() == 0 || d_current.getDay() == 6)\r
+ a_class[a_class.length] = 'weekend';\r
+ // today\r
+ if (d_current.valueOf() == d_today.valueOf())\r
+ a_class[a_class.length] = 'today';\r
+ // selected\r
+ if (d_current.valueOf() == d_selected.valueOf())\r
+ a_class[a_class.length] = 'selected';\r
+\r
+ s_html += '<td onclick="A_TCALS[\'' + this.s_id + '\'].f_hide(' + d_current.valueOf() + ')"' + (a_class.length ? ' class="' + a_class.join(' ') + '">' : '>') + d_current.getDate() + '</td>'\r
+ d_current.setDate(d_current.getDate() + 1);\r
+ }\r
+ // print row footer\r
+ s_html +='</tr>';\r
+ }\r
+ s_html +='</tbody></table>';\r
+ \r
+ // update HTML, positions and sizes\r
+ this.e_div.innerHTML = s_html;\r
+\r
+ var n_width = this.e_div.offsetWidth;\r
+ var n_height = this.e_div.offsetHeight;\r
+ var n_top = f_getPosition (this.e_icon, 'Top') + this.e_icon.offsetHeight;\r
+ var n_left = f_getPosition (this.e_icon, 'Left') - n_width + this.e_icon.offsetWidth;\r
+ if (n_left < 0) n_left = 0;\r
+ \r
+ this.e_div.style.left = n_left + 'px';\r
+ this.e_div.style.top = n_top + 'px';\r
+\r
+ this.e_shade.style.width = (n_width + 8) + 'px';\r
+ this.e_shade.style.left = (n_left - 1) + 'px';\r
+ this.e_shade.style.top = (n_top - 1) + 'px';\r
+ this.e_shade.innerHTML = b_ieFix\r
+ ? '<table><tbody><tr><td rowspan="2" colspan="2" width="6"><img src="' + this.a_tpl.imgpath + 'pixel.gif"></td><td width="7" height="7" style="filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + this.a_tpl.imgpath + 'shade_tr.png\', sizingMethod=\'scale\');"><img src="' + this.a_tpl.imgpath + 'pixel.gif"></td></tr><tr><td height="' + (n_height - 7) + '" style="filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + this.a_tpl.imgpath + 'shade_mr.png\', sizingMethod=\'scale\');"><img src="' + this.a_tpl.imgpath + 'pixel.gif"></td></tr><tr><td width="7" style="filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + this.a_tpl.imgpath + 'shade_bl.png\', sizingMethod=\'scale\');"><img src="' + this.a_tpl.imgpath + 'pixel.gif"></td><td style="filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + this.a_tpl.imgpath + 'shade_bm.png\', sizingMethod=\'scale\');" height="7" align="left"><img src="' + this.a_tpl.imgpath + 'pixel.gif"></td><td style="filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + this.a_tpl.imgpath + 'shade_br.png\', sizingMethod=\'scale\');"><img src="' + this.a_tpl.imgpath + 'pixel.gif"></td></tr><tbody></table>'\r
+ : '<table><tbody><tr><td rowspan="2" width="6"><img src="' + this.a_tpl.imgpath + 'pixel.gif"></td><td rowspan="2"><img src="' + this.a_tpl.imgpath + 'pixel.gif"></td><td width="7" height="7"><img src="' + this.a_tpl.imgpath + 'shade_tr.png"></td></tr><tr><td background="' + this.a_tpl.imgpath + 'shade_mr.png" height="' + (n_height - 7) + '"><img src="' + this.a_tpl.imgpath + 'pixel.gif"></td></tr><tr><td><img src="' + this.a_tpl.imgpath + 'shade_bl.png"></td><td background="' + this.a_tpl.imgpath + 'shade_bm.png" height="7" align="left"><img src="' + this.a_tpl.imgpath + 'pixel.gif"></td><td><img src="' + this.a_tpl.imgpath + 'shade_br.png"></td></tr><tbody></table>';\r
+ \r
+ if (this.e_iframe) {\r
+ this.e_iframe.style.left = n_left + 'px';\r
+ this.e_iframe.style.top = n_top + 'px';\r
+ this.e_iframe.style.width = (n_width + 6) + 'px';\r
+ this.e_iframe.style.height = (n_height + 6) +'px';\r
+ }\r
+ return true;\r
+}\r
+\r
+function f_getPosition (e_elemRef, s_coord) {\r
+ var n_pos = 0, n_offset,\r
+ e_elem = e_elemRef;\r
+\r
+ while (e_elem) {\r
+ n_offset = e_elem["offset" + s_coord];\r
+ n_pos += n_offset;\r
+ e_elem = e_elem.offsetParent;\r
+ }\r
+ // margin correction in some browsers\r
+ if (b_ieMac)\r
+ n_pos += parseInt(document.body[s_coord.toLowerCase() + 'Margin']);\r
+ else if (b_safari)\r
+ n_pos -= n_offset;\r
+ \r
+ e_elem = e_elemRef;\r
+ while (e_elem != document.body) {\r
+ n_offset = e_elem["scroll" + s_coord];\r
+ if (n_offset && e_elem.style.overflow == 'scroll')\r
+ n_pos -= n_offset;\r
+ e_elem = e_elem.parentNode;\r
+ }\r
+ return n_pos;\r
+}\r
+\r
+function f_tcalRelDate (d_date, d_diff, s_units) {\r
+ var s_units = (s_units == 'y' ? 'FullYear' : 'Month');\r
+ var d_result = new Date(d_date);\r
+ d_result['set' + s_units](d_date['get' + s_units]() + d_diff);\r
+ if (d_result.getDate() != d_date.getDate())\r
+ d_result.setDate(0);\r
+ return ' onclick="A_TCALS[\'' + this.s_id + '\'].f_update(' + d_result.valueOf() + ')"';\r
+}\r
+\r
+function f_tcalHideAll () {\r
+ for (var i = 0; i < window.A_TCALSIDX.length; i++)\r
+ window.A_TCALSIDX[i].f_hide();\r
+} \r
+\r
+f_getElement = document.all ?\r
+ function (s_id) { return document.all[s_id] } :\r
+ function (s_id) { return document.getElementById(s_id) };\r
+\r
+if (document.addEventListener)\r
+ window.addEventListener('scroll', f_tcalHideAll, false);\r
+if (window.attachEvent)\r
+ window.attachEvent('onscroll', f_tcalHideAll);\r
+ \r
+// global variables\r
+var s_userAgent = navigator.userAgent.toLowerCase(),\r
+ re_webkit = /WebKit\/(\d+)/i;\r
+var b_mac = s_userAgent.indexOf('mac') != -1,\r
+ b_ie5 = s_userAgent.indexOf('msie 5') != -1,\r
+ b_ie6 = s_userAgent.indexOf('msie 6') != -1 && s_userAgent.indexOf('opera') == -1;\r
+var b_ieFix = b_ie5 || b_ie6,\r
+ b_ieMac = b_mac && b_ie5,\r
+ b_safari = b_mac && re_webkit.exec(s_userAgent) && Number(RegExp.$1) < 500;\r
--- /dev/null
+// $Id$
+
+var onClickDisabled = [];
+var allDay = false;
+var observable_startdate = ['enddate'];
+var observable_enddate = ['startdate'];
+
+function newwin(url) {
+ window.open(url);
+}
+
+function focus(element) {
+ document.getElementById(element).focus();
+}
+
+function show_the_overlay() {
+ document.getElementById('display_overlay_holder').style.display = 'block';
+}
+
+function hide_the_overlay(referer) {
+ document.getElementById('display_overlay_holder').style.display = 'none';
+document.location.href=referer;
+}
+
+function setCalendar(form, input, cal) {
+ var id = document.getElementById(input);
+ var theForm = document.getElementById(form);
+
+ if (id == null || theForm == null)
+ return;
+ id.value = cal;
+}
+
+function error(msg) {
+ alert(msg);
+ document.location.href="$referer";
+}
+
+function redirect(url) {
+ window.location = url;
+}
+
+function is_array(obj) {
+ return obj && !(obj.propertyIsEnumerable('length')) &&
+ typeof obj === 'object' && typeof obj.length === 'number';
+}
+
+function getDateString(date, add) {
+ var m = (date.getMonth() + 1);
+ if (m < 10)
+ m = '0' + m;
+ var d = (date.getDate() + add);
+ if (d < 10)
+ d = '0' + d;
+ var s = date.getFullYear() + '-' + m + '-' + d;
+ return s;
+}
+
+function getTimeString(date, end) {
+ var m = date.getMinutes();
+ var h = 0;
+ if (m < 8)
+ m = '00';
+ else if (m < 23)
+ m = '15';
+ else if (m < 38)
+ m = '30';
+ else if (m < 43)
+ m = '45';
+ else {
+ m = '00';
+ h = 1;
+ }
+ var h = date.getHours() + h + end;
+ if (h < 10)
+ h = '0' + h;
+ return h + m;
+}
+
+function stateSwitch(btn, elements, init) {
+ if (btn == null || elements == null || ! is_array(elements) || elements.length < 1)
+ return;
+
+ var starttime = document.getElementById('starttime');
+ var endtime = document.getElementById('endtime');
+ var startdate = document.getElementById('startdate');
+ var enddate = document.getElementById('enddate');
+ allDay = btn.checked;
+ for (var i = 0; i < elements.length; i++) {
+ var elem = document.getElementById(elements[i]);
+ if (btn.checked == true) {
+ elem.disabled = true;
+ if (elem.onclick) {
+ onClickDisabled[elem.id] = elem.onclick;
+ elem.onclick = null;
+ }
+ }
+ else {
+ var tmp = null;
+ if (onClickDisabled[elem.id])
+ var tmp = onClickDisabled[elem.id];
+ if (tmp) {
+ elem.onclick = tmp;
+ onClickDisabled[elem.id] = null;
+ }
+ elem.disabled = false;
+ }
+ }
+ if (! init) {
+ if (allDay) {
+ starttime.value = '0000';
+ endtime.value = '0000';
+ var s_date = new Date(startdate.value);
+ var e_date = new Date(getDateString(s_date, 1));
+ enddate.value = getDateString(e_date, 0);
+ }
+ else {
+ var now = new Date();
+ var time = getTimeString(now, 0);
+ var s_date = new Date(startdate.value);
+ enddate.value = getDateString(s_date, 0);
+ starttime.value = time;
+ endtime.value = getTimeString(now, 1);
+ }
+ }
+}
+
+function enableAll(elements) {
+ if (elements == null || ! is_array(elements) || elements.length < 1)
+ return true;
+
+ for (var i = 0; i < elements.length; i++) {
+ var elem = document.getElementById(elements[i]);
+ elem.disabled = false;
+ }
+ return true;
+}
+
+function dateAlign(hasDate) {
+ if (hasDate == null)
+ return;
+
+ if (hasDate.id == 'startdate')
+ elements = observable_startdate;
+ else
+ elements = observable_enddate;
+
+ for (var i = 0; i < elements.length; i++) {
+ var elem = document.getElementById(elements[i]);
+ elem.value = hasDate.value;
+ }
+}
\ No newline at end of file
--- /dev/null
+Tigra Calendar v4.0 LICENSE:
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
\ No newline at end of file
--- /dev/null
+/* $Id$ */
+
+WebCal is a web based CalDAV enabled calendar. WebCal is mainly
+developed as a frontend to DAViCAL but should be able to connect to
+any standard conforming CalDAV calender server.
+
+Copyright (C) 2009 Michael Rasmussen <mir@datanom.net>
+
+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 3 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, see <http://www.gnu.org/licenses/>.
+
+Part of the application is the copyright of other persons.
+
+- caldav-client.php and awl is copyright Andrew McMillan added minor
+changes by me. caldav-client.php and awl is licensed under GPL 2+
+
+- Tigra Calendar is copyright www.softcomplex.com. Tigra Calendar is
+licensed under public domain.
--- /dev/null
+<?php
+/* $Id$ */
+
+if (! file_exists('config.inc.php'))
+ throw new Exception("The application is not configured yet");
+
+include_once 'config.inc.php';
+require_once 'helper.php';
+
+if (isset($_SESSION['attemps']))
+ $_SESSION['attemps']++;
+else
+ $_SESSION['attemps'] = 1;
+
+if ($_SESSION['attemps'] == 1) {
+ $_SESSION['authenticate'] = new Authenticate(DBDRIVER);
+}
+
+/*
+ * To avoid bots, script kiddeis or other password harvester
+ * add a 5 seconds delay for every 5 failed attemps
+ */
+if ($_SESSION['attemps'] > 5) {
+ sleep(5);
+ header('Location: logout.php');
+}
+
+if (isset($_POST['uid']) && isset($_POST['pwd'])) {
+ $auth = $_SESSION['authenticate'];
+
+ $auth->login($_POST['uid'], $_POST['pwd']);
+ if ($auth->validUser()) {
+ unset($_SESSION['attemps']);
+ $_SESSION['user_settings'] = new UserSettings($_POST['uid']);
+ $_SESSION['user_settings']->setSettings(
+ $_SESSION['authenticate']->getSettings());
+ //var_dump($_SESSION['user_settings']);
+ //var_dump($_SESSION['authenticate']->getSettings());
+ header('Location: index.php');
+ exit();
+ }
+}
+
+include 'include/header.inc.php';
+$email = ADMIN_MAIL;
+$action = $_SERVER['PHP_SELF'];
+
+print <<< _HTML
+<div id="login_msg">
+ <form action="$action" method="post">
+ <table>
+ <tr>
+ <td>Username</td><td><input id="uid" type="text" name="uid"/></td>
+ </tr>
+ <tr>
+ <td>Password</td><td><input type="password" name="pwd"/></td>
+ </tr>
+ <tr>
+ <td colspan="2" style="text-align: center">
+ <input type="reset" value="Clear"/>
+ <input type="submit" name="submit" value="Login"/>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2" style="text-align: center">If you don't have an account
+ <a href="mailto:$email?subject=Requesting an account">apply</a>
+ </td>
+ </tr>
+ </table>
+ </form>
+</div>
+<script type="text/javascript">
+ focus("uid");
+</script>
+_HTML;
+
+include 'include/footer.inc.php';
+
+?>
--- /dev/null
+<?php
+/* $Id$ */
+require_once 'config.inc.php';
+require_once 'authenticate.php';
+require_once 'helper.php';
+
+$root = WEB_ROOT;
+
+/* $_SESSION['caldav_server']->save(); */
+if (isset($_SESSION['authenticate']) && is_object($_SESSION['authenticate']))
+ $_SESSION['authenticate']->logout();
+
+setcookie('WEBCAL_EXPIRE', '', time()-3600, $_SESSION['WEB_ROOT']);
+
+// Unset all of the session variables.
+$_SESSION = array();
+
+if (ini_get("session.use_cookies")) {
+ $params = session_get_cookie_params();
+ setcookie(session_name(), '', time() - 42000,
+ $params["path"], $params["domain"],
+ $params["secure"], $params["httponly"]
+ );
+}
+
+// Finally, destroy the session.
+session_destroy();
+session_write_close();
+session_unset();
+
+header("Location: " . getServerUrl($root) . "/index.php");
+exit;
+?>
\ No newline at end of file
--- /dev/null
+#!/bin/sh
+
+CP="cp --parents"
+if [ -e doc_source ]; then
+ rm -rf doc_source
+fi
+
+if [ -e doc ]; then
+ rm -rf doc
+fi
+
+mkdir doc_source
+mkdir doc
+
+$CP caldav/*.php doc_source
+$CP events/*.php doc_source
+$CP include/*.php doc_source
+$CP install/*.php doc_source
+$CP navigate/*.php doc_source
+$CP templates/*.php doc_source
+$CP utils/*.php doc_source
+$CP *.php doc_source
+
+doxygen Doxyfile
+
+cd doc/latex
+make pdf
+cd ../../
+
+exit 0
--- /dev/null
+<?php
+/* $Id$ */
+require_once 'config.inc.php';
+require_once 'user_validate.php';
+require_once 'helper.php';
+
+valid_user();
+
+if (! defined($_SESSION['__ROOT__']) && empty($_SESSION['__ROOT__'])) {
+ session_destroy();
+ header('Location: ' . WEB_ROOT . 'error.html');
+ exit;
+}
+
+if (isset($_SESSION['authenticate']) && $_SESSION['authenticate']->validUser()) {
+ $view_style = ($_SESSION['user_settings']->getViewStyle()) ?
+ $_SESSION['user_settings']->getViewStyle() : VIEW_STYLE;
+ $week_start_sunday = ($_SESSION['user_settings']->getStartWeek() !== NULL) ?
+ $_SESSION['user_settings']->getStartWeek() : WEEK_START_SUNDAY;
+ $start_hour = ($_SESSION['user_settings']->getStartHour() != NULL) ?
+ (int) $_SESSION['user_settings']->getStartHour() : START_HOUR;
+ $end_hour = ($_SESSION['user_settings']->getEndHour() != NULL) ?
+ (int) $_SESSION['user_settings']->getEndHour() : END_HOUR;
+}
+
+$pwd = WEB_ROOT;
+if ($pwd[strlen($pwd)-1] == '/')
+ $pwd = substr($pwd, 0, -1);
+
+include TOP_FOLDER.'/templates/view.class.php';
+$pageView = new PageView($pwd, $start_hour, $end_hour, $week_start_sunday);
+
+switch ($view_style) {
+ case 'month':
+ $view = $pageView->createView(PageView::MONTH);
+ $year = date('Y');
+ $month = date('n');
+ $calendar = $view->getView($year, $month);
+ break;
+ case 'week':
+ $view = $pageView->createView(PageView::WEEK);
+ $year = date('Y');
+ $week = $view->get_week_number(time());
+ $calendar = $view->getView($year, $week);
+ break;
+ case 'day':
+ $view = $pageView->createView(PageView::DAY);
+ $year = date('Y');
+ $day = date('z');
+ $calendar = $view->getView($year, $day);
+ break;
+ default: trigger_error(VIEW_STYLE.": ['month', 'week', 'day']", E_USER_ERROR);
+}
+
+include TOP_FOLDER.'/include/header.inc.php';
+include TOP_FOLDER.'/include/menu.inc.php';
+
+//file_put_contents('/tmp/davical.log', "<div id=\"ui\">$calendar</div>", FILE_APPEND);
+print "<div id=\"ui\">$calendar</div>";
+include TOP_FOLDER.'/include/footer.inc.php';
+?>
--- /dev/null
+<?php
+/* $Id$ */
+require_once 'config.inc.php';
+require_once 'user_validate.php';
+require_once 'helper.php';
+
+valid_user();
+
+if (! defined($_SESSION['__ROOT__']) && empty($_SESSION['__ROOT__'])) {
+ session_destroy();
+ header('Location: ' . WEB_ROOT . 'error.html');
+ exit;
+}
+
+if (isset($_SESSION['authenticate']) && $_SESSION['authenticate']->validUser()) {
+ $view_style = ($_SESSION['user_settings']->getViewStyle()) ?
+ $_SESSION['user_settings']->getViewStyle() : VIEW_STYLE;
+ $week_start_sunday = ($_SESSION['user_settings']->getStartWeek() !== NULL) ?
+ $_SESSION['user_settings']->getStartWeek() : WEEK_START_SUNDAY;
+ $start_hour = ($_SESSION['user_settings']->getStartHour() != NULL) ?
+ (int) $_SESSION['user_settings']->getStartHour() : START_HOUR;
+ $end_hour = ($_SESSION['user_settings']->getEndHour() != NULL) ?
+ (int) $_SESSION['user_settings']->getEndHour() : END_HOUR;
+}
+
+$pwd = WEB_ROOT;
+if ($pwd[strlen($pwd)-1] == '/')
+ $pwd = substr($pwd, 0, -1);
+
+include TOP_FOLDER.'/include/header.inc.php';
+include TOP_FOLDER.'/include/menu.inc.php';
+include TOP_FOLDER.'/templates/view.class.php';
+$pageView = new PageView($pwd, $start_hour, $end_hour, $week_start_sunday);
+$day = $pageView->createView(PageView::DAY);
+
+if (isset($_GET['year']) && isset($_GET['day'])) {
+ $calendar = $day->getView($_GET['year'], $_GET['day']);
+}
+else {
+ $calendar = $day->getView();
+}
+print "<div id=\"ui\">$calendar</div>";
+include TOP_FOLDER.'/include/footer.inc.php';
+
+?>
--- /dev/null
+<?php
+/* $Id$ */
+require_once 'config.inc.php';
+require_once 'user_validate.php';
+require_once 'helper.php';
+
+valid_user();
+
+if (! defined($_SESSION['__ROOT__']) && empty($_SESSION['__ROOT__'])) {
+ session_destroy();
+ header('Location: ' . WEB_ROOT . 'error.html');
+ exit;
+}
+
+if (isset($_SESSION['authenticate']) && $_SESSION['authenticate']->validUser()) {
+ $view_style = ($_SESSION['user_settings']->getViewStyle()) ?
+ $_SESSION['user_settings']->getViewStyle() : VIEW_STYLE;
+ $week_start_sunday = ($_SESSION['user_settings']->getStartWeek() !== NULL) ?
+ $_SESSION['user_settings']->getStartWeek() : WEEK_START_SUNDAY;
+ $start_hour = ($_SESSION['user_settings']->getStartHour() != NULL) ?
+ (int) $_SESSION['user_settings']->getStartHour() : START_HOUR;
+ $end_hour = ($_SESSION['user_settings']->getEndHour() != NULL) ?
+ (int) $_SESSION['user_settings']->getEndHour() : END_HOUR;
+}
+
+$pwd = WEB_ROOT;
+if ($pwd[strlen($pwd)-1] == '/')
+ $pwd = substr($pwd, 0, -1);
+
+include TOP_FOLDER.'/include/header.inc.php';
+include TOP_FOLDER.'/include/menu.inc.php';
+include TOP_FOLDER.'/templates/view.class.php';
+$pageView = new PageView($pwd, $start_hour, $end_hour, $week_start_sunday);
+$month = $pageView->createView(PageView::MONTH);
+
+if (isset($_GET['year']) && isset($_GET['month'])) {
+ $calendar = $month->getView($_GET['year'], $_GET['month']);
+}
+else {
+ $calendar = $month->getView();
+}
+print "<div id=\"ui\">$calendar</div>";
+include TOP_FOLDER.'/include/footer.inc.php';
+
+?>
--- /dev/null
+<?php
+/* $Id$ */
+require_once 'config.inc.php';
+require_once 'user_validate.php';
+require_once 'helper.php';
+
+valid_user();
+
+if (! defined($_SESSION['__ROOT__']) && empty($_SESSION['__ROOT__'])) {
+ session_destroy();
+ header('Location: ' . WEB_ROOT . 'error.html');
+ exit;
+}
+
+if (isset($_SESSION['authenticate']) && $_SESSION['authenticate']->validUser()) {
+ $view_style = ($_SESSION['user_settings']->getViewStyle()) ?
+ $_SESSION['user_settings']->getViewStyle() : VIEW_STYLE;
+ $week_start_sunday = ($_SESSION['user_settings']->getStartWeek() !== NULL) ?
+ $_SESSION['user_settings']->getStartWeek() : WEEK_START_SUNDAY;
+ $start_hour = ($_SESSION['user_settings']->getStartHour() != NULL) ?
+ (int) $_SESSION['user_settings']->getStartHour() : START_HOUR;
+ $end_hour = ($_SESSION['user_settings']->getEndHour() != NULL) ?
+ (int) $_SESSION['user_settings']->getEndHour() : END_HOUR;
+}
+
+$pwd = WEB_ROOT;
+if ($pwd[strlen($pwd)-1] == '/')
+ $pwd = substr($pwd, 0, -1);
+
+include TOP_FOLDER.'/include/header.inc.php';
+include TOP_FOLDER.'/include/menu.inc.php';
+include TOP_FOLDER.'/templates/view.class.php';
+$pageView = new PageView($pwd, $start_hour, $end_hour, $week_start_sunday);
+$week = $pageView->createView(PageView::WEEK);
+
+if (isset($_GET['year']) && isset($_GET['week'])) {
+ $calendar = $week->getView($_GET['year'], $_GET['week']);
+}
+else {
+ $calendar = $week->getView();
+}
+print "<div id=\"ui\">$calendar</div>";
+include TOP_FOLDER.'/include/footer.inc.php';
+
+?>
--- /dev/null
+<?php
+/* $Id$ */
+include_once 'view.class.php';
+require_once 'caldavresource.class.php';
+include_once 'dateformat.class.php';
+require_once 'helper.php';
+
+class DayView extends View {
+
+ private $url;
+ private $p_year;
+ private $privious;
+ private $year_and_day;
+ private $n_year;
+ private $next;
+ private $year;
+ private $day;
+ private $range;
+ private $calendar;
+ private $etags = array();
+ private $top = "<table style=\"width: 100%\">
+ <tr>
+ <td style=\"width: 33%; text-align: left;\"><a href=
+ \"__URL__?year=__P_YEAR__&day=__PRIVIOUS__\">
+ <img style=\"border: 0\" src=\"__WEB_ROOT__/pixmaps/left.png\"
+ alt=\"Privious\"/></a></td>
+ <td style=\"width: 33%; font-size: 2.5em; font-weight: bold;
+ text-align: center\">__YEAR_AND_DAY__</td>
+ <td style=\"width: 33%; text-align: right;\">
+ <a href=\"__URL__?year=__N_YEAR__&day=__NEXT__\">
+ <img style=\"border: 0\" src=\"__WEB_ROOT__/pixmaps/right.png\"
+ alt=\"next\"/></a></td>
+ </tr></table>";
+ private $bottom;
+
+ function __construct() {
+ $this->url = parent::$root.'/navigate/show_day.php';
+ $this->calendar = $calendar;
+ $this->range = array();
+ }
+
+ protected function parseDate() {
+ if ($this->year && $this->day >= 0) {
+ $day = $this->day;
+ if ($day < 0 || $day > 365) {
+ $day = date('z');
+ $year = date('Y');
+ }
+ else
+ $year = $this->year;
+ }
+ else {
+ $day = date('z');
+ $year = date('Y');
+ }
+ $now = mktime(0, 0, 0, 1, 1, $year);
+ $this->year_and_day = "$year day ".(date('z', strtotime("+$day days", $now))+1);
+
+ $this->privious = $day - 1;
+ $this->p_year = $year;
+ if ($this->privious < 0) {
+ $this->p_year -= 1;
+ $this->privious = date('z', mktime(0, 0, 0, 12, 31, $this->p_year));
+ }
+ $this->next = $day + 1;
+ $this->n_year = $year;
+ if ($this->next > date('z', mktime(0, 0, 0, 12, 31, $this->year))) {
+ $this->next = 0;
+ $this->n_year += 1;
+ }
+
+ $this->year = $year;
+ $this->day = $day;
+ }
+
+ protected function getHead() {
+ $this->parseDate();
+ $head = str_replace('__URL__', $this->url, $this->top);
+ $head = str_replace('__P_YEAR__', $this->p_year, $head);
+ $head = str_replace('__PRIVIOUS__', $this->privious, $head);
+ $head = str_replace('__WEB_ROOT__', parent::$root, $head);
+ $head = str_replace('__YEAR_AND_DAY__', $this->year_and_day, $head);
+ $head = str_replace('__N_YEAR__', $this->n_year, $head);
+ $head = str_replace('__NEXT__', $this->next, $head);
+ $this->bottom = $head;
+ return $this->applyLegend() . $head;
+ }
+
+ private function getCell($events, $day, $progress, $excluded = FALSE) {
+ $cell = '';
+ //$etags = array();
+ if ($events) {
+ $now = mktime(0, 0, 0, 1, 1, $this->year);
+ $ts = strtotime("+$day days +$progress hours", $now);
+ $ical_start = CaldavRessource::timestamp2ICal($ts, TRUE);
+ $ts = strtotime("+$day days +".($progress+1)." hours", $now);
+ $ical_end = CaldavRessource::timestamp2ICal($ts, TRUE);
+ $dateFormat = new dateFormat();
+ foreach ($events as $etag =>$infos) {
+ foreach ($infos['dates'] as $time) {
+ CaldavRessource::fix_allday_event($time['start'],$time['end']);
+ $time['start'] = $dateFormat->UTC2Client($time['start']);
+ $time['end'] = $dateFormat->UTC2Client($time['end']);
+ if ($excluded) {
+ $ts = strtotime(
+ "+$day days +".parent::$start_hour." hours", $now);
+ $parent_start = CaldavRessource::timestamp2ICal($ts, TRUE);
+ $end = (parent::$end_hour == 24) ? 23 : parent::$end_hour;
+ $ts = strtotime(
+ "+$day days +".$end." hours", $now);
+ $parent_end = CaldavRessource::timestamp2ICal($ts, TRUE);
+ $time_start = (strrchr($time['start'], 'Z')) ?
+ trim($time['start'], "Z") : $time['start'];
+ $time_end = (strrchr($time['end'], 'Z')) ?
+ trim($time['end'], "Z") : $time['end'];
+ $parts = explode("T", $time_end);
+ if (substr($parts[1], 0, 2) == "00") {
+ $parts[1] = "24" . substr($parts[1], 2, 4);
+ $time_end = $parts[0] . "T" . $parts[1];
+ }
+ //print substr($time_end, 0, 2)."b[$parent_start : $parent_end] [$time_start : $time_end]" . CaldavRessource::cmptime(
+ // $parent_end, $time_end) ."<br/>";
+ /*if ((CaldavRessource::cmptime(
+ $parent_start, $time_start) > 0 &&
+ CaldavRessource::cmpdate($parent_start, $time_start) == 0)
+ ||
+ (CaldavRessource::cmptime(
+ $parent_end, $time_end) < 0 &&
+ CaldavRessource::cmpdate($parent_end, $time_end) == 0)) {*/
+ if ((CaldavRessource::cmptime(
+ $parent_start, $time_start) > 0 &&
+ CaldavRessource::cmpdate($parent_start, $time_end) == 0)
+ ||
+ (CaldavRessource::cmptime(
+ $parent_end, $time_end) < 0 &&
+ CaldavRessource::cmpdate($parent_end, $time_start) == 0)) {
+ if (! in_array($etag, $this->etags)) {
+ array_push($this->etags, $etag);
+ $cell = $this->makeEvent($cell, $etag, $infos);
+ //print "$cell<br/>";
+ }
+ }
+ //print "a[$parent_start : $parent_end] [$time_start : $time_end] parent_start:time_start" . CaldavRessource::cmptime(
+ // $parent_start, $time_start) ."<br/>";
+ //print "a[$parent_start : $parent_end] [$time_start : $time_end] parent_end:time_end" . CaldavRessource::cmptime(
+ // $parent_end, $time_end) ."<br/>";
+ }
+ else {
+ //print "$ical_start:$ical_end:{$time['start']}:{$time['end']}<br/>";
+ $s_cmp = CaldavRessource::datecmp($ical_start, $time['start']);
+ $e_cmp = CaldavRessource::datecmp($ical_start, $time['end']);
+ if ($s_cmp >= 0 && $e_cmp < 0) {
+ // if (! in_array($etag, $this->etags)) {
+ $cell = $this->makeEvent($cell, $etag, $infos);
+ //print "$cell";
+ // }
+ }
+ }
+ }
+ }
+ }
+ return ($cell == '') ? ' ' : $cell;
+ }
+
+ public function getView($year = NULL, $day = NULL) {
+ $this->year = $year;
+ $this->day = $day;
+ $calendar = $this->getHead();
+ $calendar .= '<br />';
+ $calendar .= str_replace('__DAY__', $this->dateFromDayInYear(
+ $this->year, $this->day, $head), $this->getViewHead('day'));
+ $now = mktime(0, 0, 0, 1, 1, $this->year);
+ $this->range['start'] = strtotime("+".($this->day - 1)." days", $now);
+ $this->range['end'] = strtotime("+".$this->day." days", $now);
+ $events = $this->getEvents($this->range);
+ $calendar .= "<tr><td class=\"time\">Excluded</td>\n";
+ $cell = $this->getCell($events, $this->day, 0, TRUE);
+ if ($this->day == date('z')) {
+ $calendar .= "<td class=\"today\">$cell</td>\n";
+ }
+ else
+ $calendar .= "<td>$cell</td>\n";
+ $calendar .= '</tr>';
+ for ($i = parent::$start_hour; $i < parent::$end_hour; $i++) {
+ $s_time = ($i < 10) ? "0$i" : $i;
+ $e_time = ($i < 9) ? '0'.($i + 1) : ($i + 1);
+ $calendar .= "<tr><td class=\"time\">$s_time - $e_time</td>\n";
+ $cell = $this->getCell($events, $this->day, $i);
+ if ($this->day == date('z')) {
+ $calendar .= "<td class=\"today\">$cell</td>\n";
+ }
+ else
+ $calendar .= "<td>$cell</td>\n";
+ $calendar .= '</tr>';
+ }
+ $calendar .= '</table></div>';
+ $calendar .= '<br />';
+ $calendar .= $this->bottom;
+ return $calendar;
+ }
+
+}
--- /dev/null
+<?php
+/* $Id$ */
+include_once 'view.class.php';
+require_once 'helper.php';
+
+class MonthView extends View {
+
+ private $view;
+ private $url;
+ private $p_year;
+ private $privious;
+ private $year_and_month;
+ private $n_year;
+ private $next;
+ private $year;
+ private $month;
+ private $range;
+ private $calendar;
+ private $top = "<table style=\"width: 100%\">
+ <tr>
+ <td style=\"width: 33%; text-align: left;\"><a href=
+ \"__URL__?year=__P_YEAR__&month=__PRIVIOUS__\">
+ <img style=\"border: 0\" src=\"__WEB_ROOT__/pixmaps/left.png\"
+ alt=\"Privious\"/></a></td><td style=\"width: 33%;
+ font-size: 2.5em; font-weight: bold;text-align: center\">
+ __YEAR_AND_MONTH__</td><td style=\"width: 33%;
+ text-align: right;\"><a href=
+ \"__URL__?year=__N_YEAR__&month=__NEXT__\">
+ <img style=\"border: 0\" src=\"__WEB_ROOT__/pixmaps/right.png\"
+ alt=\"next\"/></a></td></tr></table>";
+ private $bottom;
+
+ function __construct(Calendar $calendar = NULL) {
+ $this->url = parent::$root.'/navigate/show_month.php';
+ $this->calendar = $calendar;
+ $this->range = array();
+ }
+
+ protected function parseDate() {
+ if ($this->year && $this->month) {
+ $month = $this->month;
+ if ($month < 0 || $month > 12) {
+ $month = date('n');
+ }
+ $year = $this->year;
+ }
+ else {
+ $month = date('n');
+ $year = date('Y');
+ }
+
+ $this->privious = $month - 1;
+ $this->p_year = $year;
+ if ($this->privious < 1) {
+ $this->privious = 12;
+ $this->p_year -= 1;
+ }
+ $this->next = $month + 1;
+ $this->n_year = $year;
+ if ($this->next > 12) {
+ $this->next = 1;
+ $this->n_year += 1;
+ }
+ $this->year_and_month = date('F Y', mktime(0,0,0,$month,28,$year));
+ $this->year = $year;
+ $this->month = $month;
+ }
+
+ protected function getHead() {
+ $this->parseDate();
+ $head = str_replace('__URL__', $this->url, $this->top);
+ $head = str_replace('__P_YEAR__', $this->p_year, $head);
+ $head = str_replace('__PRIVIOUS__', $this->privious, $head);
+ $head = str_replace('__WEB_ROOT__', parent::$root, $head);
+ $head = str_replace('__YEAR_AND_MONTH__', $this->year_and_month, $head);
+ $head = str_replace('__N_YEAR__', $this->n_year, $head);
+ $head = str_replace('__NEXT__', $this->next, $head);
+ $this->bottom = $head;
+ return $this->applyLegend() . $head;
+ }
+
+ private function getCell($events, $day) {
+ $ts = gmmktime(0,0,0,$this->month,$day,$this->year);
+ //print date('c', $ts).'<br/>';
+ $icalDate = CaldavRessource::timestamp2ICal($ts, FALSE);
+ $cell = '';
+ if ($events) {
+ $dateFormat = new dateFormat();
+ foreach ($events as $etag =>$infos) {
+ foreach ($infos['dates'] as $time) {
+ //if ('20100619T144500' == $time['start'])
+ //print "$icalDate:{$time['start']}:{$time['end']}<br/>";
+ $time['start'] = $dateFormat->UTC2Client($time['start']);
+ $time['end'] = $dateFormat->UTC2Client($time['end']);
+ $s_cmp = CaldavRessource::cmpdate(
+ $icalDate, $time['start']);
+ $e_cmp = CaldavRessource::cmpdate(
+ $icalDate, $time['end']);
+ if (($s_cmp >= 0 && $e_cmp <= 0) ||
+ ($s_cmp == 0 && $e_cmp > 0) ||
+ ($s_cmp > 0 && $e_cmp == 0)) {
+ $cell = $this->makeEvent($cell, $etag, $infos);
+ //print "$cell<br/>";
+ }
+ }
+ }
+ }
+ return ($cell == '') ? ' ' : $cell;
+ }
+
+ public function getView($year = NULL, $month = NULL) {
+ $this->year = $year;
+ $this->month = $month;
+ $calendar = $this->getHead();
+ $calendar .= '<br />';
+ $calendar .= $this->getViewHead('month');
+ $days = date('t', gmmktime(0,0,0,$this->month,1,$this->year));
+ $this->range['start'] = gmmktime(0,0,0,$this->month,1,$this->year);
+ $this->range['end'] = gmmktime(23,59,59,$this->month,$days,$this->year);
+ $adjust = (parent::$start_sunday) ? 0 : 1;
+ $day = 1;
+ $start = $this->getStartDay($this->year, $this->month);
+ if ($start == 0 && ! parent::$start_sunday) {
+ switch ($days) {
+ case 28:
+ case 29: $stop = 5; break;
+ default: $stop = 6;
+ }
+ }
+ else if ($start == 1 && ! parent::$start_sunday) {
+ switch ($days) {
+ case 28: $stop = 4; break;
+ default: $stop = 5;
+ }
+ }
+ else if ($start == 0 && parent::$start_sunday) {
+ switch ($days) {
+ case 28: $stop = 4; break;
+ default: $stop = 5;
+ }
+ }
+ else if ($start > 4 && parent::$start_sunday) {
+ if ($days > 29)
+ $stop = 6;
+ else
+ $stop = 5;
+ }
+ else $stop = 5;
+ $events = $this->getEvents($this->range);
+ for ($i = 0; $i < $stop; $i++) {
+ $week = $this->get_week_number(
+ mktime(0,0,0,$this->month,($i * 7)+1,$this->year));
+ $calendar .= "<tr><td class=\"weeknum\">$week</td>";
+ if ($i == 0) {
+ if ($adjust) {
+ if ($start > 0) {
+ for ($notused = 0; $notused < $start - 1; $notused++)
+ $calendar .= "<td class=\"notused\"> </td>";
+ for ($notused = 7 - $notused; $notused > 0; $notused--, $day++) {
+ $cell = $this->getCell($events, $day);
+ if ($this->isToDay($this->year, $this->month, $day))
+ $calendar .= "<td class=\"today\">$cell<span class=\"date\">$day</span></td>";
+ else
+ $calendar .= "<td>$cell<span class=\"date\">$day</span></td>";
+ }
+ }
+ else {
+ for ($notused = 0; $notused < 6; $notused++)
+ $calendar .= "<td class=\"notused\"> </td>";
+ $cell = $this->getCell($events, $day);
+ if ($this->isToDay($this->year, $this->month, $day))
+ $calendar .= "<td class=\"today\">$cell<span class=\"date\">$day</span></td>";
+ else
+ $calendar .= "<td>$cell<span class=\"date\">$day</span></td>";
+ $day++;
+ }
+ }
+ else {
+ for ($notused = $start; $notused > 0; $notused--)
+ $calendar .= "<td class=\"notused\"></td>";
+ for ($notused = 7 - $start; $notused > 0; $notused--, $day++) {
+ $cell = $this->getCell($events, $day);
+ if ($this->isToDay($this->year, $this->month, $day))
+ $calendar .= "<td class=\"today\">$cell<span class=\"date\">$day</span></td>";
+ else
+ $calendar .= "<td>$cell<span class=\"date\">$day</span></td>";
+ }
+ }
+ }
+ else {
+ $j = $adjust + ($i * 7);
+ for (; $j < ($i * 7) + (7 + $adjust); $j++, $day++) {
+ if ($day > $days)
+ break;
+ $cell = $this->getCell($events, $day);
+ if ($this->isToDay($this->year, $this->month, $day))
+ $calendar .= "<td class=\"today\">$cell<span class=\"date\">$day</span></td>";
+ else
+ $calendar .= "<td>$cell<span class=\"date\">$day</span></td>";
+ }
+ while ($j < ($i * 7) + (7 + $adjust)) {
+ $calendar .= "<td class=\"notused\"> </td>";
+ $j++;
+ }
+ }
+ $calendar .= "</tr>\n";
+ }
+ $calendar .= '</table></div>';
+ $calendar .= '<br />';
+ $calendar .= $this->bottom;
+ return $calendar;
+ }
+
+}
--- /dev/null
+<?php
+/* $Id$ */
+
+require_once 'user_validate.php';
+
+valid_user();
+
+include_once 'config.inc.php';
+require_once 'helper.php';
+
+include_once 'month_view.class.php';
+include_once 'week_view.class.php';
+include_once 'day_view.class.php';
+include_once 'calendar.class.php';
+
+abstract class View {
+ protected static $start_sunday;
+ protected static $root;
+ protected static $start_hour;
+ protected static $end_hour;
+ private $heading = "<div id=\"events\"><table><tr>";
+ private $view_head_sunday = "
+ <th class=\"event\">Sunday</th>
+ <th class=\"event\">Monday</th>
+ <th class=\"event\">Tuesday</th>
+ <th class=\"event\">Wednedsday</th>
+ <th class=\"event\">Thursday</th>
+ <th class=\"event\">Friday</th>
+ <th class=\"event\">Saturday</th>
+ </tr>";
+ private $view_head_monday = "
+ <th class=\"event\">Monday</th>
+ <th class=\"event\">Tuesday</th>
+ <th class=\"event\">Wednedsday</th>
+ <th class=\"event\">Thursday</th>
+ <th class=\"event\">Friday</th>
+ <th class=\"event\">Saturday</th>
+ <th class=\"event\">Sunday</th>
+ </tr>";
+ private $view_head_day = "
+ <th class=\"day_event\">__DAY__</th>
+ </tr>";
+
+ function __construct($root, $start_hour, $end_hour, $start_sunday = FALSE) {
+ self::$start_sunday = $start_sunday;
+ self::$root = $root;
+ self::$start_hour = $start_hour;
+ self::$end_hour = $end_hour;
+ }
+
+ protected function applyLegend() {
+ $calenders = $_SESSION['user_settings']->getCalendars();
+ $legend = '<p style="text-align: center">';
+ foreach ($calenders as $calender) {
+ $legend .= '[<span style="background: ' . $calender->color .
+ '"> </span>:' . $calender->name . ']';
+ }
+ $legend .= '</p>';
+ $legend .= <<<_HELP
+ <p style="text-align: center">
+ Events outside configured range is only displayed
+ when Day or Week view is active
+ </p>
+_HELP;
+ return $legend;
+ }
+
+ protected function getViewHead($kindOf) {
+ switch ($kindOf) {
+ case 'month':
+ $return = $this->heading.'<th>Week</th>';
+ if (self::$start_sunday)
+ $return .= $this->view_head_sunday;
+ else
+ $return .= $this->view_head_monday;
+ return $return;
+ break;
+ case 'week':
+ if (self::$start_sunday) {
+ $head = str_replace('</th>', '<br/>__DATE__</th>',
+ $this->view_head_sunday);
+ }
+ else {
+ $head = str_replace('</th>', '<br/>__DATE__</th>',
+ $this->view_head_monday);
+ }
+ $head = '<th>Time</th>' . $head;
+ return $this->heading . $head;
+ break;
+ case 'day':
+ $return = $this->heading . '<th>Time</th>';
+ return $return . $this->view_head_day;
+ break;
+ default: trigger_error("$kindOf: ['month', 'week', 'day']", E_USER_ERROR);
+ }
+ }
+
+ /*
+ * Function get_week_number which returns the week number of the
+ * given date according to ISO 8601-1988
+ * http://www.php.happycodings.com/Date_Time/code22.html
+ */
+ protected function is_leap_year($year) {
+ if ((($year % 4) == 0 and ($year % 100)!=0) or ($year % 400)==0) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+
+ /* define ISO_WEEK_START_WDAY 1 // Monday
+ * define ISO_WEEK1_WDAY 4 // Thursday
+ * define YDAY_MINIMUM (-366)
+ * int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
+ * return (yday - (yday - wday + ISO_WEEK1_WDAY +
+ * big_enough_multiple_of_7) % 7 + ISO_WEEK1_WDAY -
+ * ISO_WEEK_START_WDAY);
+ */
+ private function iso_week_days($yday, $wday) {
+ return $yday - (($yday - $wday + 382) % 7) + 3;
+ }
+
+ protected function get_week_number($timestamp) {
+ $d = getdate($timestamp);
+ $days = $this->iso_week_days($d[ "yday"], $d[ "wday"]);
+
+ if ($days < 0) {
+ $d[ "yday"] += 365 + $this->is_leap_year(--$d[ "year"]);
+ $days = $this->iso_week_days($d[ "yday"], $d[ "wday"]);
+ } else {
+ $d[ "yday"] -= 365 + $this->is_leap_year($d[ "year"]);
+ $d2 = $this->iso_week_days($d[ "yday"], $d[ "wday"]);
+ if (0 <= $d2) {
+ /* $d["year"]++; */
+ $days = $d2;
+ }
+ }
+ $adjust = 1;
+ $day = date('w');
+ if ($_SESSION['user_settings']->getStartWeek() === true && $day == 0)
+ $adjust = 2;
+ return (int)($days / 7) + $adjust;
+ }
+
+ protected function getStartDay($year, $month) {
+ /* date('w') returns start day counting from Sunday */
+ $start = date('w', mktime(0,0,0,$month,1,$year));
+ return $start;
+ }
+
+ protected function isToDay($year, $month, $day) {
+ return ($year == date('Y') && $month == date('n') && $day == date('j'));
+ }
+
+ protected function lastDayInWeek($year, $week) {
+ $weekEndDay = 0; // 0 = Sunday.
+ $dayOfYear = 4 + (($week - 1) * 7);
+ $date = mktime(0, 0, 0, 1, $dayOfYear, $year);
+ // Find the last day of this week.
+ $dayOfWeek = date("w", $date);
+ $daysToAdd = ($weekEndDay - $dayOfWeek + 7) % 7;
+ $date += $daysToAdd * 24*60*60;
+ return (self::$start_sunday) ? $date - (24*60*60) : $date;
+ }
+
+ protected function dateFromDayInYear($year, $day) {
+ $now = mktime(0, 0, 0, 1, 1, $year);
+ return date('l, j F', strtotime("+$day days", $now));
+ }
+
+ protected function makeSummary($infos) {
+ $summary = 'Title: ';
+ $summary .= (isset($infos['summary']) && ! empty($infos['summary'])) ?
+ $infos['summary'] : 'Untitled';
+ $summary .= "\n";
+ $summary .= 'Date: ';
+ $start = strtotime($infos['dates'][0]['start']);
+ $date = date("D j M Y", $start);
+ $end = strtotime($infos['dates'][0]['end']);
+ $summary .= $date . ' ' . date("G:i", $start) . ' - ' . date("G:i", $end);
+
+ return $summary;
+ }
+
+ protected function makeEvent($cell, $uri, $infos) {
+ $history = $_SERVER['PHP_SELF'];
+ $summary = (isset($infos['summary']) && ! empty($infos['summary'])) ?
+ $infos['summary'] : 'Untitled';
+ $history .= (empty($_SERVER['QUERY_STRING'])) ? '' : '?'.$_SERVER['QUERY_STRING'];
+ //$url = WEB_ROOT . 'events/edit_event.php?etag='. $uri;
+ $url = 'etag='. $uri.'&referer='.$history.'&cal='.$infos['cal'];
+ $url = WEB_ROOT . 'events/edit_event.php?' . urlencode($url);
+ $c = '<span style="background: '.$infos['color'].';color: #E6E6E6;
+ font-weigth: bold;"><a href="'.$url.
+ '" title="'.$this->makeSummary($infos).'">'.$summary.'</a></span>';
+ return ($cell != '') ? "$cell<br/>$c" : $c;
+ }
+
+ protected function getEvents($range) {
+ $list = array();
+ $all_events = array();
+
+ $cals = $_SESSION['user_settings']->getCalendars();
+ //file_put_contents('/tmp/davical.log',
+ // __FILE__ . ": " . var_export($cals, TRUE), FILE_APPEND);
+ if (! $cals)
+ return NULL;
+ $start = CaldavRessource::timestamp2ICal($range['start'], TRUE);
+ if ($_SESSION['user_settings']->getStartWeek() === FALSE) {
+ $datetime = explode('T', $start);
+ //print_r($datetime);
+ $day = $datetime[0] + 1;
+ $start = $day.'T'.$datetime[1].'Z';
+ }
+ $end = CaldavRessource::timestamp2ICal($range['end'], TRUE);
+ $datetime = explode('T', $end);
+ $end = $datetime[0].'T'.'235959Z';
+ //print "$start:$end<br/>";
+ foreach ($cals as $cal) {
+ //var_dump($cal);
+ $conf = implode_cal(decode($cal->config));
+ //var_dump($conf);
+ $events = new Calendar($conf['url'], $conf['uid'], $conf['pwd']);
+ //print_r($events);
+ $events->getComponents($start, $end);
+ //print_r($events);
+ $all_events[$cal->name] = $events;
+ foreach ($events as $event) {
+ $dates = $event->getActiveDates();
+ //file_put_contents('/tmp/davical.log',
+ //__FILE__ . ": " . var_export($dates, TRUE), FILE_APPEND);
+ //var_dump($dates);
+ $comp = $event->getBaseComponent();
+ //print_r($comp);
+ $summary = $comp->GetPValue('SUMMARY');
+ $item = array();
+ $dtend = explode('T', $comp->GetPValue('DTEND'));
+ //print_r($comp->GetPValue('DTEND'));
+ //print "<br/>";
+ //print_r($dtend);
+ //print "<br/>";
+ //print_r($dates);
+ //print "<br/>--------------------------<br/>";
+ if (count($dates) > 0) {
+ foreach ($dates as $date) {
+ //print_r($date);
+ //print "<br/>--------------------------<br/>";
+ //$datetime = explode('T', $date);
+ //print_r($dtend);
+ //print "<br/>--------------------------<br/>";
+ //if (count($datetime) > 1) {
+ if (count($dtend) > 1) {
+ //if (count($dtend) < 2)
+ // array_push($dtend, '235959');
+ //$endtime = $datetime[0].'T'.$dtend[1];
+ $endtime = $dtend[0].'T'.$dtend[1];
+ }
+ else {
+ //$endtime = $datetime[0];
+ $day = strtotime($dtend[0]);
+ $day = strtotime("-1 day", $day);
+ $endtime = date("Ymd\T235959", $day);
+ //$endtime = $endtime."T235959";
+ //$endtime = $dtend[0]."T000000";
+ }
+ //print "$date:$endtime<br/>";
+ array_push($item, array('start' => $date, 'end' => $endtime));
+ }
+ $list[$event->getEtag()] = array('color' => $cal->color,
+ 'summary' => $summary, 'dates' => $item, 'cal' => $cal->name);
+ }
+ }
+ }
+ $_SESSION['all_events'] = $all_events;
+ //var_dump($list);
+ return $list;
+ }
+
+ protected abstract function parseDate();
+ protected abstract function getHead();
+ public abstract function getView($year = NULL, $other = NULL);
+}
+
+class PageView extends View {
+ const DAY = 0;
+ const WEEK = 1;
+ const MONTH = 2;
+
+ function __construct($root, $start_hour, $end_hour, $start_sunday = FALSE) {
+ parent::__construct($root, $start_hour, $end_hour, $start_sunday);
+ }
+
+ public function createView($view) {
+ switch ($view) {
+ case (self::DAY): return new DayView(); break;
+ case (self::WEEK): return new WeekView(); break;
+ case (self::MONTH): return new MonthView(); break;
+ default: trigger_error("$view: ['MONTH', 'WEEK', 'DAY']", E_USER_ERROR);
+ }
+ }
+
+ protected function parseDate() {
+ throw new Exception("Function can only be called from a subclass");
+ }
+
+ protected function getHead() {
+ throw new Exception("Function can only be called from a subclass");
+ }
+
+ public function getView($year = NULL, $other = NULL) {
+ throw new Exception("Function can only be called from a subclass");
+ }
+}
--- /dev/null
+<?php
+/* $Id$ */
+include_once 'view.class.php';
+require_once 'caldavresource.class.php';
+include_once 'dateformat.class.php';
+require_once 'helper.php';
+
+class WeekView extends View {
+
+ private $url;
+ private $p_year;
+ private $privious;
+ private $year_and_week;
+ private $n_year;
+ private $next;
+ private $year;
+ private $week;
+ private $range;
+ private $calendar;
+ private $etags = array();
+ private $top = "<table style=\"width: 100%\">
+ <tr>
+ <td style=\"width: 33%; text-align: left;\"><a href=
+ \"__URL__?year=__P_YEAR__&week=__PRIVIOUS__\">
+ <img style=\"border: 0\" src=\"__WEB_ROOT__/pixmaps/left.png\"
+ alt=\"Privious\"/></a></td>
+ <td style=\"width: 33%; font-size: 2.5em; font-weight: bold;
+ text-align: center\">__YEAR_AND_WEEK__</td>
+ <td style=\"width: 33%; text-align: right;\">
+ <a href=\"__URL__?year=__N_YEAR__&week=__NEXT__\">
+ <img style=\"border: 0\" src=\"__WEB_ROOT__/pixmaps/right.png\"
+ alt=\"next\"/></a></td>
+ </tr></table>";
+ private $bottom;
+
+ function __construct(Calendar $calendar = NULL) {
+ $this->url = parent::$root.'/navigate/show_week.php';
+ $this->calendar = $calendar;
+ $this->range = array();
+ }
+
+ protected function parseDate() {
+ if ($this->year && $this->week) {
+ $week = $this->week;
+ if ($week < 0 || $week > 53) {
+ $week = $this->get_week_number(time());
+ }
+ $year = $this->year;
+ }
+ else {
+ $week = $this->get_week_number(time());
+ $year = date('Y');
+ }
+ $this->privious = $week - 1;
+ $this->p_year = $year;
+ if ($this->privious == 0) {
+ $this->p_year -= 1;
+ if (date("w", strtotime($this->p_year."/12/31")) > 3)
+ $this->privious = 53;
+ else
+ $this->privious = 52;
+ }
+ $this->next = $week + 1;
+ $this->n_year = $year;
+ if ($this->next > 51) {
+ if ($this->get_week_number(strtotime("$year/12/31")) == 1 ||
+ $this->next > 53) {
+ $this->next = 1;
+ $this->n_year += 1;
+ }
+ }
+
+ $this->year_and_week = "$year Week $week";
+ $this->year = $year;
+ $this->week = $week;
+ }
+
+ protected function getHead() {
+ $this->parseDate();
+ $head = str_replace('__URL__', $this->url, $this->top);
+ $head = str_replace('__P_YEAR__', $this->p_year, $head);
+ $head = str_replace('__PRIVIOUS__', $this->privious, $head);
+ $head = str_replace('__WEB_ROOT__', parent::$root, $head);
+ $head = str_replace('__YEAR_AND_WEEK__', $this->year_and_week, $head);
+ $head = str_replace('__N_YEAR__', $this->n_year, $head);
+ $head = str_replace('__NEXT__', $this->next, $head);
+ $this->bottom = $head;
+ return $this->applyLegend() . $head;
+ }
+
+ private function addDates($head) {
+ $timestamp = $this->lastDayInWeek($this->year, $this->week);
+ $i = 7;
+ $this->range['end'] = $timestamp;
+ do {
+ $date = date('Y/m/d', $timestamp);
+ $timestamp = strtotime('-1 day', $timestamp);
+ $head = substr_replace($head, $date, strrpos($head, '__DATE__'), 8);
+ $i--;
+ } while ($i > 0);
+ $this->range['start'] = $timestamp;
+ return $head;
+ }
+
+ private function getCell($events, $day, $progress, $excluded = FALSE) {
+ $cell = '';
+ //$etags = array();
+ if ($events) {
+ //print var_export($events,true)."<br/>";
+ $dateFormat = new dateFormat();
+ foreach ($events as $etag =>$infos) {
+ foreach ($infos['dates'] as $time) {
+ //print "{$time['start']}:{$time['end']}<br/>";
+ //print $time['end']."<br/>";
+ CaldavRessource::fix_allday_event($time['start'],$time['end']);
+ //print $time['end']."<br/>";
+ //print "{$time['start']}:{$time['end']}<br/>";
+ $time['start'] = $dateFormat->UTC2Client($time['start']);
+ $time['end'] = $dateFormat->UTC2Client($time['end']);
+ //print $time['end']."<br/>";
+ if ($excluded) {
+ $ts = strtotime("+$day day +".parent::$start_hour." hour",
+ $this->range['start']);
+ $ical_start = CaldavRessource::timestamp2ICal($ts);
+ //print parent::$end_hour;
+ $end = (parent::$end_hour == 24) ? 23 : parent::$end_hour;
+ $ts = strtotime("+$day day +".$end." hour",
+ $this->range['start']);
+ $ical_end = CaldavRessource::timestamp2ICal($ts);
+ $time_start = (strrchr($time['start'], 'Z')) ?
+ trim($time['start'], "Z") : $time['start'];
+ $time_end = (strrchr($time['end'], 'Z')) ?
+ trim($time['end'], "Z") : $time['end'];
+ //print $time_end."\n";
+ $parts = explode("T", $time_end);
+ if (substr($parts[1], 0, 2) == "00") {
+ $parts[1] = "24" . substr($parts[1], 2, 4);
+ $time_end = $parts[0] . "T" . $parts[1];
+ }
+ //print "b[$time_start : $time_end]<br/>";
+ //print "a[$ical_start : $ical_end] [$time_start : $time_end]<br/>";
+ if ((CaldavRessource::cmptime(
+ $ical_start, $time_start) > 0 &&
+ CaldavRessource::cmpdate($ical_start, $time_end) == 0)
+ ||
+ (CaldavRessource::cmptime(
+ $ical_end, $time_end) < 0 &&
+ CaldavRessource::cmpdate($ical_end, $time_start) == 0)) {
+ //print "b[$ical_start : $ical_end] [$time_start : $time_end]<br/>";
+ if (! in_array($etag, $this->etags)) {
+ array_push($this->etags, $etag);
+ $cell = $this->makeEvent($cell, $etag, $infos);
+ //print "$cell<br/>";
+ //print "exc: cell: $etag<br/>";
+ //print "exc: ".var_export($this->etags, true)."<br/>";
+ }
+ }
+ }
+ else {
+ $ts = strtotime("+$day day +$progress hour",
+ $this->range['start']);
+ $icalDate = CaldavRessource::timestamp2ICal($ts, TRUE);
+ //print "$icalDate {$time['start']}:{$time['end']}<br/>";
+ $s_cmp = CaldavRessource::datecmp($icalDate, $time['start']);
+ $e_cmp = CaldavRessource::datecmp($icalDate, $time['end']);
+ //print "$s_cmp:$e_cmp<br/>";
+ if ($s_cmp >= 0 && $e_cmp < 0) {
+ //if (! in_array($etag, $this->etags)) {
+ $cell = $this->makeEvent($cell, $etag, $infos);
+ //print "$cell<br/>";
+ //print "inc: cell: $etag<br/>";
+ //print "inc: ".var_export($this->etags, true)."<br/>";
+ //}
+ }
+ }
+ }
+ }
+ }
+ return ($cell == '') ? ' ' : $cell;
+ }
+
+ public function getView($year = NULL, $week = NULL) {
+ $this->year = $year;
+ $this->week = $week;
+ $calendar = $this->getHead();
+ $calendar .= '<br />';
+ $calendar .= $this->addDates($this->getViewHead('week'));
+ if ($this->get_week_number(time()) == $week || $week == NULL) {
+ $day = date('w');
+ if ($_SESSION['user_settings']->getStartWeek() === FALSE) {
+ if ($day == 0)
+ $day = 6;
+ else
+ $day--;
+ }
+ }
+ else
+ $day = -1;
+ $events = $this->getEvents($this->range);
+ //var_dump($events);
+ //var_dump($_SESSION['all_events']);
+ $calendar .= "<tr><td class=\"time\">Excluded</td>\n";
+ $excluded = array();
+ for ($d = 0; $d < 7; $d++) {
+ $cell = $this->getCell($events, $d + 1, 0, TRUE);
+ if ($d == $day && ($year == date('Y') || $year == NULL)) {
+ $calendar .= "<td class=\"today\">$cell</td>\n";
+ }
+ else
+ $calendar .= "<td>$cell</td>\n";
+ //print_r($cell);
+ //if ($d < 6) {
+ // print "clean etags<br/>";
+ // $this->etags = array();
+ //}
+ array_push($excluded, $this->etags);
+ $this->etags = array();
+ }
+ $calendar .= '</tr>';
+ for ($i = parent::$start_hour; $i < parent::$end_hour; $i++) {
+ $s_time = ($i < 10) ? "0$i" : $i;
+ $e_time = ($i < 9) ? '0'.($i + 1) : ($i + 1);
+ $calendar .= "<tr><td class=\"time\">$s_time - $e_time</td>\n";
+ for ($d = 0; $d < 7; $d++) {
+ $this->etags = $excluded[$d];
+ $progress = $i;
+ $cell = $this->getCell($events, $d + 1, $progress);
+ //print_r($cell);
+ if ($d == $day && ($year == date('Y') || $year == NULL)) {
+ $calendar .= "<td class=\"today\">$cell</td>\n";
+ }
+ else
+ $calendar .= "<td>$cell</td>\n";
+ }
+ $calendar .= '</tr>';
+ }
+ $calendar .= '</table></div>';
+ $calendar .= '<br />';
+ $calendar .= $this->bottom;
+ //file_put_contents('/tmp/davical.log', $calendar);
+ return $calendar;
+ }
+
+ function get_week_number($timestamp) {
+ return parent::get_week_number($timestamp);
+ }
+}
--- /dev/null
+<?php
+/* $Id$ */
+include_once 'config.inc.php';
+
+$page = <<<__HTML
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+ <head>
+ <title>Web Calendar</title>
+ <link rel="stylesheet" type="text/css" href="css/top_level.css" />
+ <link rel="shortcut icon" href="pixmaps/favicon.ico" />
+ </head>
+ <body>
+ <div id="error_msg">
+ <h1 style="text-align: center">Cannot create user account</h1>
+ <p style="text-align: center">
+ A user with your username already exists.<br/>
+ You should contact your system administrator with this message
+ and inform him or her of your username
+ </p>
+ </div>
+ </body>
+</html>
+__HTML;
+
+echo $page;
+?>
\ No newline at end of file
--- /dev/null
+<?php
+/* $Id$ */
+ require_once 'config.inc.php';
+ require_once 'user_settings.inc.php';
+ require_once 'helper.php';
+
+ function valid_user() {
+ if (! isset($_SESSION['authenticate']) ||
+ ! is_object($_SESSION['authenticate'])) {
+ header('Location: ' . WEB_ROOT . 'login.php');
+ exit();
+ }
+
+ $auth = $_SESSION['authenticate'];
+ if (! $auth->validUser()) {
+ header('Location: ' . WEB_ROOT . 'login.php');
+ exit();
+ }
+ }
+
+ function has_admin_role() {
+ if (! isset($_SESSION['user_settings']) ||
+ ! is_object($_SESSION['user_settings'])) {
+ return false;
+ }
+ return ($_SESSION['user_settings']->getRole() == 0);
+ }
+
--- /dev/null
+<?php
+/* $Id$ */
+require_once 'config.inc.php';
+require_once 'persistens.php';
+require_once 'helper.php';
+
+class Authenticate {
+
+ private $valid_user;
+ private $settings;
+ private $db;
+ private $secKey;
+ private $pubKey;
+ private $ldap;
+
+ public function __construct($db) {
+ $this->valid_user = FALSE;
+ $this->settings = array();
+ $this->db = $db;
+ $this->secKey = NULL;
+ $this->pubKey = NULL;
+ $this->ldap = NULL;
+ }
+
+ public function login($uid, $pwd) {
+ $con = Persistens::getInstance($this->db);
+ if ($this->useLDAP() && $uid != 'admin') {
+ if ($this->authLDAP($uid, $pwd)) {
+ // check user exists. Internal password sha1 hash of uid
+ $pwd = sha1($uid);
+ //echo "$uid:$pwd<br/>";
+ //exit;
+ $settings = array_change_key_case(
+ $con->authenticate($uid, $pwd));
+ //print_r($settings);
+ //exit;
+ if (is_array($settings) && count($settings) > 0) {
+ // user found
+ $this->valid_user = TRUE;
+ }
+ else if (is_array($settings) && count($settings) == 0) {
+ // User not found
+ if ($con->getRole($uid)) {
+ // A user with this uid exists. We cannot create
+ $this->valid_user = FALSE;
+ if (session_id())
+ session_destroy();
+ header('Location: ' . WEB_ROOT . 'user_exist_error.php');
+ exit;
+ }
+ else {
+ // User does not exist so create a normal user
+ $data = create_user_data($uid, $pwd, 2);
+ if ($con->newUser($data) === FALSE) {
+ $this->valid_user = FALSE;
+ if (session_id())
+ session_destroy();
+ header('Location: ' . WEB_ROOT . 'error.html');
+ exit;
+ }
+ $settings = array_change_key_case(
+ $con->authenticate($uid, $pwd));
+ if (count($settings) == 0) {
+ $this->valid_user = FALSE;
+ }
+ else {
+ $this->valid_user = TRUE;
+ }
+ }
+ }
+ else {
+ $this->valid_user = FALSE;
+ if (session_id())
+ session_destroy();
+ header('Location: ' . WEB_ROOT . 'error.html');
+ exit;
+ }
+ }
+ else {
+ $this->valid_user = FALSE;
+ }
+ }
+ else {
+ $settings = array_change_key_case(
+ $con->authenticate($uid, $pwd));
+ if (count($settings) == 0) {
+ $this->valid_user = FALSE;
+ }
+ else {
+ $this->valid_user = TRUE;
+ }
+ }
+ if ($this->valid_user == TRUE) {
+ $setting = array();
+ $this->settings = array();
+ foreach ($settings as $row) {
+ $this->secKey = $row['seckey'];
+ $this->pubKey = $row['pubkey'];
+ foreach ($row as $key => $val) {
+ if ($key != 'seckey' || $key != 'pubkey')
+ $setting[$key] = $val;
+ }
+ array_push($this->settings, $setting);
+ }
+ }
+ }
+
+ public function logout() {
+ $this->valid_user = false;
+ $this->key = NULL;
+ }
+
+ public function validUser() {
+ return $this->valid_user;
+ }
+
+ public function getSettings() {
+ return $this->settings;
+ }
+
+ public function getSecretKey() {
+ return $this->secKey;
+ }
+
+ public function getPublicKey() {
+ return $this->pubKey;
+ }
+
+ private function useLDAP() {
+ $con = Persistens::getInstance($this->db);
+ $version = $con->getVersion();
+ $version = string2int($version['version']);
+ //print_r($version);
+ if ($version < 175) {
+ // no LDAP before 0.7.5
+ return FALSE;
+ }
+ $this->ldap = $con->getLdapConfig();
+ if (! is_array($this->ldap) && $this->ldap) {
+ $this->ldap = NULL;
+ if (session_id())
+ session_destroy();
+ header('Location: ' . WEB_ROOT . 'error.html');
+ exit;
+ }
+
+ return ($this->ldap && $this->ldap['enable'] !== 0);
+ }
+
+ private function authLDAP($uid, $pwd) {
+ $res = false;
+ $ver = 3;
+
+ // ldap_bind always accepts login if password is empty since and
+ // empty password will be considered a try to make an anonymous login
+ if ($this->ldap && $uid && $pwd && !empty($pwd)) {
+ $dns = $this->ldap['dns'];
+ $dn = $this->ldap['user_attr'] . "=$uid," . $this->ldap['base_dn'];
+ $lc = ldap_connect($dns);
+ if ($lc) {
+ if (ldap_set_option($lc, LDAP_OPT_PROTOCOL_VERSION, 3) === false) {
+ if (ldap_set_option($lc, LDAP_OPT_PROTOCOL_VERSION, 2) === FALSE)
+ return $res;
+ $ver = 2;
+ }
+ if ($this->ldap['tls']) {
+ if ($ver < 3)
+ return $res;
+ if (ldap_start_tls($lc) === false)
+ return $res;
+ }
+ //echo "$ver: $dn\n";
+ if (@ldap_bind($lc, $dn, $pwd))
+ $res = true;
+ ldap_close($lc);
+ }
+ }
+ return $res;
+ }
+}
--- /dev/null
+<?php
+/* $Id$ */
+require_once 'config.inc.php';
+require_once 'user_settings.inc.php';
+require_once 'user_validate.php';
+require_once 'helper.php';
+
+valid_user();
+
+if (! defined($_SESSION['__ROOT__']) && empty($_SESSION['__ROOT__'])) {
+ if (session_id())
+ session_destroy();
+ header('Location: ' . WEB_ROOT . 'error.html');
+ exit;
+}
+
+require_once 'persistens.php';
+//var_dump($_POST);
+//exit();
+include TOP_FOLDER.'/include/header.inc.php';
+include TOP_FOLDER.'/include/menu.inc.php';
+
+function colors($selected = null) {
+ $list = array('aqua', 'black', 'blue', 'fuchsia', 'gray', 'green',
+ 'lime', 'maroon', 'navy', 'olive', 'purple', 'red', 'silver',
+ 'teal', 'white', 'yellow');
+
+ $colors = '';
+ foreach ($list as $color) {
+ $colors .= "<option value=\"$color\" style=\"background: $color\"";
+ if ($selected && $selected == $color)
+ $colors .= ' selected="true"';
+ $colors .= ">$color</option>";
+ }
+ return $colors;
+}
+
+$user = $_SESSION['user_settings'];
+if (count($_POST) > 0 && isset($_POST['action'])) {
+ $db = Persistens::getInstance(DBDRIVER);
+ $calconf = $_POST['calendar'];
+ if ($_POST['action'] == 'new') {
+ $row = $calconf;
+ $text = "url={$row['url']}\nuid={$row['uid']}\npwd={$row['pwd']}";
+ $text = encode($text);
+ $calendar = new CalendarInfo();
+ $calendar->name = $row['name'];
+ $calendar->color = $row['color'];
+ $calendar->config = $text;
+ $id = $db->addCalendar($user->getUid(), $calendar);
+ if (is_numeric($id)) {
+ $user->addCalendar($id, $calendar);
+ $pageView = "<p class=\"usermanage\">Calendar was added with id $id</p>";
+ }
+ else {
+ $pageView = "<p class=\"usermanage\">$id</p>";
+ }
+ }
+ else {
+ foreach ($calconf as $id => $row) {
+ if (! isset($row[check]))
+ continue;
+ if ($_POST['action'] == 'update') {
+ $text = "url={$row['url']}\nuid={$row['uid']}\npwd={$row['pwd']}";
+ $text = encode($text);
+ $calendar = new CalendarInfo();
+ $calendar->name = $row['name'];
+ $calendar->color = $row['color'];
+ $calendar->config = $text;
+ $res = $db->updateCalendar($user->getUid(), $id, $calendar);
+ if ($res === TRUE) {
+ $user->addCalendar($id, $calendar);
+ $pageView = "<p class=\"usermanage\">Calendar with id $id was updated</p>";
+ }
+ else {
+ $pageView = "<p class=\"usermanage\">$id</p>";
+ }
+ }
+ else {
+ $res = $db->deleteCalendar($user->getUid(), $id);
+ if ($res === TRUE) {
+ $user->removeCalendar($id);
+ $pageView = "<p class=\"usermanage\">Calendar with id $id was removed</p>";
+ }
+ else {
+ $pageView = "<p class=\"usermanage\">$id</p>";
+ }
+ }
+ }
+ }
+ $pageView .= '</table>';
+}
+else if (count($_POST) > 0 && isset($_POST['new'])) {
+ $colors = colors();
+ $pageView = '<form id="form" action="'.$_SERVER[PHP_SELF].'" method="post">
+ <table class="config">';
+ $pageView .= "<tr><td>Name</td>
+ <td><input name=\"calendar[name]\" type=\"text\" size=\"20\"/></td>
+ </tr>
+ <tr>
+ <td>Color</td>
+ <td>
+ <select name=\"calendar[color]\">
+ $colors
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td>URL</td>
+ <td><input name=\"calendar[url]\" type=\"text\" size=\"50\"/></td>
+ </tr>
+ <tr>
+ <td>Username</td>
+ <td><input name=\"calendar[uid]\" type=\"text\" size=\"20\"/></td>
+ </tr>
+ <tr>
+ <td>Password</td>
+ <td><input name=\"calendar[pwd]\" type=\"password\" size=\"20\"/></td>
+ </tr>";
+ $pageView .= '<tr>
+ <td colspan="6" style="text-align: center">
+ <input type="button" value="Submit"
+ onclick="document.getElementById(\'form\').submit()">
+ <input type="hidden" name="action" value="new"/>
+ </td>
+ </tr>';
+ $pageView .= '</table></form>';
+}
+else {
+ //var_dump($_SESSION['authenticate']);
+ //var_dump($user);
+ //exit();
+ $calendars = $user->getCalendars();
+ //var_dump($calendars);
+ //exit();
+ $pageView = '<form id="form" action="'.$_SERVER[PHP_SELF].'" method="post">
+ <table id="cal">';
+
+ if (count($calendars) > 0) {
+ foreach ($calendars as $id => $cal) {
+ $text = decode($cal->config);
+ $color = colors($cal->color);
+ $info = implode_cal($text);
+ $pageView .= "<tr><td>Name</td>
+ <td><input name=\"calendar[$id][name]\" type=\"text\" size=\"8\" value=\"{$cal->name}\"/></td>
+ <td>Color</td>
+ <td>
+ <select name=\"calendar[$id][color]\">
+ $color
+ </select>
+ </td>
+ <td>URL</td>
+ <td><input name=\"calendar[$id][url]\" type=\"text\" size=\"40\" value=\"{$info['url']}\"/>
+ </td>
+ <td>Username</td>
+ <td><input name=\"calendar[$id][uid]\" type=\"text\" size=\"8\" value=\"{$info['uid']}\"/></td>
+ <td>Password</td>
+ <td><input name=\"calendar[$id][pwd]\" type=\"password\" size=\"8\" value=\"{$info['pwd']}\"/></td>
+ <td><input type=\"checkbox\" name=\"calendar[$id][check]\" value=\"$id\"/></td>
+ </tr>";
+ }
+ $pageView .= '<tr>
+ <td colspan="11" style="text-align: center">
+ <input type="radio" name="action" value="delete">Delete</input>
+ <input type="radio" name="action" value="update">Update</input>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="11" style="text-align: center">
+ <input type="button" value="Submit"
+ onclick="document.getElementById(\'form\').submit()">
+ <input type="submit" name="new" value="New Calendar"/>
+ </td>
+ </tr>';
+ }
+ else {
+ $pageView .= '<tr>
+ <td>
+ <input type="submit" name="new" value="New Calendar"/>
+ </td>
+ </tr>';
+ }
+ $pageView .= '</table></form>';
+}
+print "<div id=\"ui\">$pageView</div>";
+
+include TOP_FOLDER.'/include/footer.inc.php';
+?>
--- /dev/null
+<?php
+/* $Id$ */
+require_once 'config.inc.php';
+require_once 'user_validate.php';
+require_once 'timezone.php';
+require_once 'helper.php';
+
+valid_user();
+
+if (! defined($_SESSION['__ROOT__']) && empty($_SESSION['__ROOT__'])) {
+ if (session_id())
+ session_destroy();
+ header('Location: ' . WEB_ROOT . 'error.html');
+ exit;
+}
+
+require_once 'persistens.php';
+
+$user = $_SESSION['user_settings'];
+
+if (count($_POST) > 0 && isset($_POST['action'])) {
+ $db = Persistens::getInstance(DBDRIVER);
+
+ if ($_POST['action'] == "password") {
+ if ($_POST['pwd1'] == $_POST['pwd2']) {
+ $res = $db->changePassword($user->getUid(), sha1($_POST['pwd1']));
+ if ($res === TRUE) {
+ header("Location: " . WEB_ROOT . "logout.php");
+ exit();
+ }
+ //else {
+ // $res = "uid: ".$user->getUid()." ".$_POST['pwd1']." ".$_POST['pwd2']." -> $res";
+ //}
+ }
+ else {
+ $res = "Passwords did not compare";
+ }
+ $pageView = "<p style=\"text-align: center\">$res</p>";
+ }
+ else if ($_POST['action'] == "settings") {
+ file_put_contents('/tmp/davical.log',
+ __FILE__ . ": " . var_export($_POST, TRUE), FILE_APPEND);
+ $conf = array();
+ if ($_POST['endDay'] > $_POST['startDay']) {
+ $conf['daystart'] = $_POST['startDay'];
+ $conf['dayend'] = $_POST['endDay'];
+ }
+ else {
+ $conf['daystart'] = $user->getStartHour();
+ $conf['dayend'] = $user->getEndHour();
+ }
+ $conf['timeout'] =
+ ($_POST['timeout'] > 0) ? $_POST['timeout'] * 60 :
+ $user->getTimeout() / 60;
+ $conf['userview'] = $_POST['viewStyle'];
+ $conf['weekstart'] = ($_POST['startWeek'] == 'SU') ? 1 : 0;
+ $conf['timezone'] = $_POST['timezone'];
+ $conf['userrole'] = $user->getRole();
+ $res = $db->setUserSettings($user->getUid(), $conf);
+ if ($res === TRUE) {
+ $user->setSettings(array($conf));
+ header("Location: " . $_SERVER['PHP_SELF']);
+ exit();
+ }
+ $pageView = "<p style=\"text-align: center\">$res</p>";
+ }
+}
+else {
+ $timeout = $user->getTimeout() / 60;
+ $viewStyle = $user->getViewStyle();
+ switch ($viewStyle) {
+ case 'day':
+ $viewStyle = <<<_SELECT
+ <select name="viewStyle">
+ <option value="day" selected="true">Day</option>
+ <option value="week">Week</option>
+ <option value="month">Month</option>
+ </select>
+_SELECT;
+ break;
+ case 'week':
+ $viewStyle = <<<_SELECT
+ <select name="viewStyle">
+ <option value="day">Day</option>
+ <option value="week" selected="true">Week</option>
+ <option value="month">Month</option>
+ </select>
+_SELECT;
+ break;
+ case 'month':
+ $viewStyle = <<<_SELECT
+ <select name="viewStyle">
+ <option value="day">Day</option>
+ <option value="week">Week</option>
+ <option value="month" selected="true">Month</option>
+ </select>
+_SELECT;
+ break;
+ }
+ $weekStart = $user->getStartWeek();
+ if ($weekStart)
+ $weekStart = <<<_SELECT
+ <select name="startWeek">
+ <option value="SU" selected="true">Sunday</option>
+ <option value="MO">Monday</option>
+ </select>
+_SELECT;
+ else
+ $weekStart = <<<_SELECT
+ <select name="startWeek">
+ <option value="SU">Sunday</option>
+ <option value="MO" selected="true">Monday</option>
+ </select>
+_SELECT;
+
+ $dayStart = (int) $user->getStartHour();
+ $start = '<select name="startDay">';
+ for ($i = 0; $i < 25; $i++) {
+ $hour = ($i < 10) ? "0$i:00" : "$i:00";
+ $start .= "<option value=\"$i\"";
+ if ($i == $dayStart)
+ $start .= " selected=\"true\"";
+ $start .= ">$hour</option>";
+ }
+ $start .= '</select>';
+ $dayEnd = (int) $user->getEndHour();
+ $end = '<select name="endDay">';
+ for ($i = 0; $i < 25; $i++) {
+ $hour = ($i < 10) ? "0$i:00" : "$i:00";
+ $end .= "<option value=\"$i\"";
+ if ($i == $dayEnd)
+ $end .= " selected=\"true\"";
+ $end .= ">$hour</option>";
+ }
+ $end .= '</select>';
+
+ $current = $user->getTimezone();
+ foreach ($timezones as $timezone) {
+ $tz .= "<option value=\"$timezone\"";
+ if ($current == $timezone)
+ $tz .= ' selected="true"';
+ $tz .= ">$timezone</option>";
+ }
+
+ $url = getServerUrl();
+ if ($url[strlen($url)-1] == '/')
+ $url = substr($url, 0, -1);
+
+ $pageView = <<< __EOF
+ <p>
+ <form action="{$_SERVER['PHP_SELF']}" method="post">
+ <table class="config">
+ <tr>
+ <th>Setting</th><th>Current</th>
+ </tr>
+ <tr>
+ <td class="config">Session timeout in minuts</td>
+ <td class="config">
+ <input size="6" name="timeout" type="text" value="$timeout"/>
+ </td>
+ </tr>
+ <tr>
+ <td class="config">Default view</td><td>$viewStyle</td>
+ </tr>
+ <tr>
+ <td class="config">Timezone</td>
+ <td class="config">
+ <select name="timezone">
+ $tz
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td class="config">Week start on</td><td>$weekStart</td>
+ </tr>
+ <tr>
+ <td class="config">Day start</td>
+ <td class="config">$start</td>
+ </tr>
+ <tr>
+ <td class="config">Day end</td>
+ <td class="config">$end</td>
+ </tr>
+ <tr>
+ <input type="hidden" name="action" value="settings"/>
+ <td class="config" colspan="2" style="text-align: center">
+ <input type="submit" name="setting" value="Submit changes"/>
+ </td>
+ </tr>
+ </table>
+ </form>
+ </p>
+__EOF;
+ if (strtoupper($user->getUid()) != 'ADMIN') {
+ $pageView .= <<< __EOF
+ <p style="text-align: center">
+ <button type="button" id="calconfig"
+ onclick="document.location.href='$url/utils/calendar.php'">
+ Configure Calendars
+ </button>
+ </p>
+__EOF;
+ }
+ if ($user->getRole() === 0) {
+ $pageView .= <<<__EOF
+ <p style="text-align: center">
+ <button type="button" id="useradm"
+ onclick="document.location.href='$url/utils/users.php'">
+ Manage users
+ </button>
+
+ <button type="button" id="ldapadm"
+ onclick="document.location.href='$url/utils/ldap.php'">
+ Configure LDAP
+ </button>
+ </p>
+__EOF;
+ }
+ $pageView .= <<<__EOF
+ <p>
+ <form action="{$_SERVER['PHP_SELF']}" method="post">
+ <table class="config">
+ <tr>
+ <th colspan="2" style="text-align: center">Change password</th>
+ </tr>
+ <tr>
+ <td colspan="2"><span style="background: red; font-weight: bold;">
+ After changing the password a relogin is required
+ </span></td>
+ </tr>
+ <tr>
+ <td class="config">New Password</td>
+ <td class="config"><input name="pwd1" type="password"/></td>
+ </tr>
+ <tr>
+ <td class="config">Repeat Password</td>
+ <td class="config"><input name="pwd2" type="password"/></td>
+ </tr>
+ <tr>
+ <input type="hidden" name="action" value="password"/>
+ <td class="config" colspan="2" style="text-align: center">
+ <input type="submit" name="password" value="Submit"/>
+ </td>
+ </tr>
+ </table>
+ </form>
+ </p>
+__EOF;
+}
+
+include TOP_FOLDER.'/include/header.inc.php';
+include TOP_FOLDER.'/include/menu.inc.php';
+
+print "<div id=\"ui\">$pageView</div>";
+
+include TOP_FOLDER.'/include/footer.inc.php';
+?>
--- /dev/null
+<?php
+
+include_once 'config.inc.php';
+require_once 'helper.php';
+
+class DateFormat {
+/* private $tz;
+
+ function __construct($tz = '') {
+ if (empty($tz)) {
+ $tz = ($_SESSION['user_settings']->getTimeZone() !== NULL) ?
+ $_SESSION['user_settings']->getTimeZone() : TIMEZONE;
+ }
+ $timezone = date_default_timezone_get();
+ $tz_server = date("Z")/3600;
+ date_default_timezone_set($tz);
+ $tz_client = date("Z")/3600;
+ date_default_timezone_set($timezone);
+ $this->tz = $tz_client - $tz_server;
+ print "$timezone:$tz_server:$tz_client<br/>";
+ }*/
+
+ public function client2UTC($datetime) {
+ if (strcasecmp(substr($datetime, -1), "Z") === 0) {
+ // Time is in UTC already
+ return $datetime;
+ }
+
+ $timestamp = strtotime($datetime);
+
+ return gmdate("Ymd\THis\Z", $timestamp);
+ }
+
+ public function UTC2Client($datetime) {
+ //print "UTC2Client: $datetime\n";
+ if (strcasecmp(substr($datetime, -1), "Z") !== 0) {
+ // Time is not in UTC
+ return $datetime;
+ }
+
+ $timestamp = strtotime($datetime);
+
+ return date("Ymd\THis", $timestamp);
+ }
+
+ public function UTC2Local($datetime) {
+ if (strcasecmp(substr($datetime, -1), "Z") !== 0) {
+ // Time is not in UTC
+ return $datetime;
+ }
+
+ $offset = $_SESSION['timezone_offset'] - date("Z");
+ $timestamp = strtotime($datetime) + $offset;
+
+ return date("Ymd\THis", $timestamp);
+ }
+
+}
\ No newline at end of file
--- /dev/null
+<?php
+/* $Id$ */
+
+function make_sql_stm() {
+ $db = array();
+
+ array_push($db, "create sequence roles_pk_seq");
+ array_push($db, "create table roles (
+ id integer primary key default nextval('roles_pk_seq'),
+ name varchar(256) not null
+ )");
+ array_push($db, "insert into roles values(0,'administrator')");
+ array_push($db, "insert into roles values(1,'power user')");
+ array_push($db, "insert into roles values(2,'user')");
+
+ array_push($db, "create sequence users_pk_seq");
+ array_push($db, "create table users (
+ id integer primary key default nextval('users_pk_seq'),
+ uid varchar(256) not null,
+ pwd varchar(256) not null,
+ userrole integer not null,
+ timeout integer default 3600,
+ userview varchar(256) default 'week',
+ weekstart integer default 0,
+ daystart numeric(4,2) default 8.00,
+ dayend numeric(4,2) default 17.00,
+ timezone varchar(256) default 'Etc/UTC',
+ seckey varchar(256) default '',
+ pubkey varchar(256) default '',
+ constraint uid_index unique (uid),
+ constraint userrole_fk foreign key (userrole) references roles (id)
+ on update cascade
+ on delete restrict
+ )");
+
+ array_push($db, "create sequence calendar_pk_seq");
+ array_push($db, "create table calendar (
+ id integer default nextval('calendar_pk_seq'),
+ uid integer not null,
+ name varchar(256) not null,
+ color varchar(256) default 'navy',
+ config varchar(4000) default '',
+ constraint calendar_pk primary key (id, uid),
+ constraint uid_fk foreign key (uid) references users (id)
+ on update cascade
+ on delete cascade
+ )");
+ array_push($db, "create table about (
+ id integer default 1,
+ version varchar(256) default '')");
+ array_push($db, "create table ldap (
+ enable integer default 0,
+ dns varchar(256) default '',
+ tls integer default 0,
+ base_dn varchar(256) default '',
+ user_attr varchar(256) default 'uid')");
+
+ return $db;
+}
--- /dev/null
+BEGIN TRANSACTION;
+DELETE FROM sqlite_sequence;
+INSERT INTO "sqlite_sequence" VALUES('roles',2);
+INSERT INTO "sqlite_sequence" VALUES('user',5);
+CREATE TABLE roles (
+id integer primary key autoincrement,
+name text not null
+);
+INSERT INTO "roles" VALUES(0,'administrator');
+INSERT INTO "roles" VALUES(1,'power user');
+INSERT INTO "roles" VALUES(2,'user');
+CREATE TABLE user (
+id integer primary key autoincrement,
+uid text not null,
+pwd text not null,
+userrole integer not null,
+timeout integer default 3600,
+userview text default 'week',
+weekstart integer default 0,
+daystart real default 8.00,
+dayend real default 17.00,
+seckey text default '',
+pubkey text default '',
+constraint uid_index unique (uid)
+constraint userrole_fk foreign key (userrole) references roles (id)
+on delete restrict
+on update cascade
+on insert cascade
+);
+INSERT INTO "user" VALUES(1,'admin','d033e22ae348aeb5660fc2140aec35850c4da997',0,1200,'week',0,8.0,17.0,'','');
+INSERT INTO "user" VALUES(2,'test','a94a8fe5ccb19ba61c4c0873d391e987982fbbd3',1,3600,'week',0,8.0,17.0,'da830961dc3af47fff6d1af3be3d66d6','\93¢yQ è\85§¸\90d\8e\9c±gaÙ8(\r<\a\vk\9dÂy\86*\19:ð');
+CREATE TABLE calendar (
+id integer default -1,
+uid integer not null,
+name text not null,
+color text default 'navy',
+config text default '',
+constraint calendar_pk primary key (id, uid),
+constraint uid_fk foreign key (uid) references user (id)
+on delete cascade
+on update cascade
+on insert cascade
+);
+CREATE TRIGGER compute_id after insert on calendar
+begin
+ update calendar set id = (select max(id) + 1 from calendar) where id = -1;
+end;
+CREATE TRIGGER genfkey2_insert_referencing BEFORE INSERT ON "calendar" WHEN
+ new."uid" IS NOT NULL AND NOT EXISTS (SELECT 1 FROM "user" WHERE new."uid" == "id")
+BEGIN
+ SELECT RAISE(ABORT, 'constraint failed');
+END;
+CREATE TRIGGER genfkey2_update_referencing BEFORE
+ UPDATE OF uid ON "calendar" WHEN
+ new."uid" IS NOT NULL AND
+ NOT EXISTS (SELECT 1 FROM "user" WHERE new."uid" == "id")
+BEGIN
+ SELECT RAISE(ABORT, 'constraint failed');
+END;
+CREATE TRIGGER genfkey2_delete_referenced BEFORE DELETE ON "user" WHEN
+ EXISTS (SELECT 1 FROM "calendar" WHERE old."id" == "uid")
+BEGIN
+ DELETE FROM "calendar" WHERE "uid" = old."id";
+END;
+CREATE TRIGGER genfkey2_update_referenced AFTER
+ UPDATE OF id ON "user" WHEN
+ EXISTS (SELECT 1 FROM "calendar" WHERE old."id" == "uid")
+BEGIN
+ UPDATE "calendar" SET "uid" = new."id" WHERE "uid" = old."id";
+END;
+CREATE TRIGGER genfkey1_insert_referencing BEFORE INSERT ON "user" WHEN
+ new."userrole" IS NOT NULL AND NOT EXISTS (SELECT 1 FROM "roles" WHERE new."userrole" == "id")
+BEGIN
+ SELECT RAISE(ABORT, 'constraint failed');
+END;
+CREATE TRIGGER genfkey1_update_referencing BEFORE
+ UPDATE OF userrole ON "user" WHEN
+ new."userrole" IS NOT NULL AND
+ NOT EXISTS (SELECT 1 FROM "roles" WHERE new."userrole" == "id")
+BEGIN
+ SELECT RAISE(ABORT, 'constraint failed');
+END;
+CREATE TRIGGER genfkey1_delete_referenced BEFORE DELETE ON "roles" WHEN
+ EXISTS (SELECT 1 FROM "user" WHERE old."id" == "userrole")
+BEGIN
+ SELECT RAISE(ABORT, 'constraint failed');
+END;
+CREATE TRIGGER genfkey1_update_referenced AFTER
+ UPDATE OF id ON "roles" WHEN
+ EXISTS (SELECT 1 FROM "user" WHERE old."id" == "userrole")
+BEGIN
+ UPDATE "user" SET "userrole" = new."id" WHERE "userrole" = old."id";
+END;
+COMMIT;
--- /dev/null
+<?php
+/* $Id$ */
+
+function make_sql_stm() {
+ $db = array();
+
+ array_push($db, "drop table if exists roles");
+ array_push($db, "CREATE TABLE roles (
+ id integer primary key autoincrement,
+ name text not null
+ )");
+ array_push($db, "INSERT INTO roles VALUES(0,'administrator')");
+ array_push($db, "INSERT INTO roles VALUES(1,'power user')");
+ array_push($db, "INSERT INTO roles VALUES(2,'user')");
+
+ array_push($db, "drop table if exists user");
+ array_push($db, "CREATE TABLE user (
+ id integer primary key autoincrement,
+ uid text not null,
+ pwd text not null,
+ userrole integer not null,
+ timeout integer default 3600,
+ userview text default 'week',
+ weekstart integer default 0,
+ daystart real default 8.00,
+ dayend real default 17.00,
+ timezone text default 'Etc/UTC',
+ seckey text default '',
+ pubkey text default '',
+ constraint uid_index unique (uid)
+ )");
+
+ array_push($db, "drop table if exists calendar");
+ array_push($db, "CREATE TABLE calendar (
+ id integer default -1,
+ uid integer not null,
+ name text not null,
+ color text default 'navy',
+ config text default '',
+ constraint calendar_pk primary key (id, uid)
+ )");
+ array_push($db, "CREATE TRIGGER compute_id after insert on calendar
+ begin
+ update calendar set id = (select max(id) + 1 from calendar) where id = -1;
+ end;");
+ array_push($db, "CREATE TRIGGER genfkey2_insert_referencing BEFORE INSERT ON calendar WHEN
+ new.uid IS NOT NULL AND NOT EXISTS (SELECT 1 FROM user WHERE new.uid == id)
+ BEGIN
+ SELECT RAISE(ABORT, 'constraint failed');
+ END");
+ array_push($db, "CREATE TRIGGER genfkey2_update_referencing BEFORE
+ UPDATE OF uid ON calendar WHEN
+ new.uid IS NOT NULL AND
+ NOT EXISTS (SELECT 1 FROM user WHERE new.uid == id)
+ BEGIN
+ SELECT RAISE(ABORT, 'constraint failed');
+ END");
+ array_push($db, "CREATE TRIGGER genfkey2_delete_referenced BEFORE DELETE ON
+ user WHEN EXISTS (SELECT 1 FROM calendar WHERE old.id == uid)
+ BEGIN
+ DELETE FROM calendar WHERE uid = old.id;
+ END");
+ array_push($db, "CREATE TRIGGER genfkey2_update_referenced AFTER
+ UPDATE OF id ON user WHEN
+ EXISTS (SELECT 1 FROM calendar WHERE old.id == uid)
+ BEGIN
+ UPDATE calendar SET uid = new.id WHERE uid = old.id;
+ END");
+ array_push($db, "CREATE TRIGGER genfkey1_insert_referencing BEFORE INSERT ON
+ user WHEN new.userrole IS NOT NULL AND NOT EXISTS (SELECT 1 FROM roles WHERE
+ new.userrole == id)
+ BEGIN
+ SELECT RAISE(ABORT, 'constraint failed');
+ END");
+ array_push($db, "CREATE TRIGGER genfkey1_update_referencing BEFORE
+ UPDATE OF userrole ON user WHEN new.userrole IS NOT NULL AND
+ NOT EXISTS (SELECT 1 FROM roles WHERE new.userrole == id)
+ BEGIN
+ SELECT RAISE(ABORT, 'constraint failed');
+ END");
+ array_push($db, "CREATE TRIGGER genfkey1_delete_referenced BEFORE DELETE ON
+ roles WHEN EXISTS (SELECT 1 FROM user WHERE old.id == userrole)
+ BEGIN
+ SELECT RAISE(ABORT, 'constraint failed');
+ END");
+ array_push($db, "CREATE TRIGGER genfkey1_update_referenced AFTER
+ UPDATE OF id ON roles WHEN
+ EXISTS (SELECT 1 FROM user WHERE old.id == userrole)
+ BEGIN
+ UPDATE user SET userrole = new.id WHERE userrole = old.id;
+ END");
+ array_push($db, "drop table if exists about");
+ array_push($db, "create table about (
+ id integer default 1,
+ version text default '')");
+ array_push($db, "drop table if exists ldap");
+ array_push($db, "create table ldap (
+ enable integer default 0,
+ dns text default '',
+ tls integer default 0,
+ base_dn text default '',
+ user_attr text default 'uid')");
+
+ return $db;
+}
--- /dev/null
+<?php
+/* $Id$ */
+include_once 'config.inc.php';
+require_once 'persistens.php';
+
+define('MICRO', 1);
+define('MINOR', 8);
+define('MAJOR', 0);
+
+$VERSION = MAJOR.".".MINOR.".".MICRO;
+$CURRENT_VERSION = $VERSION;
+$PREFIX = TOP_FOLDER."/install/".DBDRIVER;
+$PATCH_SET = array(
+ "173" => "db_upgrade_0_7_3.sql",
+ "174" => "db_upgrade_0_7_4.sql",
+ "175" => "db_upgrade_0_7_5.sql",
+ "180" => "db_upgrade_0_8_0.sql",
+ "181" => "db_upgrade_0_8_1.sql",
+);
+
+$pwd = WEB_ROOT;
+if ($pwd[strlen($pwd)-1] == '/')
+ $pwd = substr($pwd, 0, -1);
+
+function string2int($str) {
+ if (is_numeric($str))
+ return $str;
+ if (is_string($str)) {
+ $parts = explode(".", $str);
+ $str = 0;
+ for ($i = 0; $i < count($parts); $i++) {
+ $num = ($i == 0) ? $parts[$i] + 1 : $parts[$i];
+ $str += (pow(10, count($parts) - $i - 1) * $num);
+ }
+ }
+ return $str;
+}
+
+function getServerUrl($root = WEB_ROOT, $cwd = "") {
+ $root = (! empty($root) && $root[0] == '/') ? substr($root, 1) : $root;
+ $root = (! empty($root) && $root[strlen($root) - 1] == '/') ? substr($root, 0, -1) : $root;
+ $cwd = (! empty($cwd) && $cwd[0] == '/') ? substr($cwd, 1) : $cwd;
+ $cwd = (! empty($cwd) && $cwd[strlen($cwd) - 1] == '/') ? substr($cwd, 0, -1) : $cwd;
+
+ //echo var_export($_SERVER, true);
+ $protocol = ((isset($_SERVER['HTTPS']) && ! empty($_SERVER['HTTPS'])) || (isset($_SERVER['HTTPS']) && strcasecmp("on", $_SERVER['HTTPS']) === 0)
+ || (isset($_SERVER['HTTP_SCHEME']) && strcasecmp("https", $_SERVER['HTTP_SCHEME']) === 0)) ? "https" : "http";
+ //echo "$protocol<br/>";
+ $server = ($_SERVER['SERVER_PORT'] == 80 || $_SERVER['SERVER_PORT'] == 443)?
+ $_SERVER['SERVER_NAME'] : $_SERVER['SERVER_NAME'].':'.$_SERVER['SERVER_PORT'];
+ $url = (! empty($cwd)) ? "$protocol://$server/$cwd" : "$protocol://$server";
+
+ return "$url/$root";
+}
+
+function getServerUri() {
+ return TOP_FOLDER;
+}
+
+function createKey($key) {
+ $td = mcrypt_module_open('rijndael-256', '', 'ofb', '');
+ $public = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_DEV_RANDOM);
+ $ks = mcrypt_enc_get_key_size($td);
+ mcrypt_module_close($td);
+
+ /* Create key */
+ $secret = substr($key, 0, $ks);
+ return array($secret, $public);
+}
+
+function encode($text) {
+ /* Intialize encryption */
+ $td = mcrypt_module_open('rijndael-256', '', 'ofb', '');
+ $iv = $_SESSION['authenticate']->getPublicKey();
+ $key = $_SESSION['authenticate']->getSecretKey();
+
+ mcrypt_generic_init($td, $key, $iv);
+
+ /* Encrypt data */
+ $ciffer = mcrypt_generic($td, $text);
+ $encrypted = quoted_printable_encode($ciffer);
+
+ /* Terminate encryption handler */
+ mcrypt_generic_deinit($td);
+ mcrypt_module_close($td);
+
+ return $encrypted;
+}
+
+function decode($text) {
+ $td = mcrypt_module_open('rijndael-256', '', 'ofb', '');
+ $iv = $_SESSION['authenticate']->getPublicKey();
+ $key = $_SESSION['authenticate']->getSecretKey();
+
+ /* Initialize encryption module for decryption */
+ mcrypt_generic_init($td, $key, $iv);
+
+ /* Decrypt encrypted string */
+ $ciffer = quoted_printable_decode($text);
+ $decrypted = mdecrypt_generic($td, $ciffer);
+
+ /* Terminate decryption handle and close module */
+ mcrypt_generic_deinit($td);
+ mcrypt_module_close($td);
+
+ return $decrypted;
+}
+
+function implode_cal($text) {
+ $infos = explode("\n", $text);
+ foreach ($infos as $info) {
+ $row = explode('=', $info);
+ $result[$row[0]] = $row[1];
+ }
+ return $result;
+}
+
+// taken from roundcubemail
+if (!function_exists("quoted_printable_encode")) {
+ function quoted_printable_encode($text) {
+ $length=strlen($text);
+ for ($whitespace= "", $line=0,$encode= "",
+ $index=0;$index<$length;$index++) {
+ $character=substr($text,$index,1);
+ $order=Ord($character);
+ $encode=0;
+ switch($order) {
+ case 9:
+ case 32:
+ if ($header_charset== "") {
+ $previous_whitespace=$whitespace;
+ $whitespace=$character;
+ $character= "";
+ }
+ else {
+ if ($order==32)
+ $character= "_";
+ else
+ $encode=1;
+ }
+ break;
+ case 10:
+ case 13:
+ if ($whitespace!= "") {
+ if ($line+3>75) {
+ $encoded.= "=\n";
+ $line=0;
+ }
+ $encoded.=sprintf( "=%02X",Ord($whitespace));
+ $line+=3;
+ $whitespace= "";
+ }
+ $encoded.=$character;
+ $line=0;
+ continue 2;
+ default:
+ if ($order > 127 || $order < 32 || $character == "="
+ || ($character == "?" || $character == "_" ||
+ $character == "(" || $character== ")"))
+ $encode=1;
+ break;
+ }
+ if ($whitespace!= "") {
+ if ($line+1>75) {
+ $encoded.= "=\n";
+ $line=0;
+ }
+ $encoded.=$whitespace;
+ $line++;
+ $whitespace= "";
+ }
+ if ($character!= "") {
+ if($encode) {
+ $character=sprintf( "=%02X",$order);
+ $encoded_length=3;
+ }
+ else
+ $encoded_length=1;
+ if ($line+$encoded_length > 75) {
+ $encoded.= "=\n";
+ $line=0;
+ }
+ $encoded.=$character;
+ $line+=$encoded_length;
+ }
+ }
+ if ($whitespace!= "") {
+ if ($line+3>75)
+ $encoded.= "=\n";
+ $encoded.=sprintf( "=%02X",Ord($whitespace));
+ }
+ return $encoded;
+ }
+}
+
+function newUpdates() {
+ global $VERSION, $CURRENT_VERSION;
+
+ $con = Persistens::getInstance(DBDRIVER);
+ try {
+ $res = $con->getVersion();
+ }
+ catch (Exception $e) {
+ ReportError($e);
+ }
+ $version = $res['version'];
+ $version = string2int($version);
+ if (! is_numeric($version)) {
+ ReportError("Invalid version format");
+ exit;
+ }
+ $CURRENT_VERSION = $version;
+ //file_put_contents('/tmp/updates', string2int($VERSION)." > $version", FILE_APPEND);
+ return string2int($VERSION) > $version;
+}
+
+function upgrade() {
+ global $VERSION, $PATCH_SET, $CURRENT_VERSION, $PREFIX;
+ $table = 'backup';
+
+ $version = string2int($CURRENT_VERSION);
+ $con = Persistens::getInstance(DBDRIVER);
+ try {
+ $res = $con->getVersion();
+ }
+ catch (Exception $e) {
+ ReportError($e);
+ exit;
+ }
+ if (($num = $con->nextTableNumber('backup')) > 0)
+ $table .= $num;
+
+ if ($version < 173) {
+ if (($res = $con->execute(
+ "create table $table as select * from calendar")) !== true) {
+ ReportError($res);
+ exit;
+ }
+ $rows = $con->getCalendarConfig();
+ if (! is_array($rows)) {
+ ReportError($rows);
+ exit;
+ }
+ foreach($rows as $row) {
+ if (function_exists(quoted_printable_encode))
+ $ciffer = quoted_printable_encode($row['config']);
+ else
+ $ciffer = webcal_quoted_printable_encode($row['config']);
+ if (($res = $con->execute("begin transaction")) !== true) {
+ ReportError($res);
+ exit;
+ }
+ if (($res = $con->execute(
+ "update calendar set config = '$ciffer' where id = " .
+ $row['id'])) !== true) {
+ $con->execute("rollback");
+ ReportError($res."<br/>A backup of your calendar data can be found in table backup");
+ exit;
+ }
+ }
+ $con->execute("commit");
+ }
+ if ($version >= 174) {
+ // remove pgsql.php from root. Accidentally placed there in release 0.7.4
+ if (file_exists(TOP_FOLDER."/pgsql.php"))
+ unlink(TOP_FOLDER."/pgsql.php");
+ // patch config.inc.php
+ if (substr(PHP_OS, 0, 3) !== 'WIN') {
+ $oldcwd = getcwd();
+ $cwd = TOP_FOLDER.'/install';
+ chdir($cwd);
+ if ($version < 181) {
+ exec("patch -p0 < config.inc.php.patch");
+ }
+ if ($version > 180) {
+ exec("patch -p0 < config.inc.php1.patch");
+ }
+ chdir($oldcwd);
+ }
+ }
+ foreach ($PATCH_SET as $set => $file) {
+ $content = array();
+ //echo "$set -> $file<br/>";
+ if ($version < $set) {
+ //echo $PREFIX."_".$file."<br/>";
+ if (! file_exists($PREFIX."_".$file))
+ continue;
+ $sql = file_get_contents($PREFIX."_".$file);
+ $raw_lines = explode("\n", $sql);
+ foreach ($raw_lines as $line) {
+ if (preg_match("/^--/", $line))
+ continue;
+ $content[] = $line;
+ }
+ $lines = explode(";", join("\n", $content));
+ if (count($lines) > 0) {
+ if (($res = $con->execute("begin transaction")) !== true) {
+ ReportError($res);
+ exit;
+ }
+ foreach ($lines as $line) {
+ $line = trim($line);
+ if (preg_match("/^\s*$/", $line) || preg_match("/^--/", $line))
+ continue;
+ if (($res = $con->execute($line)) !== true) {
+ ReportError($res);
+ $con->execute("rollback");
+ exit;
+ }
+ }
+ $con->execute("commit");
+ }
+ }
+ else
+ continue;
+ }
+}
+
+function ReportError($msg) {
+ // be sure that the supplied parameter is a string and not empty
+ if (empty ($msg) || !is_string ($msg)) {
+ throw new ErrorException ('Invalid parameter supplied to ReportError', 0, E_ERROR);
+ }
+
+ // retrieve error settings
+ $display = strtolower(ini_get('display_errors'));
+ $log = strtolower(ini_get('log_errors'));
+
+ // check if we're displaying errors
+ if ($display === 'on' || $display === '1' || $display === 1 || $display === 'true' || $display === true) {
+ echo $msg;
+ }
+ else {
+ $pwd = WEB_ROOT;
+ if ($pwd[strlen($pwd)-1] == '/')
+ $pwd = substr($pwd, 0, -1);
+ print '<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+ <head>
+ <title>Web Calendar</title>
+ <link rel="stylesheet" type="text/css"
+ href="'.$pwd.'/css/top_level.css" />
+ <link rel="shortcut icon"
+ href="'.$pwd.'/pixmaps/favicon.ico" />
+ </head>
+ <body>
+ <div id="error_msg">
+ <p>
+ The application has triggered an error which is not
+ recoverable. The execution has therefore been cancelled.
+ <br/><br/>
+ The error is logged and the webmaster will handle
+ the error in due time.
+ <br/><br/>
+ To help fix the application you are welcome to notify
+ the <a href="mailto:'.$_SERVER['SERVER_ADMIN'].'
+ ?subject='.TITLE.': error report['.
+ $_SERVER['SERVER_NAME'].']">webmaster</a>
+ by email with a detailed description containing the
+ following information:
+ <br/><br/>
+ 1) What did you do just before this message occurred<br/>
+ 2) What did you expect to happen<br/>
+ 3) Your browser name and version number.<br/>
+ </p>
+ </div>
+ </body>
+</html>';
+ }
+
+ // check if we're logging errors
+ if ($log === 'on' || $log === '1' || $log === 1 || $log === 'true' || $log === true) {
+ $result = error_log ($msg);
+
+ // check for error while logging
+ if (!$result) {
+ throw new ErrorException ('Attempt to write message to error log failed in ReportError', 0, E_ERROR);
+ }
+ }
+}
+
+function create_user_data($uid, $pwd, $role) {
+ $data = array();
+
+ $data['uid'] = $uid;
+ $data['pwd'] = sha1($pwd);
+ $data['userrole'] = $role;
+ $keys = createKey(sha1("{$data['uid']}{$data['pwd']}"));
+ $data['seckey'] = $keys[0];
+ $data['pubkey'] = $keys[1];
+ $data['timezone'] = TIMEZONE;
+ $data['view'] = VIEW_STYLE;
+ $data['timeout'] = TIMEOUT;
+ $data['week_start'] = WEEK_START_SUNDAY;
+ $data['start'] = START_HOUR;
+ $data['end'] = END_HOUR;
+
+ return $data;
+}
+
+function popup_window($text = '', $redirect = NULL, $form_elem = array(), $title = NULL) {
+ $con = Persistens::getInstance(DBDRIVER);
+ if (! is_array($res = $con->getVersion())) {
+ ErrorReport($res);
+ }
+
+ $title = ($title) ? $title : TITLE;
+ /* deprecated */
+ if (count($form_elem) < 1) {
+ $form = NULL;
+ $input = NULL;
+ }
+ else {
+ $form = key($form_elem);
+ $input = $form_elem[$form];
+ }
+ /* end deprecated */
+ $referer = ($redirect) ? urldecode($redirect) : WEB_ROOT;
+ //print "$referer<br/>";
+ //exit;
+ $pwd = WEB_ROOT;
+$head = <<<__HEAD
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<title>$title</title>
+<meta http-equiv="content-type" content="application/xhtml+xml; charset=UTF-8"/>
+<meta http-equiv="content-style-type" content="text/css"/>
+<link rel="stylesheet" type="text/css" href="$pwd/css/top_level.css" />
+<link rel="shortcut icon" href="$pwd/pixmaps/favicon.ico" />
+<style type="text/css">
+<!--
+#display_overlay_holder {
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ display:none;
+}
+#display_overlay_bg {
+ position: absolute;
+ left: 0px;
+ top: 0px;
+ width: 100%;
+ height: 100%;
+ background-color:#000000;
+ opacity: 0.55;
+ filter: alpha(opacity=85);
+}
+#display_horizon {
+ position: absolute;
+ top: 45%;
+ left: 0px;
+ width: 100%;
+ height: 1px;
+ overflow: visible;
+}
+#display_content {
+ position: absolute;
+ width: 400px;
+ height: 250px;
+ left: 50%;
+ margin-left: -200px;
+ top: -125px;
+ background-color: #CCCCCC;
+}
+#text_content {
+ font-size: 0.8em;
+ color: blue;
+}
+-->
+</style>
+<script type="text/javascript" src="$pwd/js/helper.js"></script>
+</head>
+<body onload="show_the_overlay()">
+<table style="width: 100%;">
+<tr>
+<td style="width: 33%"><img src="$pwd/pixmaps/calendar.png" alt="calendar.png" /></td>
+<td style="width: 33%; text-align: center;"><a href="$pwd/logout.php"><img style="border: 0" src="$pwd/pixmaps/exit.png" width="32" height="32" alt="Logout" /><br/>Logout</a></td>
+<td style="text-align: right"><span style="font-size: 1.6em">DAViCal Web Calendar</span><br/> - A Web Interface for <a href="javascript: newwin('http://www.davical.org/');">DAViCal</a></td>
+</tr>
+</table>
+__HEAD;
+$display = <<<_DISPLAY
+<div id="display_overlay_holder">
+ <div id="display_overlay_bg" />
+ <div id="display_horizon">
+ <div id="display_content">
+ <div id="text_content">
+ $text
+ <br/><br/><br/>
+ <p style="text-align: center;">
+ <button type="button" onclick="hide_the_overlay('$referer')">Cancel</button>
+ </p>
+ </div>
+ </div>
+ </div>
+</div>
+_DISPLAY;
+$foot = <<<_FOOTER
+<div id="footer">
+<p>
+ $title {$res[0]} - © 2010, 2011 Michael Rasmussen<br/>Released under GPLv3
+ <a href="http://validator.w3.org/check?uri=referer">
+ <img src="http://www.w3.org/Icons/valid-xhtml10-blue.png"
+ alt="Valid XHTML 1.0 Strict" height="31" width="88" />
+ </a>
+ <a href="http://jigsaw.w3.org/css-validator/check/referer">
+ <img src="http://www.w3.org/Icons/valid-css2-blue.png"
+ alt="Valid CSS 2.0" height="31" width="88" />
+ </a>
+</p>
+</div>
+_FOOTER;
+ ob_start();
+ print $head;
+ include TOP_FOLDER.'/include/menu.inc.php';
+ print "<div id=\"ui\"> </div>";
+ print $foot;
+ print $display;
+ print "</body></html>";
+
+ return ob_get_clean();
+}
+
+function construct_URL($query_string, $attributes = array()) {
+ $test = trim($query_string);
+ if (empty($test))
+ return array();
+ $current = NULL;
+ $query = array();
+ $query_str = urldecode($query_string);
+ //print "$query_str<br/>";
+ $q = explode('&', $query_str);
+ //print_r($q); echo "<br/>";
+ foreach ($q as $elem) {
+ $s = explode('=', $elem);
+ //print_r($s); echo "<br/>";
+ if (! $current && in_array($s[0], $attributes)) {
+ if (count($s) > 2) {
+ $key = array_shift($s);
+ $value = array_shift($s);
+ $value .= '=';
+ //print "kv: $key $value<br/>";
+ while ($s) {
+ $value .= array_shift($s);
+ $value .= '&';
+ $value .= array_shift($s);
+ }
+ $current = $key;
+ }
+ else {
+ $key = array_shift($s);
+ $value = array_shift($s);
+ }
+ $query[$key] = $value;
+ //print_r($query); echo "<br/>";
+ }
+ else if ($current) {
+ $value = $query[$current];
+ while ($s) {
+ $value .= array_shift($s);
+ $value .= '=';
+ $value .= array_shift($s);
+ }
+ $query[$current] = $value;
+ $current = NULL;
+ //print_r($query); echo "<br/>";
+ }
+ else {
+ $key = array_shift($s);
+ $value = array_shift($s);
+ $query[$key] = $value;
+ //print_r($query); echo "<br/>";
+ }
+ }
+ //print_r($query); echo "<br/>";
+ //exit;
+ // urlencode if nessasary
+ foreach ($query as $key => $value) {
+ if (strpos($value, '&') !== FALSE)
+ $value = urlencode($value);
+ $query_array[$key] = $value;
+ }
+ return $query_array;
+}
+
+//Begin main function definition
+function ErrorsAsExceptions($level, $msg, $fileName, $lineNumber) {
+ // do nothing if error reporting is turned off
+ if (error_reporting() === 0) {
+ return;
+ }
+
+ // be sure received error is supposed to be reported
+ if (error_reporting() & $level) {
+ try {
+ // report error to appropriate channels
+ ReportError(/*$reportMsg*/$msg);
+ }
+ catch (ErrorException $e) {
+ // ignore errors while reporting
+ }
+
+ // go ahead and throw the exception
+ throw new ErrorException($msg, 0, $level, $fileName, $lineNumber);
+ }
+}
+
+set_error_handler('ErrorsAsExceptions');
--- /dev/null
+<?php
+/* $Id$ */
+require_once 'config.inc.php';
+require_once 'user_validate.php';
+require_once 'helper.php';
+
+valid_user();
+
+if (! defined($_SESSION['__ROOT__']) && empty($_SESSION['__ROOT__'])) {
+ if (session_id())
+ session_destroy();
+ header('Location: ' . WEB_ROOT . 'error.html');
+ exit;
+}
+
+require_once 'persistens.php';
+
+$user = $_SESSION['user_settings'];
+
+if ($user->getRole() !== 0) {
+ if (session_id())
+ session_destroy();
+ header('Location: ' . WEB_ROOT . 'error.html');
+ exit;
+}
+
+$db = Persistens::getInstance(DBDRIVER);
+
+if (count($_POST) > 0) {
+ $config = array(
+ (isset($_POST['enable']) && $_POST['enable'] == 'on') ? 1 : 0,
+ $_POST['dns'],
+ (isset($_POST['tls']) && $_POST['tls'] == 'on') ? 1 : 0,
+ $_POST['base_dn'],
+ $_POST['user_attr']
+ );
+ if (($res = $db->setLdapConfig($config)) === true)
+ $pageView = "<p style=\"text-align: center\">
+ LDAP configuration was successfully updated</p>";
+ else
+ $pageView = "<p style=\"text-align: center\">$res</p>";
+}
+else {
+ $config = $db->getLdapConfig();
+ if (! is_array($config) && $config) {
+ if (session_id())
+ session_destroy();
+ header('Location: ' . WEB_ROOT . 'error.html');
+ exit;
+ }
+
+ $enable = ($config['enable']) ? ' checked="checked"' : '';
+ $tls = ($config['tls']) ? ' checked="checked"' : '';
+ $dns = $config['dns'];
+ $base_dn = $config['base_dn'];
+ $user_attr = $config['user_attr'];
+ $pageView = <<< __EOF
+ <form action="{$_SERVER['PHP_SELF']}" method="post">
+ <table class="config">
+ <tr>
+ <th>Setting</th><th>Current</th>
+ </tr>
+ <tr>
+ <td class="config">LDAP enabled</td>
+ <td class="config">
+ <input name="enable" type="checkbox"$enable/>
+ </td>
+ </tr>
+ <tr>
+ <td class="config">URL</td>
+ <td class="config">
+ <input size="30" name="dns" type="text" value="$dns"/>
+ </td>
+ </tr>
+ <tr>
+ <td class="config">Use TLS</td>
+ <td class="config">
+ <input name="tls" type="checkbox"$tls/>
+ </td>
+ </tr>
+ <tr>
+ <td class="config">Base DN</td>
+ <td class="config">
+ <input size="30" name="base_dn" type="text" value="$base_dn"/>
+ </td>
+ </tr>
+ <tr>
+ <td class="config">User ATTR</td>
+ <td class="config">
+ <input name="user_attr" type="text" value="$user_attr"/>
+ </td>
+ </tr>
+ <tr>
+ <td class="config" colspan="2" style="text-align: center">
+ <input type="submit" name="setting" value="Submit changes"/>
+ </td>
+ </tr>
+ </table>
+ </form>
+ <p>
+ After enabling LDAP users will be authenticated by LDAP and when
+ a user logs on for the first time an account will automatically
+ be created using the username provided by LDAP. If the user
+ account is removed from LDAP the account will be deactivated but
+ remain in webcal until deleted by the admin user.<br/>
+ <br/>
+ If your LDAP server is located here: <span class="bold">ldap.foo.tld
+ </span> on either port
+ 389 or 636 then URL is:<br/>
+ Without SSL (389): <span class="bold">ldap://</span>ldap.foo.tld<br/>
+ With SSL (636): <span class="bold">ldaps://</span>ldap.foo.tld<br/>
+ With TLS (389): <span class="bold">ldap://</span>ldap.foo.tld and
+ <span class="bold">check "Use TLS"</span><br/>
+ If your LDAP server is listen on 8389 then this port number must
+ be added to the URL like ldap://ldap.foo.tld<span class="bold">:8389</span><br/>
+ <br/>
+ If your Bind DN is the following: uid=username,ou=people,dc=foo,
+ dc=tld then "Base DN" and "User ATTR" has to look like this:<br/>
+ Base DN: <span class="bold">ou=people,dc=foo,dc=tld</span><br/>
+ User ATTR: <span class="bold">uid</span><br/>
+ If your Bind DN is the following: cn=username,dc=foo,dc=tld then
+ "Base DN" and "User ATTR" has to look like this:<br/>
+ Base DN: <span class="bold">dc=foo,dc=tld</span><br/>
+ User ATTR: <span class="bold">cn</span>
+ </p>
+__EOF;
+}
+
+include TOP_FOLDER.'/include/header.inc.php';
+include TOP_FOLDER.'/include/menu.inc.php';
+
+print "<div id=\"ui\">$pageView</div>";
+
+include TOP_FOLDER.'/include/footer.inc.php';
+?>
\ No newline at end of file
--- /dev/null
+<?php
+/* $Id$ */
+require_once 'config.inc.php';
+require_once 'user_validate.php';
+require_once 'helper.php';
+
+valid_user();
+
+if (! defined($_SESSION['__ROOT__']) && empty($_SESSION['__ROOT__'])) {
+ if (session_id())
+ session_destroy();
+ header('Location: ' . WEB_ROOT . 'error.html');
+ exit;
+}
+
+if (! has_admin_role()) {
+ if (session_id())
+ session_destroy();
+ header('Location: ' . WEB_ROOT . 'error.html');
+ exit;
+}
+
+require_once 'persistens.php';
+
+include TOP_FOLDER.'/include/header.inc.php';
+include TOP_FOLDER.'/include/menu.inc.php';
+$self =$_SERVER['PHP_SELF'];
+$db = Persistens::getInstance(DBDRIVER);
+
+if (count($_POST) > 0 && isset($_POST['action'])) {
+
+ if (strtolower($_POST['action']) == 'add') {
+ if ($_POST['pwd1'] != $_POST['pwd2']) {
+ $result = "Password does not match";
+ }
+ else {
+ $data = create_user_data(
+ $_POST['uid'], $_POST['pwd1'], $_POST['role']);
+ $result = $db->newUser($data);
+ if ($result === TRUE) {
+ $name = $db->getRoleName((int) $_POST['role']);
+ $result = "{$_POST['uid']} with role: {$name['name']} added";
+ }
+ $result = nl2br($result);
+ }
+ }
+ $pageView .= <<<__EOF
+<p style="text-align: center">
+ $result
+</p>
+__EOF;
+}
+else {
+ $roles = $db->getRoles();
+ $select = '<select name="role">';
+ foreach ($roles as $role) {
+ $select .= "<option value=\"{$role['id']}\">{$role['name']}</option>";
+ }
+ $select .= "</select>";
+ $pageView .= <<<__EOF
+ <form action="$self" method="post" id="new_form">
+ <p>
+ <table class="config">
+ <tr>
+ <th colspan="2" style="text-align: center">New user</th>
+ </tr>
+ <tr>
+ <td class="config">Username</td>
+ <td class="config"><input name="uid" type="text"/></td>
+ </tr>
+ <tr>
+ <td class="config">User role</td>
+ <td class="config">$select</td>
+ </tr>
+ <tr>
+ <td class="config">Password</td>
+ <td class="config"><input name="pwd1" type="password"/></td>
+ </tr>
+ <tr>
+ <td class="config">Repeat Password</td>
+ <td class="config"><input name="pwd2" type="password"/></td>
+ </tr>
+ <tr>
+ <td class="config" colspan="2" style="text-align: center">
+ <input type="submit" name="action" value="Add"/>
+ </td>
+ </tr>
+ </table>
+ </p>
+ </form>
+__EOF;
+}
+
+print "<div id=\"ui\">$pageView</div>";
+
+include TOP_FOLDER.'/include/footer.inc.php';
+
+?>
--- /dev/null
+<?php
+/* $Id$ */
+
+include_once 'config.inc.php';
+require_once 'helper.php';
+
+require_once 'sqlite.php';
+require_once 'pgsql.php';
+
+class DefaultConfig {
+ public $viewStyle;
+ public $timeout;
+ public $startWeek;
+ public $startHour;
+ public $endHour;
+ public $title;
+ public $timezone;
+ public $errorDisplay;
+ public $errorLog;
+ public $logFile;
+ public $topFolder;
+ public $webRoot;
+ public $dns;
+ public $role;
+}
+
+interface WebcalSupport {
+ function getViewStyle($uid);
+ function getTimeout($uid);
+ function getRole($uid);
+ function getStartWeek($uid);
+ function getStartHour($uid);
+ function getEndHour($uid);
+ function getTimezone($uid);
+ function authenticate($uid, $pwd);
+ function createDatabase($name);
+ function initDatabase($name, $pwd, $uid);
+ function addUser($data);
+ function setUserSettings($uid, $data);
+ function deleteUser($uid);
+ function addCalendar($uid, CalendarInfo $calendar);
+ function deleteCalendar($uid, $id);
+ function updateCalendar($uid, $id, CalendarInfo $calendar);
+ function changePassword($uid, $pwd);
+ function getAllUsers($limit, $offset);
+ function getRoles();
+ function getRoleName($id);
+ function changeDefault($data);
+ function getVersion();
+ function execute($sql);
+ function getCalendarConfig($id);
+ function nextTableNumber($name);
+ function getLdapConfig();
+ function setLdapConfig(array $config);
+}
+
+class Persistens {
+
+ private static $instance = NULL;
+ private $con;
+
+ private function __construct($driver, $dns) {
+ $this->con = new $driver($dns);
+ }
+
+ private function __clone() {}
+
+ static function getInstance($db = NULL, $dns = NULL) {
+ if (! self::$instance) {
+ if (! $db)
+ throw new Exception('Missing database driver');
+ switch (strtolower($db)) {
+ case 'sqlite':
+ self::$instance = new Persistens('SQLite', $dns); break;
+ break;
+ case 'pgsql':
+ self::$instance = new Persistens('Pgsql', $dns); break;
+ break;
+ default: throw new Exception("$db: Unsupported driver");
+ }
+ }
+ return self::$instance;
+ }
+
+ function getViewStyle($uid) {
+ return $this->con->getViewStyle($uid);
+ }
+
+ function getStartWeek($uid) {
+ return $this->con->getStartWeek($uid);
+ }
+
+ function getStartHour($uid) {
+ return $this->con->getStartHour($uid);
+ }
+
+ function getEndHour($uid) {
+ return $this->con->getEndHour($uid);
+ }
+
+ function authenticate($uid, $pwd) {
+ return $this->con->authenticate($uid, sha1($pwd));
+ }
+
+ function getTimeout($uid) {
+ return $this->con->getTimeout($uid);
+ }
+
+ function getRole($uid) {
+ return $this->con->getRole($uid);
+ }
+
+ function createDatabase($name) {
+ $this->con->createDatabase($name);
+ }
+
+ function initDatabase($name, $pwd, $uid = 'webcal') {
+ $this->con->initDatabase($name, $pwd, $uid = 'webcal');
+ $this->con = NULL;
+ self::$instance = NULL;
+ }
+
+ function newUser($data) {
+ return $this->con->addUser($data);
+ }
+
+ function setUserSettings($uid, $settings) {
+ return $this->con->setUserSettings($uid, $settings);
+ }
+
+ function deleteUser($uid) {
+ return $this->con->deleteUser($uid);
+ }
+
+ function addCalendar($uid, CalendarInfo $calendar) {
+ return $this->con->addCalendar($uid, $calendar);
+ }
+
+ function deleteCalendar($uid, $id) {
+ return $this->con->deleteCalendar($uid, $id);
+ }
+
+ function updateCalendar($uid, $id, CalendarInfo $calendar) {
+ return $this->con->updateCalendar($uid, $id, $calendar);
+ }
+
+ function changePassword($uid, $pwd) {
+ return $this->con->changePassword($uid, $pwd);
+ }
+
+ function getAllUsers($limit = -1, $offset = 0) {
+ return $this->con->getAllUsers($limit, $offset);
+ }
+
+ function getRoles() {
+ return $this->con->getRoles();
+ }
+
+ function getRoleName($id) {
+ return $this->con->getRoleName($id);
+ }
+
+ function changeDefault($data) {
+ return $this->con->changeDefault($data);
+ }
+
+ function getVersion() {
+ $res = $this->con->getVersion();
+ if (! is_array($res))
+ throw new Exception($res);
+ return $res;
+ }
+
+ function execute($sql) {
+ return $this->con->execute($sql);
+ }
+
+ function getCalendarConfig($id = -1) {
+ return $this->con->getCalendarConfig($id);
+ }
+
+ function nextTableNumber($name) {
+ return $this->con->nextTableNumber($name);
+ }
+
+ function getLdapConfig() {
+ return $this->con->getLdapConfig();
+ }
+
+ function setLdapConfig(array $config) {
+ return $this->con->setLdapConfig($config);
+ }
+
+}
--- /dev/null
+<?php
+/* $Id$ */
+
+include_once 'config.inc.php';
+require_once 'persistens.php';
+require_once 'helper.php';
+
+class Pgsql extends PDO implements WebcalSupport {
+
+ private $user;
+
+ function __construct($dns = NULL) {
+ if ($dns)
+ $db_dns = "pgsql:$dns";
+ else
+ $db_dns = 'pgsql:'.DNS;
+ try {
+ parent::__construct($db_dns);
+ $locale = iconv_get_encoding('internal_encoding');
+ parent::exec("set client_encoding = '$locale'");
+ }
+ catch (PDOException $ex) {
+ throw new Exception($ex->getMessage());
+ }
+ }
+
+ private function getMsg($resource) {
+ $err = $resource->errorInfo();
+ if (count($err) > 2)
+ return $err[2];
+ else
+ return "";
+ }
+
+ function initDatabase($name, $pwd, $uid) {
+ $locale = "select pg_encoding_to_char(encoding) as encoding from pg_database where datname='template0'";
+ $usr = "create user $uid with encrypted password '$pwd'";
+ $init = "create database $name with encoding 'utf8' template template0 owner $uid";
+ try {
+ $sth = $this->prepare($locale);
+ $sth->execute();
+ $res = $sth->fetch();
+ if (strcasecmp($res['encoding'], 'UTF8') !== 0)
+ throw new Exception("Template0 encoding [".$res['encoding']."]. Must be UTF8");
+ $this->exec($usr);
+ $this->exec($init);
+ }
+ catch (PDOException $ex) {
+ throw new Exception($ex->getMessage());
+ }
+ }
+
+ function createDatabase($name) {
+ $sql = "select count(*) as exist from pg_database where datname=?";
+ $sth = $this->prepare($sql);
+ $sth->execute(array($name));
+ $res = $sth->fetch();
+ if ($res['exist'] != 0) {
+ $this->beginTransaction();
+ include_once 'db_create.postgresql.php';
+ $db = make_sql_stm();
+ foreach ($db as $sql) {
+ $sth->closeCursor();
+ $sth = $this->prepare($sql);
+ if (! $sth) {
+ $this->rollBack();
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ throw new Exception($err);
+ }
+ $sth->execute();
+ //throw new Exception(var_export($sth, true));
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $this->rollBack();
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ throw new Exception($err);
+ }
+ }
+ $this->commit();
+ }
+ else
+ throw new Exception("$name: Database does not exist");
+ }
+
+ function getViewStyle($uid) {
+ $sql = "select userview from users u where u.uid = ?";
+ $sth = $this->prepare($sql);
+ $sth->execute(array($uid));
+ $res = $sth->fetch();
+ return $res[0];
+ }
+
+ function getRole($uid) {
+ $sql = "select userrole from users u where u.uid = ?";
+ $sth = $this->prepare($sql);
+ $sth->execute(array($uid));
+ $res = $sth->fetch();
+ return $res[0];
+ }
+
+ function getTimeout($uid) {
+ $sql = "select timeout from users u where u.uid = ?";
+ $sth = $this->prepare($sql);
+ $sth->execute(array($uid));
+ $res = $sth->fetch();
+ return $res[0];
+ }
+
+ function getTimezone($uid) {
+ $sql = "select timezone from users u where u.uid = ?";
+ $sth = $this->prepare($sql);
+ $sth->execute(array($uid));
+ $res = $sth->fetch();
+ return $res[0];
+ }
+
+ function getStartWeek($uid) {
+ $sql = "select weekstart from users u where u.uid = ?";
+ $sth = $this->prepare($sql);
+ $sth->execute(array($uid));
+ $res = $sth->fetch();
+ return ($res[0]) ? 'MO' : 'SU';
+ }
+
+ function getStartHour($uid) {
+ $sql = "select daystart from users u where u.uid = ?";
+ $sth = $this->prepare($sql);
+ $sth->execute(array($uid));
+ $res = $sth->fetch();
+ return $res[0];
+ }
+
+ function getEndHour($uid) {
+ $sql = "select daystart from users u where u.uid = ?";
+ $sth = $this->prepare($sql);
+ $sth->execute(array($uid));
+ $res = $sth->fetch();
+ return $res[0];
+ }
+
+ function authenticate($uid, $pwd) {
+ $res = array();
+ $sql = "select userrole, timeout, userview, weekstart, daystart,
+ dayend, timezone, seckey, pubkey, c.id as id, name, color, config
+ from users u left join calendar c on c.uid = u.id where
+ u.uid = ? and u.pwd = ?";
+ $sth = $this->prepare($sql);
+ if (! $sth) {
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ throw new Exception($err);
+ }
+ $sth->execute(array($uid,$pwd));
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ throw new Exception($err);
+ }
+ $res = $sth->fetchAll(PDO::FETCH_ASSOC);
+
+ /*
+ if ($res[0]['config']) {
+ //$res[0]['config'] = base64_decode($res[0]['config']);
+ //$res[0]['config'] = quoted_printable_decode($res[0]['config']);
+ $res[0]['config'] = $res[0]['config'];
+ }
+ */
+
+ return $res;
+ }
+
+ function addUser($data) {
+ //$fp = fopen('/tmp/davical.log', 'a');
+ //fwrite($fp, "New user\nuid: {$data['uid']}\npwd: {$data['pwd']}\ntimezone: {$data['timezone']}\nuserrole: {$data['userrole']}\nseckey: {$data['seckey']}\npubkey: {$data['pubkey']}");
+ //fclose($fp);
+ $sql = "insert into users (uid, pwd, timezone, userrole, seckey, pubkey, " .
+ "timeout, userview, weekstart, daystart, dayend) values (?,?,?,?,?,?,?,?,?,?,?)";
+ $sth = $this->prepare($sql);
+ if (! $sth) {
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ return $err;
+ }
+ $this->beginTransaction();
+ $sth->execute(array($data['uid'],$data['pwd'],$data['timezone'],
+ $data['userrole'],$data['seckey'],$data['pubkey'],
+ $data['timeout'], $data['view'], ($data['week_start'] == false) ? 0 : 1,
+ $data['start'], $data['end']));
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $this->rollBack();
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ return $err;
+ }
+ $this->commit();
+ return TRUE;
+ }
+
+ function setUserSettings($uid, $data) {
+ $sql = "update users set userrole = ?, timeout = ?, userview = ?,
+ weekstart = ?, daystart = ?, dayend = ?, timezone = ?
+ where uid = ?";
+ $sth = $this->prepare($sql);
+ if (! $sth) {
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ return $err;
+ }
+ $this->beginTransaction();
+ $sth->execute(array($data['userrole'],$data['timeout'],
+ $data['userview'],$data['weekstart'],$data['daystart'],
+ $data['dayend'],$data['timezone'],$uid));
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $this->rollBack();
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ return $err;
+ }
+ $this->commit();
+ return TRUE;
+ }
+
+ function changeDefault($data) {
+ $this->beginTransaction();
+ foreach ($data as $column => $default) {
+ $sql = "alter table users alter $column set default $default";
+ //echo "$sql<br/>";
+ $res = $this->exec($sql);
+ if ($res === FALSE) {
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ $this->rollBack();
+ return $err;
+ }
+ }
+ $this->commit();
+ return TRUE;
+ }
+
+ function deleteUser($uid) {
+ $sql = "delete from users where uid = ?";
+ $sth = $this->prepare($sql);
+ if (! $sth) {
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ return $err;
+ }
+ $this->beginTransaction();
+ $sth->execute(array($uid));
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $this->rollBack();
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ return $err;
+ }
+ $this->commit();
+ return TRUE;
+ }
+
+ function addCalendar($uid, CalendarInfo $cal) {
+ //$fp = fopen('/tmp/add_calender.log', 'a');
+ //fwrite($fp, "New calendar\nUID: $uid\nname: {$cal->name}\nColor: {$cal->color}\nConfig: {$cal->config}\n");
+ $this->beginTransaction();
+ $sql = "select id from users where uid = ?";
+ //fwrite($fp, "Get ID: $sql\n");
+ $sth = $this->prepare($sql);
+ if (! $sth) {
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ $this->rollBack();
+ return $err;
+ }
+ $sth->execute(array($uid));
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ $this->rollBack();
+ return $err;
+ }
+ $sth->bindColumn(1, $id);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ $this->rollBack();
+ return $err;
+ }
+ $sth->fetch(PDO::FETCH_BOUND);
+ //fwrite($fp, "Returned users ID: $id\n");
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ $this->rollBack();
+ return $err;
+ }
+ $sth->closeCursor();
+ $sql = "insert into calendar (uid, name, color, config)
+ values ($id,?,?,?)";
+ //var_dump($sql);
+ //fwrite($fp, "Insert into calendar: $sql\n");
+ $sth = $this->prepare($sql);
+ if (! $sth) {
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ $this->rollBack();
+ return $err;
+ }
+ //$sth->execute(array($cal->name,$cal->color,base64_encode($cal->config)));
+ $sth->execute(array($cal->name, $cal->color, $cal->config));
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ $this->rollBack();
+ return $err;
+ }
+ $sth->closeCursor();
+ $sth = $this->prepare('select max(id) from calendar');
+ $sth->execute();
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ $this->rollBack();
+ return $err;
+ }
+ $sth->bindColumn(1, $id);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ $this->rollBack();
+ return $err;
+ }
+ $sth->fetch(PDO::FETCH_BOUND);
+ //fwrite($fp, "Returned ID for created calendar: $id\n");
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ $this->rollBack();
+ return $err;
+ }
+ $sth->closeCursor();
+ $this->commit();
+/* $sql = "select * from calendar where id = $id";
+ $sth = $this->prepare($sql);
+ $sth->execute();
+ $result = $sth->fetchAll(PDO::FETCH_ASSOC);
+ if ($result)
+ fwrite($fp, var_export($result[0], TRUE) . "\n");
+ else
+ fwrite($fp, "No date found in calendar relation\n");
+ fclose($fp);*/
+ return $id;
+ }
+
+ function deleteCalendar($uid, $id) {
+ $this->beginTransaction();
+ $sql = "select id from users where uid = ?";
+ $sth = $this->prepare($sql);
+ if (! $sth) {
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ $this->rollBack();
+ return $err;
+ }
+ $sth->execute(array($uid));
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ $this->rollBack();
+ return $err;
+ }
+ $sth->bindColumn(1, $uid);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ $this->rollBack();
+ return $err;
+ }
+ $sth->fetch(PDO::FETCH_BOUND);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ $this->rollBack();
+ return $err;
+ }
+ $sth->closeCursor();
+ $sql = "delete from calendar where id = ? and uid = $uid";
+ $sth = $this->prepare($sql);
+ if (! $sth) {
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ $this->rollBack();
+ return $err;
+ }
+ $sth->execute(array($id));
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ $this->rollBack();
+ return $err;
+ }
+ $this->commit();
+ return TRUE;
+ }
+
+ function updateCalendar($uid, $id, CalendarInfo $cal) {
+ //echo "$uid:$id:".var_export($cal,true)."<br/>";
+ $this->beginTransaction();
+ $sql = "select id from users where uid = ?";
+ $sth = $this->prepare($sql);
+ if (! $sth) {
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ $this->rollBack();
+ return $err;
+ }
+ $sth->execute(array($uid));
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ $this->rollBack();
+ return $err;
+ }
+ $sth->bindColumn(1, $uid);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ $this->rollBack();
+ return $err;
+ }
+ $sth->fetch(PDO::FETCH_BOUND);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ $this->rollBack();
+ return $err;
+ }
+ $sth->closeCursor();
+ $sql = "update calendar set name = ?, color = ?, config = ?
+ where id = ? and uid = $uid";
+ $sth = $this->prepare($sql);
+ if (! $sth) {
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ $this->rollBack();
+ return $err;
+ }
+ //$sth->execute(array($cal->name,$cal->color,base64_encode($cal->config),$id));
+ $sth->execute(array($cal->name,$cal->color, $cal->config,$id));
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ $this->rollBack();
+ return $err;
+ }
+ $this->commit();
+ return TRUE;
+ }
+
+ function changePassword($uid, $pwd) {
+ $this->beginTransaction();
+ $sql = "update users set pwd = ? where uid = ?";
+ $sth = $this->prepare($sql);
+ if (! $sth) {
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ return $err;
+ }
+ $sth->execute(array($pwd,$uid));
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $this->rollBack();
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ return $err;
+ }
+ $this->commit();
+ return TRUE;
+ }
+
+ function getAllUsers($limit, $offset) {
+ if ($limit == -1) {
+ $sql = "select u.uid, r.name as userrole from users u, roles r
+ where u.userrole = r.id limit all offset ?";
+ }
+ else {
+ $sql = "select u.uid, r.name as userrole from users u, roles r
+ where u.userrole = r.id limit ? offset ?";
+ }
+ $sth = $this->prepare($sql);
+ if (! $sth) {
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ return $err;
+ }
+ if ($limit == -1)
+ $sth->execute(array($offset));
+ else
+ $sth->execute(array($limit,$offset));
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ return $err;
+ }
+ return $sth->fetchAll(PDO::FETCH_ASSOC);
+ }
+
+ function getRoles() {
+ $sql = "select id, name from roles order by id desc";
+ $sth = $this->prepare($sql);
+ if (! $sth) {
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ return $err;
+ }
+ $sth->execute();
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ return $err;
+ }
+ return $sth->fetchAll(PDO::FETCH_ASSOC);
+ }
+
+ function getRoleName($id) {
+ $sql = "select name from roles where id = ?";
+ $sth = $this->prepare($sql);
+ if (! $sth) {
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ return $err;
+ }
+ $sth->execute(array($id));
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ return $err;
+ }
+ return $sth->fetch(PDO::FETCH_ASSOC);
+ }
+
+ function getVersion() {
+ $version = array('version' => 0);
+ $sql = "select count(*) as exist from pg_tables where tablename = 'about'";
+ $sth = $this->prepare($sql);
+ if (! $sth) {
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ return $err;
+ }
+ $sth->execute();
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ return $err;
+ }
+ $res = $sth->fetch();
+ if ($res['exist'] > 0) {
+ $sql = "select version from about where id = 1";
+ $sth = $this->prepare($sql);
+ if (! $sth) {
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ return $err;
+ }
+ $sth->execute();
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ return $err;
+ }
+ $res = $sth->fetch();
+ $version = $res;
+ }
+ return $version;
+ }
+
+ function execute($sql) {
+ $sth = $this->prepare($sql);
+ if (! $sth) {
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ return $err;
+ }
+ $sth->execute();
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ return $err;
+ }
+ return true;
+ }
+
+ function getCalendarConfig($id) {
+ if ($id == -1) {
+ $sql = "select id, config from calendar";
+ }
+ else {
+ $sql = "select id, config from calendar where id = ?";
+ }
+ $sth = $this->prepare($sql);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ $sth->execute(array($id));
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ return $sth->fetchAll(PDO::FETCH_ASSOC);
+ }
+
+ function nextTableNumber($name) {
+ $sql = "select count(*) as found from pg_tables where tableowner = 'webcal' " .
+ "and tablename like ?";
+ $sth = $this->prepare($sql);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ $sth->execute(array($name . '%'));
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ $res = $sth->fetch(PDO::FETCH_ASSOC);
+ return $res['found'];
+ }
+
+ function getLdapConfig() {
+ $sql = "select enable, dns, tls, base_dn, user_attr from ldap";
+ $sth = $this->prepare($sql);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ $sth->execute();
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ return $sth->fetch(PDO::FETCH_ASSOC);
+ }
+
+ function setLdapConfig(array $config) {
+ $old_config = $this->getLdapConfig();
+ if (! is_array($old_config) && $old_config)
+ return $old_config;
+ else if (is_array($old_config))
+ $sql = "update ldap set enable=?, dns=?, tls=?, base_dn=?, user_attr=?";
+ else
+ $sql = "insert into ldap values(?, ?, ?, ?, ?)";
+ $this->beginTransaction();
+ $sth = $this->prepare($sql);
+ if (! $sth) {
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ $this->rollBack();
+ return $err;
+ }
+ $sth->execute($config);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $this->rollBack();
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ return $err;
+ }
+ $this->commit();
+ return true;
+ }
+
+}
--- /dev/null
+<?php
+/* $Id$ */
+
+include_once 'config.inc.php';
+require_once 'persistens.php';
+require_once 'helper.php';
+
+class SQLite extends PDO implements WebcalSupport {
+
+ function __construct($dns = NULL) {
+ if ($dns) {
+ $db_dns = "sqlite:$dns";
+ }
+ else {
+ $db_dns = 'sqlite:'.TOP_FOLDER.'/'.DNS;
+ }
+ try {
+ parent::__construct($db_dns, 0600);
+ parent::exec("PRAGMA foreign_keys = OFF");
+ //parent::setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+ //parent::setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
+ }
+ catch (PDOException $ex) {
+ throw new Exception($ex->getMessage());
+ }
+ }
+
+ private function getMsg($resource) {
+ $err = $resource->errorInfo();
+ if (count($err) > 2)
+ return $err[2];
+ else
+ return "";
+ }
+
+ function initDatabase($name, $pwd, $uid) {
+ }
+
+ function createDatabase($name) {
+ $sql = "select count(*) as found from sqlite_master where
+ type = 'table' and name = 'user'";
+ $sth = $this->prepare($sql);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ throw new Exception($err);
+ }
+ $sth->execute();
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ throw new Exception($err);
+ }
+ $res = $sth->fetch();
+ if ($res['found'] == 0) {
+ $this->beginTransaction();
+ include 'db_create.sqlite.php';
+ $db = make_sql_stm();
+ foreach ($db as $sql) {
+ $sth->closeCursor();
+ $sth = $this->prepare($sql);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $this->rollBack();
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ throw new Exception($err);
+ }
+ $sth->execute();
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $this->rollBack();
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ throw new Exception($err);
+ }
+ }
+ $this->commit();
+ }
+ else
+ throw new Exception("Database exists");
+ }
+
+ function getViewStyle($uid) {
+ $sql = "select userview from user u where u.uid = ?";
+ $sth = $this->prepare($sql);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ $sth->execute(array($uid));
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ $res = $sth->fetch();
+ return $res[0];
+ }
+
+ function getRole($uid) {
+ $sql = "select userrole from user u where u.uid = ?";
+ $sth = $this->prepare($sql);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ $sth->execute(array($uid));
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ $res = $sth->fetch();
+ return $res[0];
+ }
+
+ function getTimeout($uid) {
+ $sql = "select timeout from user u where u.uid = ?";
+ $sth = $this->prepare($sql);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ $sth->execute(array($uid));
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ $res = $sth->fetch();
+ return $res[0];
+ }
+
+ function getTimezone($uid) {
+ $sql = "select timezone from user u where u.uid = ?";
+ $sth = $this->prepare($sql);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ $sth->execute(array($uid));
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ $res = $sth->fetch();
+ return $res[0];
+ }
+
+ function getStartWeek($uid) {
+ $sql = "select weekstart from user u where u.uid = ?";
+ $sth = $this->prepare($sql);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ $sth->execute(array($uid));
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ $res = $sth->fetch();
+ return ($res[0]) ? 'MO' : 'SU';
+ }
+
+ function getStartHour($uid) {
+ $sql = "select daystart from user u where u.uid = ?";
+ $sth = $this->prepare($sql);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ $sth->execute(array($uid));
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ $res = $sth->fetch();
+ return $res[0];
+ }
+
+ function getEndHour($uid) {
+ $sql = "select daystart from user u where u.uid = ?";
+ $sth = $this->prepare($sql);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ $sth->execute(array($uid));
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ $res = $sth->fetch();
+ return $res[0];
+ }
+
+ function authenticate($uid, $pwd) {
+ $res = array();
+ $sql = "select userrole, timeout, userview, weekstart, daystart,
+ dayend, timezone, seckey, pubkey, c.id id, name, color, config
+ from user u left join calendar c on c.uid = u.id where
+ u.uid = ? and u.pwd = ?";
+ $sth = $this->prepare($sql);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ throw new Exception($err);
+ }
+ $sth->execute(array($uid,$pwd));
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ throw new Exception($err);
+ }
+ $res = $sth->fetchAll(PDO::FETCH_ASSOC);
+ return $res;
+ }
+
+ function addUser($data) {
+ $sql = "insert into user (uid, pwd, timezone, userrole, seckey, pubkey, " .
+ "timeout, userview, weekstart, daystart, dayend) values (?,?,?,?,?,?,?,?,?,?,?)";
+ $sth = $this->prepare($sql);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ $this->beginTransaction();
+ $sth->execute(array($data['uid'],$data['pwd'],$data['timezone'],
+ $data['userrole'],$data['seckey'],$data['pubkey'],
+ $data['timeout'], $data['view'], ($data['week_start'] == false) ? 0 : 1,
+ $data['start'], $data['end']));
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $this->rollBack();
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ $this->commit();
+ return TRUE;
+ }
+
+ function setUserSettings($uid, $data) {
+ $sql = "update user set userrole = ?, timeout = ?, userview = ?,
+ weekstart = ?, daystart = ?, dayend = ?, timezone = ?
+ where uid = ?";
+ $sth = $this->prepare($sql);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ $this->beginTransaction();
+ $sth->execute(array($data['userrole'],$data['timeout'],
+ $data['userview'],$data['weekstart'],$data['daystart'],
+ $data['dayend'],$data['timezone'],$uid));
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $this->rollBack();
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ $this->commit();
+ return TRUE;
+ }
+/*
+timeout integer default 3600,
+userview text default 'week',
+weekstart integer default 0,
+daystart real default 8.00,
+dayend real default 17.00,
+timezone text default 'Etc/UTC',
+*/
+ function changeDefault($data) {
+ $temp = <<<_TEMP
+ CREATE TEMPORARY TABLE tmpuser (
+ id integer,
+ uid text,
+ pwd text,
+ userrole integer,
+ timeout integer,
+ userview text,
+ weekstart integer,
+ daystart real,
+ dayend real,
+ timezone text,
+ seckey text,
+ pubkey text
+ )
+_TEMP;
+ $table = <<<_TABLE
+ CREATE TABLE user (
+ id integer primary key autoincrement,
+ uid text not null,
+ pwd text not null,
+ userrole integer not null,
+ timeout integer default __TIMEOUT__,
+ userview text default '__VIEW__',
+ weekstart integer default __WEEKSTART__,
+ daystart real default __DAYSTART__,
+ dayend real default __DAYEND__,
+ timezone text default '__TIMEZONE__',
+ seckey text default '',
+ pubkey text default '',
+ constraint uid_index unique (uid)
+ constraint userrole_fk foreign key (userrole) references roles (id)
+ on delete restrict
+ on update cascade
+ on insert cascade
+ )
+_TABLE;
+ $table = str_replace('__TIMEOUT__', $data['TIMEOUT'], $table);
+ $table = str_replace('__VIEW__', $data['VIEW_STYLE'], $table);
+ $table = str_replace('__WEEKSTART__', $data['WEEK_START_SUNDAY'], $table);
+ $table = str_replace('__DAYSTART__', $data['START_HOUR'], $table);
+ $table = str_replace('__DAYEND__', $data['END_HOUR'], $table);
+ $table = str_replace('__TIMEZONE__', $data['TIMEZONE'], $table);
+ $this->beginTransaction();
+ if ($this->exec($temp) === FALSE) {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ $this->rollBack();
+ return $err;
+ }
+ if ($this->exec('insert into tmpuser select * from user') === FALSE) {
+ $err = "cp to tmp table\n";
+ $err .= $this->getMsg($this)."\n";
+ $this->rollBack();
+ return $err;
+ }
+ if ($this->exec('drop table user') === FALSE) {
+ $err = "drop user table\n";
+ $err .= $this->getMsg($this)."\n";
+ $this->rollBack();
+ return $err;
+ }
+ if ($this->exec($table) === FALSE) {
+ $err = "create table\n";
+ $err .= $this->getMsg($this)."\n";
+ $this->rollBack();
+ return $err;
+ }
+ if ($this->exec('insert into user select * from tmpuser') === FALSE) {
+ $err = "cp tmp to user table\n";
+ $err .= $this->getMsg($this)."\n";
+ $this->rollBack();
+ return $err;
+ }
+ if ($this->exec('drop table tmpuser') === FALSE) {
+ $err = "drop user table\n";
+ $err .= $this->getMsg($this)."\n";
+ $this->rollBack();
+ return $err;
+ }
+ $this->commit();
+ return TRUE;
+ }
+
+ function deleteUser($uid) {
+ $sql = "delete from user where uid = ?";
+ $sth = $this->prepare($sql);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ $this->beginTransaction();
+ $sth->execute(array($uid));
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $this->rollBack();
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ $this->commit();
+ return TRUE;
+ }
+
+ function addCalendar($uid, CalendarInfo $cal) {
+ //$fp = fopen('/tmp/add_calender.log', 'a');
+ //fwrite($fp, "New calendar\nUID: $uid\nname: {$cal->name}\nColor: {$cal->color}\nConfig: {$cal->config}\n");
+ $this->beginTransaction();
+ $sql = "select id from user where uid = ?";
+ //fwrite($fp, "Get ID: $sql\n");
+ $sth = $this->prepare($sql);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ $this->rollBack();
+ return $err;
+ }
+ $sth->execute(array($uid));
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ $this->rollBack();
+ return $err;
+ }
+ $sth->bindColumn(1, $id);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ $this->rollBack();
+ return $err;
+ }
+ $sth->fetch(PDO::FETCH_BOUND);
+ //fwrite($fp, "Returned user ID: $id\n");
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ $this->rollBack();
+ return $err;
+ }
+ $sth->closeCursor();
+ $sql = "insert into calendar (uid, name, color, config)
+ values ($id,?,?,?)";
+ //var_dump($sql);
+ //fwrite($fp, "Insert into calendar: $sql\n");
+ $sth = $this->prepare($sql);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ $this->rollBack();
+ return $err;
+ }
+ $sth->execute(array($cal->name,$cal->color,$cal->config));
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ $this->rollBack();
+ return $err;
+ }
+ $sth->closeCursor();
+ $sth = $this->prepare('select max(id) from calendar');
+ $sth->execute();
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ $this->rollBack();
+ return $err;
+ }
+ $sth->bindColumn(1, $id);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ $this->rollBack();
+ return $err;
+ }
+ $sth->fetch(PDO::FETCH_BOUND);
+ //fwrite($fp, "Returned ID for created calendar: $id\n");
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ $this->rollBack();
+ return $err;
+ }
+ $sth->closeCursor();
+ $this->commit();
+/* $sql = "select * from calendar where id = $id";
+ $sth = $this->prepare($sql);
+ $sth->execute();
+ $result = $sth->fetchAll(PDO::FETCH_ASSOC);
+ if ($result)
+ fwrite($fp, var_export($result[0], TRUE) . "\n");
+ else
+ fwrite($fp, "No date found in calendar relation\n");
+ fclose($fp);*/
+ return $id;
+ }
+
+ function deleteCalendar($uid, $id) {
+ $this->beginTransaction();
+ $sql = "select id from user where uid = ?";
+ $sth = $this->prepare($sql);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ $this->rollBack();
+ return $err;
+ }
+ $sth->execute(array($uid));
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ $this->rollBack();
+ return $err;
+ }
+ $sth->bindColumn(1, $uid);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ $this->rollBack();
+ return $err;
+ }
+ $sth->fetch(PDO::FETCH_BOUND);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ $this->rollBack();
+ return $err;
+ }
+ $sth->closeCursor();
+ $sql = "delete from calendar where id = ? and uid = $uid";
+ $sth = $this->prepare($sql);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ $this->rollBack();
+ return $err;
+ }
+ $sth->execute(array($id));
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ $this->rollBack();
+ return $err;
+ }
+ $this->commit();
+ return TRUE;
+ }
+
+ function updateCalendar($uid, $id, CalendarInfo $cal) {
+ $this->beginTransaction();
+ $sql = "select id from user where uid = ?";
+ $sth = $this->prepare($sql);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ $this->rollBack();
+ return $err;
+ }
+ $sth->execute(array($uid));
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ $this->rollBack();
+ return $err;
+ }
+ $sth->bindColumn(1, $uid);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ $this->rollBack();
+ return $err;
+ }
+ $sth->fetch(PDO::FETCH_BOUND);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ $this->rollBack();
+ return $err;
+ }
+ $sth->closeCursor();
+ $sql = "update calendar set name = ?, color = ?, config = ?
+ where id = ? and uid = $uid";
+ $sth = $this->prepare($sql);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ $this->rollBack();
+ return $err;
+ }
+ $sth->execute(array($cal->name,$cal->color,$cal->config,$id));
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ $this->rollBack();
+ return $err;
+ }
+ $this->commit();
+ return TRUE;
+ }
+
+ function changePassword($uid, $pwd) {
+ $this->beginTransaction();
+ $sql = "update user set pwd = ? where uid = ?";
+ $sth = $this->prepare($sql);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ $sth->execute(array($pwd,$uid));
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $this->rollBack();
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ $this->commit();
+ return TRUE;
+ }
+
+ function getAllUsers($limit, $offset) {
+ $sql = "select u.uid, r.name as userrole from user u, roles r
+ where u.userrole = r.id limit ? offset ?";
+ $sth = $this->prepare($sql);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ $sth->execute(array($limit,$offset));
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ return $sth->fetchAll(PDO::FETCH_ASSOC);
+ }
+
+ function getRoles() {
+ $sql = "select id, name from roles order by id desc";
+ $sth = $this->prepare($sql);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ $sth->execute();
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ return $sth->fetchAll(PDO::FETCH_ASSOC);
+ }
+
+ function getRoleName($id) {
+ $sql = "select name from roles where id = ?";
+ $sth = $this->prepare($sql);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ $sth->execute(array($id));
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ return $sth->fetch(PDO::FETCH_ASSOC);
+ }
+
+ function getVersion() {
+ $version = array('version' => 0);
+ $sql = "select count(*) as exist from sqlite_master where
+ type = 'table' and tbl_name = 'about'";
+ $sth = $this->prepare($sql);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ $sth->execute();
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ $res = $sth->fetch();
+ if ($res['exist'] > 0) {
+ $sql = "select version from about where id = 1";
+ $sth = $this->prepare($sql);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ $sth->execute();
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ $res = $sth->fetch();
+ $version = $res;
+ }
+ return $version;
+ }
+
+ function execute($sql) {
+ $sth = $this->prepare($sql);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ $sth->execute();
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ return true;
+ }
+
+ function getCalendarConfig($id) {
+ if ($id == -1) {
+ $sql = "select id, config from calendar";
+ }
+ else {
+ $sql = "select id, config from calendar where id = ?";
+ }
+ $sth = $this->prepare($sql);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ $sth->execute(array($id));
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ return $sth->fetchAll(PDO::FETCH_ASSOC);
+ }
+
+ function nextTableNumber($name) {
+ $sql = "select count(*) as found from sqlite_master where " .
+ "type = 'table' and name like ?";
+ $sth = $this->prepare($sql);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ $sth->execute(array($name . '%'));
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ $res = $sth->fetch(PDO::FETCH_ASSOC);
+ return $res['found'];
+ }
+
+ function getLdapConfig() {
+ $sql = "select enable, dns, tls, base_dn, user_attr from ldap";
+ $sth = $this->prepare($sql);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ $sth->execute();
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $err = "$sql\n";
+ $err .= $this->getMsg($sth)."\n";
+ return $err;
+ }
+ return $sth->fetch(PDO::FETCH_ASSOC);
+ }
+
+ function setLdapConfig(array $config) {
+ $old_config = $this->getLdapConfig();
+ if (! is_array($old_config) && $old_config)
+ return $old_config;
+ else if (is_array($old_config))
+ $sql = "update ldap set enable=?, dns=?, tls=?, base_dn=?, user_attr=?";
+ else
+ $sql = "insert into ldap values(?, ?, ?, ?, ?)";
+ $this->beginTransaction();
+ $sth = $this->prepare($sql);
+ if (! $sth) {
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ $this->rollBack();
+ return $err;
+ }
+ $sth->execute($config);
+ if ($sth->errorCode() && $sth->errorCode() != '00000') {
+ $this->rollBack();
+ $err = "$sql\n";
+ foreach ($this->errorInfo() as $info)
+ $err .= "$info\n";
+ return $err;
+ }
+ $this->commit();
+ return true;
+ }
+
+}
--- /dev/null
+<?php
+/* $Id$ */
+
+$timezones = array(
+ "Africa/Abidjan",
+ "Africa/Accra",
+ "Africa/Addis_Ababa",
+ "Africa/Algiers",
+ "Africa/Asmara",
+ "Africa/Asmera",
+ "Africa/Bamako",
+ "Africa/Bangui",
+ "Africa/Banjul",
+ "Africa/Bissau",
+ "Africa/Blantyre",
+ "Africa/Brazzaville",
+ "Africa/Bujumbura",
+ "Africa/Cairo",
+ "Africa/Casablanca",
+ "Africa/Ceuta",
+ "Africa/Conakry",
+ "Africa/Dakar",
+ "Africa/Dar_es_Salaam",
+ "Africa/Djibouti",
+ "Africa/Douala",
+ "Africa/El_Aaiun",
+ "Africa/Freetown",
+ "Africa/Gaborone",
+ "Africa/Harare",
+ "Africa/Johannesburg",
+ "Africa/Kampala",
+ "Africa/Khartoum",
+ "Africa/Kigali",
+ "Africa/Kinshasa",
+ "Africa/Lagos",
+ "Africa/Libreville",
+ "Africa/Lome",
+ "Africa/Luanda",
+ "Africa/Lubumbashi",
+ "Africa/Lusaka",
+ "Africa/Malabo",
+ "Africa/Maputo",
+ "Africa/Maseru",
+ "Africa/Mbabane",
+ "Africa/Mogadishu",
+ "Africa/Monrovia",
+ "Africa/Nairobi",
+ "Africa/Ndjamena",
+ "Africa/Niamey",
+ "Africa/Nouakchott",
+ "Africa/Ouagadougou",
+ "Africa/Sao_Tome",
+ "Africa/Timbuktu",
+ "Africa/Tripoli",
+ "Africa/Tunis",
+ "Africa/Windhoek",
+ "America/Adak",
+ "America/Anchorage",
+ "America/Anguilla",
+ "America/Antigua",
+ "America/Araguaina",
+ "America/Aruba",
+ "America/Asuncion",
+ "America/Atikokan",
+ "America/Atka",
+ "America/Bahia",
+ "America/Barbados",
+ "America/Belem",
+ "America/Belize",
+ "America/Boa_Vista",
+ "America/Bogota",
+ "America/Boise",
+ "America/Buenos_Aires",
+ "America/Cambridge_Bay",
+ "America/Campo_Grande",
+ "America/Cancun",
+ "America/Caracas",
+ "America/Catamarca",
+ "America/Cayenne",
+ "America/Cayman",
+ "America/Chicago",
+ "America/Chihuahua",
+ "America/Coral_Harbour",
+ "America/Cordoba",
+ "America/Costa_Rica",
+ "America/Cuiaba",
+ "America/Curacao",
+ "America/Danmarkshavn",
+ "America/Dawson",
+ "America/Dawson_Creek",
+ "America/Denver",
+ "America/Detroit",
+ "America/Dominica",
+ "America/Edmonton",
+ "America/Eirunepe",
+ "America/El_Salvador",
+ "America/Ensenada",
+ "America/Fort_Wayne",
+ "America/Fortaleza",
+ "America/Glace_Bay",
+ "America/Godthab",
+ "America/Goose_Bay",
+ "America/Grand_Turk",
+ "America/Grenada",
+ "America/Guadeloupe",
+ "America/Guatemala",
+ "America/Guayaquil",
+ "America/Guyana",
+ "America/Halifax",
+ "America/Havana",
+ "America/Hermosillo",
+ "America/Indianapolis",
+ "America/Inuvik",
+ "America/Iqaluit",
+ "America/Jamaica",
+ "America/Jujuy",
+ "America/Juneau",
+ "America/Knox_IN",
+ "America/La_Paz",
+ "America/Lima",
+ "America/Los_Angeles",
+ "America/Louisville",
+ "America/Maceio",
+ "America/Managua",
+ "America/Manaus",
+ "America/Marigot",
+ "America/Martinique",
+ "America/Mazatlan",
+ "America/Mendoza",
+ "America/Menominee",
+ "America/Merida",
+ "America/Mexico_City",
+ "America/Miquelon",
+ "America/Moncton",
+ "America/Monterrey",
+ "America/Montevideo",
+ "America/Montreal",
+ "America/Montserrat",
+ "America/Nassau",
+ "America/New_York",
+ "America/Nipigon",
+ "America/Nome",
+ "America/Noronha",
+ "America/Panama",
+ "America/Pangnirtung",
+ "America/Paramaribo",
+ "America/Phoenix",
+ "America/Port_of_Spain",
+ "America/Porto_Acre",
+ "America/Porto_Velho",
+ "America/Puerto_Rico",
+ "America/Rainy_River",
+ "America/Rankin_Inlet",
+ "America/Recife",
+ "America/Regina",
+ "America/Resolute",
+ "America/Rio_Branco",
+ "America/Rosario",
+ "America/Santarem",
+ "America/Santiago",
+ "America/Santo_Domingo",
+ "America/Sao_Paulo",
+ "America/Scoresbysund",
+ "America/Shiprock",
+ "America/St_Barthelemy",
+ "America/St_Johns",
+ "America/St_Kitts",
+ "America/St_Lucia",
+ "America/St_Thomas",
+ "America/St_Vincent",
+ "America/Swift_Current",
+ "America/Tegucigalpa",
+ "America/Thule",
+ "America/Thunder_Bay",
+ "America/Tijuana",
+ "America/Toronto",
+ "America/Tortola",
+ "America/Vancouver",
+ "America/Virgin",
+ "America/Whitehorse",
+ "America/Winnipeg",
+ "America/Yakutat",
+ "America/Yellowknife",
+ "Antarctica/Casey",
+ "Antarctica/Davis",
+ "Antarctica/DumontDUrville",
+ "Antarctica/Mawson",
+ "Antarctica/McMurdo",
+ "Antarctica/Palmer",
+ "Antarctica/Rothera",
+ "Antarctica/South_Pole",
+ "Antarctica/Syowa",
+ "Antarctica/Vostok",
+ "Arctic/Longyearbyen",
+ "Asia/Aden",
+ "Asia/Almaty",
+ "Asia/Amman",
+ "Asia/Anadyr",
+ "Asia/Aqtau",
+ "Asia/Aqtobe",
+ "Asia/Ashgabat",
+ "Asia/Ashkhabad",
+ "Asia/Baghdad",
+ "Asia/Bahrain",
+ "Asia/Baku",
+ "Asia/Bangkok",
+ "Asia/Beirut",
+ "Asia/Bishkek",
+ "Asia/Brunei",
+ "Asia/Calcutta",
+ "Asia/Choibalsan",
+ "Asia/Chongqing",
+ "Asia/Chungking",
+ "Asia/Colombo",
+ "Asia/Dacca",
+ "Asia/Damascus",
+ "Asia/Dhaka",
+ "Asia/Dili",
+ "Asia/Dubai",
+ "Asia/Dushanbe",
+ "Asia/Gaza",
+ "Asia/Harbin",
+ "Asia/Ho_Chi_Minh",
+ "Asia/Hong_Kong",
+ "Asia/Hovd",
+ "Asia/Irkutsk",
+ "Asia/Istanbul",
+ "Asia/Jakarta",
+ "Asia/Jayapura",
+ "Asia/Jerusalem",
+ "Asia/Kabul",
+ "Asia/Kamchatka",
+ "Asia/Karachi",
+ "Asia/Kashgar",
+ "Asia/Kathmandu",
+ "Asia/Katmandu",
+ "Asia/Kolkata",
+ "Asia/Krasnoyarsk",
+ "Asia/Kuala_Lumpur",
+ "Asia/Kuching",
+ "Asia/Kuwait",
+ "Asia/Macao",
+ "Asia/Macau",
+ "Asia/Magadan",
+ "Asia/Makassar",
+ "Asia/Manila",
+ "Asia/Muscat",
+ "Asia/Nicosia",
+ "Asia/Novosibirsk",
+ "Asia/Omsk",
+ "Asia/Oral",
+ "Asia/Phnom_Penh",
+ "Asia/Pontianak",
+ "Asia/Pyongyang",
+ "Asia/Qatar",
+ "Asia/Qyzylorda",
+ "Asia/Rangoon",
+ "Asia/Riyadh",
+ "Asia/Saigon",
+ "Asia/Sakhalin",
+ "Asia/Samarkand",
+ "Asia/Seoul",
+ "Asia/Shanghai",
+ "Asia/Singapore",
+ "Asia/Taipei",
+ "Asia/Tashkent",
+ "Asia/Tbilisi",
+ "Asia/Tehran",
+ "Asia/Tel_Aviv",
+ "Asia/Thimbu",
+ "Asia/Thimphu",
+ "Asia/Tokyo",
+ "Asia/Ujung_Pandang",
+ "Asia/Ulaanbaatar",
+ "Asia/Ulan_Bator",
+ "Asia/Urumqi",
+ "Asia/Vientiane",
+ "Asia/Vladivostok",
+ "Asia/Yakutsk",
+ "Asia/Yekaterinburg",
+ "Asia/Yerevan",
+ "Atlantic/Azores",
+ "Atlantic/Bermuda",
+ "Atlantic/Canary",
+ "Atlantic/Cape_Verde",
+ "Atlantic/Faeroe",
+ "Atlantic/Faroe",
+ "Atlantic/Jan_Mayen",
+ "Atlantic/Madeira",
+ "Atlantic/Reykjavik",
+ "Atlantic/South_Georgia",
+ "Atlantic/St_Helena",
+ "Atlantic/Stanley",
+ "Australia/ACT",
+ "Australia/Adelaide",
+ "Australia/Brisbane",
+ "Australia/Broken_Hill",
+ "Australia/Canberra",
+ "Australia/Currie",
+ "Australia/Darwin",
+ "Australia/Eucla",
+ "Australia/Hobart",
+ "Australia/LHI",
+ "Australia/Lindeman",
+ "Australia/Lord_Howe",
+ "Australia/Melbourne",
+ "Australia/North",
+ "Australia/NSW",
+ "Australia/Perth",
+ "Australia/Queensland",
+ "Australia/South",
+ "Australia/Sydney",
+ "Australia/Tasmania",
+ "Australia/Victoria",
+ "Australia/West",
+ "Australia/Yancowinna",
+ "Brazil/Acre",
+ "Brazil/DeNoronha",
+ "Brazil/East",
+ "Brazil/West",
+ "Canada/Atlantic",
+ "Canada/Central",
+ "Canada/Eastern",
+ "Canada/Mountain",
+ "Canada/Newfoundland",
+ "Canada/Pacific",
+ "Canada/Saskatchewan",
+ "Canada/Yukon",
+ "CET",
+ "Chile/Continental",
+ "Chile/EasterIsland",
+ "CST6CDT",
+ "Cuba",
+ "EET",
+ "Egypt",
+ "Eire",
+ "EST",
+ "EST5EDT",
+ "Etc/GMT",
+ "Etc/GMT0",
+ "Etc/Greenwich",
+ "Etc/UCT",
+ "Etc/Universal",
+ "Etc/UTC",
+ "Etc/Zulu",
+ "Europe/Amsterdam",
+ "Europe/Andorra",
+ "Europe/Athens",
+ "Europe/Belfast",
+ "Europe/Belgrade",
+ "Europe/Berlin",
+ "Europe/Bratislava",
+ "Europe/Brussels",
+ "Europe/Bucharest",
+ "Europe/Budapest",
+ "Europe/Chisinau",
+ "Europe/Copenhagen",
+ "Europe/Dublin",
+ "Europe/Gibraltar",
+ "Europe/Guernsey",
+ "Europe/Helsinki",
+ "Europe/Isle_of_Man",
+ "Europe/Istanbul",
+ "Europe/Jersey",
+ "Europe/Kaliningrad",
+ "Europe/Kiev",
+ "Europe/Lisbon",
+ "Europe/Ljubljana",
+ "Europe/London",
+ "Europe/Luxembourg",
+ "Europe/Madrid",
+ "Europe/Malta",
+ "Europe/Mariehamn",
+ "Europe/Minsk",
+ "Europe/Monaco",
+ "Europe/Moscow",
+ "Europe/Nicosia",
+ "Europe/Oslo",
+ "Europe/Paris",
+ "Europe/Podgorica",
+ "Europe/Prague",
+ "Europe/Riga",
+ "Europe/Rome",
+ "Europe/Samara",
+ "Europe/San_Marino",
+ "Europe/Sarajevo",
+ "Europe/Simferopol",
+ "Europe/Skopje",
+ "Europe/Sofia",
+ "Europe/Stockholm",
+ "Europe/Tallinn",
+ "Europe/Tirane",
+ "Europe/Tiraspol",
+ "Europe/Uzhgorod",
+ "Europe/Vaduz",
+ "Europe/Vatican",
+ "Europe/Vienna",
+ "Europe/Vilnius",
+ "Europe/Volgograd",
+ "Europe/Warsaw",
+ "Europe/Zagreb",
+ "Europe/Zaporozhye",
+ "Europe/Zurich",
+ "Factory",
+ "GB",
+ "GMT",
+ "GMT0",
+ "Greenwich",
+ "Hongkong",
+ "HST",
+ "Iceland",
+ "Indian/Antananarivo",
+ "Indian/Chagos",
+ "Indian/Christmas",
+ "Indian/Cocos",
+ "Indian/Comoro",
+ "Indian/Kerguelen",
+ "Indian/Mahe",
+ "Indian/Maldives",
+ "Indian/Mauritius",
+ "Indian/Mayotte",
+ "Indian/Reunion",
+ "Iran",
+ "Israel",
+ "Jamaica",
+ "Japan",
+ "Kwajalein",
+ "Libya",
+ "MET",
+ "Mexico/BajaNorte",
+ "Mexico/BajaSur",
+ "Mexico/General",
+ "MST",
+ "MST7MDT",
+ "Navajo",
+ "NZ",
+ "Pacific/Apia",
+ "Pacific/Auckland",
+ "Pacific/Chatham",
+ "Pacific/Easter",
+ "Pacific/Efate",
+ "Pacific/Enderbury",
+ "Pacific/Fakaofo",
+ "Pacific/Fiji",
+ "Pacific/Funafuti",
+ "Pacific/Galapagos",
+ "Pacific/Gambier",
+ "Pacific/Guadalcanal",
+ "Pacific/Guam",
+ "Pacific/Honolulu",
+ "Pacific/Johnston",
+ "Pacific/Kiritimati",
+ "Pacific/Kosrae",
+ "Pacific/Kwajalein",
+ "Pacific/Majuro",
+ "Pacific/Marquesas",
+ "Pacific/Midway",
+ "Pacific/Nauru",
+ "Pacific/Niue",
+ "Pacific/Norfolk",
+ "Pacific/Noumea",
+ "Pacific/Pago_Pago",
+ "Pacific/Palau",
+ "Pacific/Pitcairn",
+ "Pacific/Ponape",
+ "Pacific/Port_Moresby",
+ "Pacific/Rarotonga",
+ "Pacific/Saipan",
+ "Pacific/Samoa",
+ "Pacific/Tahiti",
+ "Pacific/Tarawa",
+ "Pacific/Tongatapu",
+ "Pacific/Truk",
+ "Pacific/Wake",
+ "Pacific/Wallis",
+ "Pacific/Yap",
+ "Poland",
+ "Portugal",
+ "PRC",
+ "PST8PDT",
+ "ROC",
+ "ROK",
+ "Singapore",
+ "Turkey",
+ "UCT",
+ "Universal",
+ "US/Alaska",
+ "US/Aleutian",
+ "US/Arizona",
+ "US/Central",
+ "US/Eastern",
+ "US/Hawaii",
+ "US/Michigan",
+ "US/Mountain",
+ "US/Pacific",
+ "US/Samoa",
+ "UTC",
+ "WET",
+ "Zulu"
+);
--- /dev/null
+<?php
+/* $Id$ */
+require_once 'config.inc.php';
+require_once 'user_validate.php';
+require_once 'helper.php';
+
+valid_user();
+
+$root = WEB_ROOT;
+
+if (! defined($_SESSION['__ROOT__']) && empty($_SESSION['__ROOT__'])) {
+ session_destroy();
+ header('Location: ' . WEB_ROOT . 'error.html');
+ exit;
+}
+
+if (strtoupper($_SESSION['user_settings']->getUid()) == 'ADMIN' && newUpdates()) {
+ upgrade();
+}
+
+header('Location: ' . getServerUrl($root) . '/index.php');
+exit;
+?>
--- /dev/null
+<?php
+/* $Id$ */
+require_once 'config.inc.php';
+require_once 'user_validate.php';
+require_once 'helper.php';
+
+valid_user();
+
+if (! defined($_SESSION['__ROOT__']) && empty($_SESSION['__ROOT__'])) {
+ if (session_id())
+ session_destroy();
+ header('Location: ' . WEB_ROOT . 'error.html');
+ exit;
+}
+
+if (! has_admin_role()) {
+ if (session_id())
+ session_destroy();
+ header('Location: ' . WEB_ROOT . 'error.html');
+ exit;
+}
+
+require_once 'persistens.php';
+
+include TOP_FOLDER.'/include/header.inc.php';
+include TOP_FOLDER.'/include/menu.inc.php';
+$self =$_SERVER['PHP_SELF'];
+$db = Persistens::getInstance(DBDRIVER);
+
+if (count($_POST) > 0 && isset($_POST['action'])) {
+
+ $action = strtolower($_POST['action']);
+ switch ($action) {
+ case 'delete':
+ $error = '';
+ if (isset($_POST['uid']) && ! empty($_POST['uid'])) {
+ foreach ($_POST['uid'] as $uid) {
+ $result = $db->deleteUser($uid);
+ if ($result !== TRUE) {
+ $error .= "$result<br/>";
+ }
+ }
+ }
+ else
+ $error = 'No user selected for deletion';
+ if ($error == '')
+ $result = "Users was succesfully delete";
+ else
+ $result = $error;
+ break;
+ case 'reset password':
+ $res = '';
+ $error = '';
+ if (isset($_POST['uid']) && ! empty($_POST['uid'])) {
+ foreach ($_POST['uid'] as $uid) {
+ $pwd = substr(md5($_POST['uid'] . microtime()), 0, 8);
+ $result = $db->changePassword($uid, sha1($pwd));
+ if ($result !== TRUE)
+ $res .= $_POST['uid'] .": No change<br/>";
+ else
+ $res .= $uid .": $pwd<br/>";
+ }
+ }
+ else
+ $error = 'No user selected for resetting password';
+ if ($error == '')
+ $result = $res;
+ else
+ $result = $error;
+ break;
+ default:
+ $result = "$action: Unknown action";
+ break;
+ }
+ $pageView .= <<<__EOF
+<p style="text-align: center">
+ $result
+</p>
+__EOF;
+}
+else {
+ $pageView = <<<__EOF
+ <form action="$self" method="post" id="form">
+ <p>
+ <table class="config">
+ <tr>
+ <td colspan="3" style="text-align: center;
+ font-weight: bold;font-size: 2.0em;">
+ Manage users
+ </td>
+ </tr>
+ <tr>
+ <th>Username</th><th>Role</th><th> </th>
+ </tr>
+__EOF;
+ $users = $db->getAllUsers();
+ foreach ($users as $user) {
+ if (strtoupper($user['uid']) == 'ADMIN') {
+ $pageView .= "<tr><td>{$user['uid']}</td><td>{$user['userrole']}</td>
+ <td> </td>
+ </tr>";
+ }
+ else {
+ $pageView .= "<tr><td>{$user['uid']}</td><td>{$user['userrole']}</td>
+ <td style=\"text-align: center\"><input type=\"checkbox\" name=\"uid[]\"
+ value=\"{$user['uid']}\"/></td></tr>";
+ }
+ }
+ $pageView .= '<tr><td class="config" colspan="3" style="text-align: center">
+ <input type="submit" name="action" value="Delete"/>
+ <input type="button" value="New user"
+ onclick="document.location.href=\'newuser.php\'" />
+ <input type="submit" name="action" value="Reset password" />
+ </td></tr></table></p></form>';
+}
+
+print "<div id=\"ui\">$pageView</div>";
+
+include TOP_FOLDER.'/include/footer.inc.php';
+
+?>