diff options
author | Allen Winter <allen.winter@kdab.com> | 2014-06-28 15:30:53 -0400 |
---|---|---|
committer | Allen Winter <allen.winter@kdab.com> | 2014-06-28 15:30:53 -0400 |
commit | c363e524f603b4dbeb5bbde5971e7d1c9b26b206 (patch) | |
tree | ba17e68406efd25045f86b0c5403c6c4273f1097 /src/python | |
download | libical-git-0.48.tar.gz |
Diffstat (limited to 'src/python')
-rw-r--r-- | src/python/Attendee.py | 114 | ||||
-rw-r--r-- | src/python/CMakeLists.txt | 72 | ||||
-rw-r--r-- | src/python/ChangeLog | 129 | ||||
-rw-r--r-- | src/python/Collection.py | 128 | ||||
-rw-r--r-- | src/python/Component.py | 819 | ||||
-rw-r--r-- | src/python/DerivedProperties.py | 159 | ||||
-rw-r--r-- | src/python/Duration.py | 92 | ||||
-rw-r--r-- | src/python/Error.py | 10 | ||||
-rw-r--r-- | src/python/Gauge.py | 88 | ||||
-rw-r--r-- | src/python/Libical.py | 39 | ||||
-rw-r--r-- | src/python/LibicalWrap.i | 193 | ||||
-rw-r--r-- | src/python/LibicalWrap_icaltime.i | 204 | ||||
-rw-r--r-- | src/python/LibicalWrap_icaltimezone.i | 216 | ||||
-rw-r--r-- | src/python/Makefile.am | 55 | ||||
-rw-r--r-- | src/python/Makefile.in | 651 | ||||
-rw-r--r-- | src/python/Period.py | 214 | ||||
-rw-r--r-- | src/python/Property.py | 269 | ||||
-rw-r--r-- | src/python/Store.py | 181 | ||||
-rw-r--r-- | src/python/Time.py | 226 | ||||
-rw-r--r-- | src/python/__init__.py | 25 | ||||
-rw-r--r-- | src/python/littlefile.txt | 3 | ||||
-rw-r--r-- | src/python/python-binding.txt | 434 | ||||
-rw-r--r-- | src/python/test.py | 606 |
23 files changed, 4927 insertions, 0 deletions
diff --git a/src/python/Attendee.py b/src/python/Attendee.py new file mode 100644 index 00000000..874f4b66 --- /dev/null +++ b/src/python/Attendee.py @@ -0,0 +1,114 @@ +#!/usr/bin/env python +# -*- Mode: python -*- +#====================================================================== +# FILE: Property.py +# CREATOR: eric +# +# DESCRIPTION: +# +# +# $Id: Attendee.py,v 1.1 2001-04-03 15:18:42 ebusboom Exp $ +# $Locker: $ +# +# (C) COPYRIGHT 2001, Eric Busboom <eric@softwarestudio.org> +# (C) COPYRIGHT 2001, Patrick Lewis <plewis@inetarena.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of either: +# +# The LGPL as published by the Free Software Foundation, version +# 2.1, available at: http://www.fsf.org/copyleft/lesser.html +# +# Or: +# +# The Mozilla Public License Version 1.0. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +#====================================================================== + +from LibicalWrap import * +from Property import Property +from types import DictType, StringType, IntType + +class Attendee(Property): + """Class for Attendee properties. + + Usage: + Attendee([dict]) + Attendee([address]) + + Where: + dict is an optional dictionary with keys of + 'value': CAL-ADDRESS string and any parameter: parameter_value entries. + 'name' and 'value_type' entries in dict are ignored and automatically set + with the appropriate values. + address is the CAL-ADDRESS (string) of the Attendee + """ + + def __init__(self, arg={}): + + assert(isinstance(arg,DictType)) + + ref = None + + if arg!={}: + ref = arg['ref'] + + Property.__init__(self,type='ATTENDEE',ref=ref) + + def _doParam(self, parameter, v): + if v!=None: + self[parameter]=v + return self[parameter] + + # Methods for accessing enumerated parameters + def cn(self, v=None): self._doParam('CN', v) + def cutype(self, v=None): self._doParam('CUTYPE', v) + def dir(self, v=None): self._doParam('DIR', v) + def delegated_from(self, v=None): self._doParam('DELEGATED-FROM', v) + def delegated_to(self, v=None): self._doParam('DELEGATED-TO', v) + def language(self, v=None): self._doParam('LANGUAGE', v) + def member(self, v=None): self._doParam('MEMBER', v) + def partstat(self, v=None): self._doParam('PARTSTAT', v) + def role(self, v=None): self._doParam('ROLE', v) + def rsvp(self, v=None): self._doParam('RSVP', v) + def sent_by(self, v=None): self._doParam('SENT-BY', v) + + +class Organizer(Property): + """Class for Organizer property. + """ + + def __init__(self, arg={}): + + assert(isinstance(arg, DictType)) + + ref = None + if arg != {}: + ref = arg['ref'] + Property.__init__(self, type='ORGANIZER', ref=ref) + +## param_t = ( 'CN', 'DIR', 'SENT-BY', 'LANGUAGE' ) +## for param in param_t: +## self[param] = None +## if value != None: +## self.value(value) + + + def _doParam(self, parameter, v): + if v!=None: + self[parameter]=v + return self[parameter] + + def name(self): + "Return the name of the property." + return Property.name(self) + + def value_type(self): + "Return the value type of the property." + return self._desc['value_type'] + + # Methods for accessing enumerated parameters + def cn(self, v=None): self._doParam('CN', v) + def dir(self, v=None): self._doParam('DIR', v) + def language(self, v=None): self._doParam('LANGUAGE', v) + def sent_by(self, v=None): self._doParam('SENT-BY', v) diff --git a/src/python/CMakeLists.txt b/src/python/CMakeLists.txt new file mode 100644 index 00000000..84ea04b9 --- /dev/null +++ b/src/python/CMakeLists.txt @@ -0,0 +1,72 @@ +include_directories(${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/src/libical ${CMAKE_SOURCE_DIR}/src/libicalss ) + + +########### next target ############### + +SET(LibicalWrap_LIB_SRCS + LibicalWrap.c +) + +add_library(LibicalWrap ${LIBRARY_TYPE} ${LibicalWrap_LIB_SRCS}) + +target_link_libraries(LibicalWrap) + +set_target_properties(LibicalWrap PROPERTIES VERSION ${LIBICAL_LIB_VERSION_STRING} SOVERSION ${LIBICAL_LIB_MAJOR_VERSION}) +install(TARGETS LibicalWrap DESTINATION lib) + + +########### install files ############### + + + + +#original Makefile.am contents follow: + +# +#lib_LTLIBRARIES = libLibicalWrap.la +# +#libLibicalWrap_la_SOURCES = LibicalWrap.c +# +#INCLUDES = \ +# -I$(top_builddir) \ +# -I$(top_srcdir)/src \ +# -I$(top_builddir)/src \ +# -I$(top_srcdir)/src/libical \ +# -I$(top_builddir)/src/libical \ +# -I$(top_srcdir)/src/libicalss \ +# $(PY_CFLAGS) +# +#LDADD = ../libical/libical.la ../libicalss/libicalss.la +# +#all: LibicalWrap.so +# +#LibicalWrap.c: LibicalWrap.i +# swig -python -o LibicalWrap.c LibicalWrap.i +# +## This part should be done with libtool, but I don't know how to do +## it. Libtool needs to generate a shared library in this directory +## regardless of the value of AM_DISABLE_SHARED +#LibicalWrap.so: LibicalWrap.c +# ld -shared -o LibicalWrap.so LibicalWrap.o ../libical/.libs/libical.a ../libicalss/.libs/libicalss.a +# +#CLEANFILES = LibicalWrap.c LibicalWrap_wrap.doc Libical.pyc LibicalWrap.so +# +#EXTRA_DIST = \ +#Libical.py \ +#LibicalWrap.i \ +#python-binding.txt \ +#test.py \ +#Attendee.py \ +#Collection.py \ +#Component.py \ +#DerivedProperties.py \ +#Duration.py \ +#Error.py \ +#Gauge.py \ +#Period.py \ +#Property.py \ +#Store.py \ +#Time.py \ +#ChangeLog +# +# diff --git a/src/python/ChangeLog b/src/python/ChangeLog new file mode 100644 index 00000000..ef096f4e --- /dev/null +++ b/src/python/ChangeLog @@ -0,0 +1,129 @@ +2001-04-04 Eric Busboom <eric@softwarestudio.org> + + * Component.py Added Calendar class. + + * Componeny.py Changed all component constructor so they cannot + take string arguments. Now, only NewComponent() can turn an iCal + string into a component. + + +2001-04-02 Eric Busboom <eric@softwarestudio.org> + + * Component.py removed arguments from the Event constructor, since + I presume that the Component derived classes will always be + constructed with no arguments. + + * Property.py Split out Attendee, Organizer, Time, Duration and + Period into their own files. Moved remaining classes to Derived + Properties.pm + + +2001-03-13 Eric Busboom <eric@softwarestudio.org> + + * Component.py Added Component.property() + +2001-03-10 Patrick Lewis <plewis@inetarena.com> + + * Added __str__ method to Collection.Collection + + * Component.Component can now be initialized without arguments + + * Made _singular_property and _multiple_properties (in Component) + useful for nearly all the specific component interfaces + + * Changed Property.Attendee and Property.Organizer to allow creation + with no arguments + + * Filled in Todo skeleton + + * Added test function for an Event + + +2001-03-05 Eric Busboom <eric@softwarestudio.org> + + * Property.py Added a lot of exception code to signal failure to + create a Property. + + * DerivedProperties.py Added derived property classes for RDATE + and TRIGGER, two properties that can have one of two value types. + + +2001-03-04 Eric Busboom <eric@softwarestudio.org> + + * Property.pm Added Property.ConstructorFailedError exception + + * Component.pm fixed bug in Collection.__setslice__. "," used + instead of ":" + +2001-03-04 Patrick Lewis <plewis@inetarena.com> + + * Split Libical.py file into Component.py, Property.py, Collection.py, + and Store.py + + * Added test_* functions to test.py + + * Changed component bindings to return a Collection when objects can + have multiple values + + * Changed Component object to allow for creation of an object without + an initial string + + * Added Todo and Journal events + +2001-02-28 Eric Busboom <eric@softwarestudio.org> + + * Property Remove most internal data. The property now work + alsmost entirely off of the icalproperty that it holds a reference + to. Made changes in all derived Properties to accomodate the + change. + + * Property Added __del__ + + * Component Component.properties() now caches properties that it + constructs, so two calls to properties() to that get the same + icalproperty will also get the same Property. + + * Property Added Property.__cmp__ to test equality of properties + based on ical string values + +2001-02-27 Eric Busboom <eric@softwarestudio.org> + + * Property Added Property.ref() to set/get the reference to the + Property's internal icalproperty + + * Property Property._update_value now changes the icalproperty + value if a reference has been set. + + * Component re-instituted Component.properties(). The routine now + adds a 'ref' key to the dict that holds the python pointer + string. The C hex value of the pointer is in the 'pid' key + + +2001-02-27 Patrick Lewis <plewis@inetarena.com> + + * Backed out changes to Component removing comp_p; + Component.comp_p should be restored + +2001-02-26 Eric Busboom <eric@softwarestudio.org> + + * Period Added test routine,test_period() + + * Period implemented methods in period + + * Time Addedd addition and subtraction operators + +2001-02-25 Eric Busboom <eric@softwarestudio.org> + + * Libical.py Added test routine for time, time_test() + + * Libical.py Remove end of line chars ('\r\n" ) from + Property._str__. Caller should add these lines itself + + * Liical.py CHanges Time._update_values to set time VALUE type + based on use of is_date, rather than length of string. + + * Libical.py Removed call to _update_value in TIme::timezone + + + * Libical.py changed update_value to _update_value + diff --git a/src/python/Collection.py b/src/python/Collection.py new file mode 100644 index 00000000..48c3652c --- /dev/null +++ b/src/python/Collection.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python +# -*- Mode: python -*- +#====================================================================== +# FILE: Collection.py +# CREATOR: eric +# +# DESCRIPTION: +# +# +# $Id: Collection.py,v 1.3 2001-03-11 00:46:57 plewis Exp $ +# $Locker: $ +# +# (C) COPYRIGHT 2001, Eric Busboom <eric@softwarestudio.org> +# (C) COPYRIGHT 2001, Patrick Lewis <plewis@inetarena.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of either: +# +# The LGPL as published by the Free Software Foundation, version +# 2.1, available at: http://www.fsf.org/copyleft/lesser.html +# +# Or: +# +# The Mozilla Public License Version 1.0. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +#====================================================================== + +from types import * + +class Collection: + """A group of components that can be modified somewhat like a list. + + Usage: + Collection(componet, propSequence) + + component is a Component object + propSequence is a list or tuple of Property (or subclass of Property) + of objects already in component + """ + + def __init__(self, component, propSequence): + self._properties = list(propSequence[:]) + self._component = component + + def __getslice__(self, beg, end): + return Collection(self._component, self._properties[beg:end]) + + def __setslice__(self, beg, end, sequence): + + if not isinstance(sequence,ListType): + raise TypeError, "must assign list (not instance) to slice" + + oldProps = self._properties[beg:end] + + for p in oldProps: + self._component.remove_property(p) + + self._properties[beg:end] = sequence + for p in sequence: + self._component.add_property(p) + + def __getitem__(self, i): + return self._properties[i] + + def __setitem__(self, i, prop): + self._component.remove_property(self._properties[i]) + self._component.add_property(prop) + self._properties[i]=prop + + def __delitem__(self, i): + self._component.remove_property(self._properties[i]) + del self._properties[i] + + def __len__(self): + return len(self._properties) + + def __str__(self): + s = "[ " + if len(self._properties) > 0: + s = s + str(self._properties[0]) + for p in self._properties[1:]: + s = "%s, %s" % (s, p) + s = s + " ]" + return s + + def append(self, property): + self._properties.append(property) + self._component.add_property(property) + +class ComponentCollection: + + def __init__(self, parent, componentSequence): + self._parent = parent + self._components = list(componentSequence[:]) + + def __getslice__(self, beg, end): + return ComponentCollection(self._parent, self._components[beg:end]) + + def __setslice__(self, beg, end, sequence): + oldComps = self._components[beg:end] + self._components.__setslice__(beg, end, sequence) + for c in sequence: + self._parent.add_component(c) + for c in oldComps: + self._parent.remove_component(c) + + def __getitem__(self, i): + return self._components[i] + + def __setitem__(self, i, prop): + self._parent.remove_component(self._components[i]) + self._parent.add_property(prop) + self._components[i]=prop + + def __delitem__(self, i): + self._parent.remove_componet(self._components[i]) + del self._components[i] + + def __len__(self): + return len(self._components) + + def __add__(self, iterable): + for i in iterable: + self.append(i) + + def append(self, property): + self._components.append(property) + self._parent.add_component(property) diff --git a/src/python/Component.py b/src/python/Component.py new file mode 100644 index 00000000..8f24f544 --- /dev/null +++ b/src/python/Component.py @@ -0,0 +1,819 @@ +#!/usr/bin/env python +# -*- Mode: python -*- +#====================================================================== +# FILE: Component.py +# CREATOR: eric +# +# DESCRIPTION: +# +# +# $Id: Component.py,v 1.15 2002-10-24 13:41:17 acampi Exp $ +# $Locker: $ +# +# (C) COPYRIGHT 2001, Eric Busboom <eric@softwarestudio.org> +# (C) COPYRIGHT 2001, Patrick Lewis <plewis@inetarena.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of either: +# +# The LGPL as published by the Free Software Foundation, version +# 2.1, available at: http://www.fsf.org/copyleft/lesser.html +# +# Or: +# +# The Mozilla Public License Version 1.0. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +#====================================================================== + +from LibicalWrap import * +from types import DictType, StringType, IntType +from Property import Property +from Collection import * +from Attendee import Attendee, Organizer +from Time import Time +from Duration import Duration +from Period import Period +import string + +WrapperNULL = None + +# Swig objects are natively unhashable, so we hash on the pointer val. +class SwigRefHash(dict): + def __getitem__(self, k): + return dict.__getitem__(self, int(k)) + + def __setitem__(self, k, v): + return dict.__setitem__(self, int(k), v) + + def __delitem__(self, k): + dict.__delitem__(self, int(k)) + + def has_key(self, k): + return dict.has_key(self, int(k)) + +class Component(object): + + def __init__(self,ref=None,kind=None): + + self._ref = None + if ref != None: + self._ref = ref + elif kind != None: + self._ref = icalcomponent_new( + icalcomponent_string_to_kind("VCALENDAR")) + _kind = icalcomponent_string_to_kind(kind) + inner = icalcomponent_new(_kind) + + icalcomponent_add_component(self._ref,inner); + + else: + raise "Could not construct component of kind" + kind + + self.cached_props = SwigRefHash() + self.cached_comps = SwigRefHash() + + def __del__(self): + if self._ref != None and icalcomponent_get_parent(self._ref) != WrapperNULL: + + for k in self.cached_props.keys(): + del self.cached_props[k] + + icalcomponent_free(self._ref) + self._ref = None + + def _prop_from_ref(self,p): + + if(p == None or p== WrapperNULL): + return None; + + d = {} + d['value'] = icalproperty_get_value_as_string(p) + d['name'] = icalproperty_get_property_name(p) + + propkind = icalproperty_string_to_kind(d['name']) + kind = icalproperty_kind_to_value_kind(propkind) + d['value_type'] = icalvalue_kind_to_string(kind) + d['ref'] = p + + + #~ print p, Property(ref=p).name() + if not self.cached_props.has_key(p): + + if d['value_type'] == 'DATE-TIME' or d['value_type'] == 'DATE': + prop = Time(d,) + elif d['value_type'] == 'PERIOD': + prop = Period(d) + elif d['value_type'] == 'DURATION': + prop = Duration(d) + elif d['name'] == 'ATTACH': + prop = Attach(d) + elif d['name'] == 'ATTENDEE': + prop = Attendee(d) + elif d['name'] == 'ORGANIZER': + prop = Organizer(d) + else: + prop=Property(ref=p) + + self.cached_props[p] = prop + + def property(self, type): + + p = icallangbind_get_first_property(self._ref,type) + + if p !=WrapperNULL: + self._prop_from_ref(p) + prop = self.cached_props[p] + return prop + else : + return None + + def properties(self,type='ANY'): + """ + Return a list of Property instances, each representing a + property of the type 'type.' + """ + + props = [] + + p = icallangbind_get_first_property(self._ref,type) + + while p !=WrapperNULL and p != None: + + self._prop_from_ref(p) # Puts property in self.cached_props + prop = self.cached_props[p] + props.append(prop) + p = icallangbind_get_next_property(self._ref,type) + + return Collection(self,props) + + def add_property(self, prop): + "Adds the property object to the component." + + if not isinstance(prop,Property): + raise TypeError + + prop_p = prop.ref() + + if not prop_p: + s = str(prop) + prop_p = icalproperty_new_from_string(s) + + if prop_p == WrapperNULL: + raise "Bad property string: " + s + + prop.ref(prop_p) + + if icalproperty_get_parent(prop_p)==WrapperNULL: + icalcomponent_add_property(self._ref, prop_p) + elif icalproperty_get_parent(prop_p) != self._ref: + raise "Property is already a child of another component" + + + def remove_property(self,prop): + + if prop.ref() and self.cached_props.has_key(prop.ref()): + + del self.cached_props[prop.ref()] + icalcomponent_remove_property(self._ref,prop.ref()) + + def components(self,type='ANY'): + comps = [] + + kind = icalcomponent_string_to_kind(type) + c = icalcomponent_get_first_component(self._ref,kind); + + while c != WrapperNULL and c != None: + + if not self.cached_comps.has_key(c): + + self.cached_comps[c] = Component(c) + + comp = self.cached_comps[c] + comps.append(comp) + c = icalcomponent_get_next_component(self._ref,kind); + + return ComponentCollection(self, comps) + + def inner_component(self): + + inner = icalcomponent_get_inner(self._ref) + + if inner == WrapperNULL and inner != None: + return None + + return NewComponent(inner) + + def add_component(self, comp): + "Adds a child component." + + if not isinstance(comp,Component): + raise ValueError("Expected a Component") + + if icalcomponent_get_parent(comp._ref) != WrapperNULL: + raise "Failed to add child component. Child already has a parent"; + + icalcomponent_add_component(self._ref,comp._ref) + + def remove_component(self, comp): + "Removes a child component" + + if not isinstance(comp,Component): + raise ValueError("Expected a Component") + + icalcomponent_remove_component(self._ref,comp._ref) + + def as_ical_string(self): + return self.__str__() + + def __str__(self): + + return icalcomponent_as_ical_string(self._ref) + + def name(self): + k = icalcomponent_isa(self._ref) + return icalcomponent_kind_to_string(k) + + def ref(self): + """ Return the internal reference to the libical icalproperty """ + return self._ref + +def CloneComponent(c): + "Clones a string or C icalcomponent into the right component object." + + wasStr=0 # Were we passed a string or an icalcomponent? + + if isinstance(c, Component): + comp = icalparser_parse_string(c.as_ical_string()) + elif isinstance (c, StringType) and string.find(c,"icalcomponent") == -1: + comp = icalparser_parse_string(c) + else: + comp = c + + if comp == None or comp == WrapperNULL: + raise ValueError("Expected a libical reference or an iCal string") + + kind = icalcomponent_isa(comp) + kindStr = icalcomponent_kind_to_string(kind) + + if kindStr == 'VCALENDAR': + inner = icalcomponent_get_inner(comp) + kind = icalcomponent_isa(inner) + kindStr = icalcomponent_kind_to_string(kind) + + if kindStr == 'VEVENT': + newComp = Event(comp) + elif kindStr == 'VTODO': + newComp = Todo(comp) + elif kindStr == 'VJOURNAL': + newComp = Journal(comp) + else: + newComp = Component(comp) + + # I don't think I need to free the component created when passed a string, + # as it wasn't created with a _new function. + + return newComp + + +def NewComponent(c): + "Converts a string or C icalcomponent into the right component object." + + wasStr=0 # Were we passed a string or an icalcomponent? + + if isinstance (c, StringType) and string.find(c,"icalcomponent") == -1: + comp = icalparser_parse_string(c) + else: + comp = c + + if comp == None or comp == WrapperNULL: + raise ValueError("Expected a libical reference or an iCal string") + + kind = icalcomponent_isa(comp) + kindStr = icalcomponent_kind_to_string(kind) + + if kindStr == 'VEVENT': + newComp = Event(comp) + elif kindStr == 'VTODO': + newComp = Todo(comp) + elif kindStr == 'VJOURNAL': + newComp = Journal(comp) + else: + newComp = Component(comp) + + # I don't think I need to free the component created when passed a string, + # as it wasn't created with a _new function. + + return newComp + + +class GenericComponent(Component): + + def __init__(self,ref=None,kind=None): + + if ref != None: + Component.__init__(self, ref=ref) # Call from subclasses + elif type != None: + Component.__init__(self, kind=kind) # Call from subclasses + else: + raise ValueError("Expected either a icalcomponent reference or a kind string") + + + self._recurrence_set=None + + def _singular_property(self, name, value_type, value=None, + property_obj=None, enumerated_values=None): + """Sets or gets the value of a method which exists once per Component. + + This is a constructor method for properties without a strictly defined + object.""" + + # Depending on the property name, this routine will either + # operate on the VCALENDAR container or on the inner VEVENT, + # VTODO, or VJOURNAL + + if name in ['METHOD','PRODID','CALSCALE','VERSION']: + comp = self + else: + comp = self.inner_component() + + curr_properties = comp.properties(name) + + # Get the value + if value==None: + if len(curr_properties) == 0: + return None + elif len(curr_properties) == 1: + return curr_properties[0] + else: + raise ValueError, "too many properties of type %s" % propType + + # Set the value + else: + # Check if value is in enumerated_values + if enumerated_values: + value = string.upper(value) + if value not in enumerated_values: + raise ValueError, "%s is not one of %s" \ + % (value, enumerated_values) + + # Create the new property + if property_obj: + if not isinstance(value, property_obj): + # Create a special property_obj property + if property_obj == Time: + p = Time(value, name) + ## p.value_type(value_type) + elif property_obj == Duration: + p = Duration(value) + else: + p = property_obj() + ## p.value_type(value_type) + p.value(value) + else: + p = value # value is already a property_obj + else: + # Create a generic property + p = Property(name) + ## p.value_type(value_type) + p.value(value) + + if len(curr_properties) == 1: + comp.remove_property(curr_properties[0]) + elif len(curr_properties) > 1: + raise ValueError, "too many properties of type %s" % propType + + comp.add_property(p) + + # METHOD, PRODID, CALSCALE and VERSION are properties of the + # VCALENDAR, not the inner component + + def method(self, v=None): + "Sets or returns the value of the METHOD property." + return self._singular_property("METHOD", "TEXT", v) + + def prodid(self, v=None): + "Sets or returns the value of the PRODID property." + return self._singular_property("PRODID", "TEXT", v) + + def calscale(self, v=None): + "Sets or returns the value of the CALSCALE property." + return self._singular_property("CALSCALE", "TEXT", v) + + def version(self, v=None): + "Sets or returns the value of the Version property." + return self._singular_property("VERSION", "TEXT", v) + + # The remaining properties are all in the inner component + + def clone(self): + "Returns a copy of the object." + return CloneComponent(self) + + def class_prop(self, v=None): # Class is a reserved word + "Sets or returns the value of the CLASS property." + if v!=None: + v = string.upper(v) + return self._singular_property('CLASS', 'TEXT', v) + + def created(self, v=None): + """Sets or returns the value of the CREATED property. + + Usage: + created(time_obj) # Set the value using a Time object + created('19970101T123000Z') # Set using an iCalendar string + created(982362522) # Set using seconds + created() # Return an iCalendar string + """ + return self._singular_property("CREATED", "DATE-TIME", v, Time) + + def description(self, v=None): + "Sets or returns the value of the DESCRIPTION property." + return self._singular_property("DESCRIPTION", "TEXT", v) + + def dtstamp(self, v=None): + """Sets or returns the value of the DTSTAMP property. + + Usage: + dtstamp(time_obj) # Set the value using a Time object + dtstamp('19970101T123000Z')# Set using an iCalendar string + dtstamp(982362522) # Set using seconds + dtstamp() # Return an iCalendar string + """ + return self._singular_property("DTSTAMP", "DATE-TIME", v, Time) + + def dtstart(self, v=None): + """Sets or returns the value of the DTSTART property. + + Usage: + dtstart(time_obj) # Set the value using a Time object + dtstart('19970101T123000Z') # Set the value as an iCalendar string + dtstart(982362522) # Set the value using seconds (time_t) + dtstart() # Return the time as an iCalendar string + """ + return self._singular_property("DTSTART", "DATE-TIME", v, Time) + + def last_modified(self, v=None): + """Sets or returns the value of the LAST-MODIFIED property. + + Usage: + last_modified(time_obj) # Set the value using a Time object + last_modified('19970101T123000Z')# Set using an iCalendar string + last_modified(982362522) # Set using seconds + last_modified() # Return an iCalendar string + """ + return self._singular_property("LAST-MODIFIED", "DATE-TIME", v, Time) + + def organizer(self, v=None): + """Sets or gets the value of the ORGANIZER property. + + Usage: + organizer(orgObj) # Set value using an organizer object + organizer('MAILTO:jd@not.com') # Set value using a CAL-ADDRESS string + organizer() # Return a CAL-ADDRESS string + """ + return self._singular_property('ORGANIZER', 'CAL-ADDRESS', v, + Organizer) + + def recurrence_id(self, v=None): + """Sets or gets the value for the RECURRENCE-ID property. + + Usage: + recurrence_id(recIdObj) # Set using a Recurrence_Id object + recurrence_id("19700801T133000") # Set using an iCalendar string + recurrence_id(8349873494) # Set using seconds from epoch + recurrence_id() # Return an iCalendar string + """ + return self._singular_property('RECURRENCE-ID', 'DATE-TIME', v, + Recurrence_Id) + + def sequence(self, v=None): + """Sets or gets the SEQUENCE value of the Event. + + Usage: + sequence(1) # Set the value using an integer + sequence('2') # Set the value using a string containing an integer + sequence() # Return an integer + """ + if isinstance(v, StringType): + v = int(str) + return self._singular_property('SEQUENCE', 'INTEGER', v) + + def summary(self, v=None): + "Sets or gets the SUMMARY value of the Event." + return self._singular_property('SUMMARY', 'TEXT', v) + + def uid(self, v=None): + "Sets or gets the UID of the Event." + return self._singular_property('UID', 'TEXT', v) + + def url(self, v=None): + """Sets or returns the URL property.""" + return self._singular_property('URL', 'URI', v) + + #### + # Not quite sure if this is how we want to handle recurrence rules, but + # this is a start. + + def recurrence_set(self): + "Returns the Events RecurrenceSet object." + if self._recurrence_set == None: # i.e haven't initialized one + self._recurrence_set = RecurrenceSet() + return self._recurrence_set + + ### + # Alarm interface. Returns an ComponentCollection. + + def alarms(self, values=None): + """Sets or returns ALARM components. + + Examples: + alarms((alarm1,)) # Set using Alarm component + alarms() # Returns an ComponentCollection of all Alarms + """ + if values!=None: + for alarm in values: + self.add_component(alarm) + else: + return self.components('VALARM') + + #### + # Methods that deal with Properties that can occur multiple times are + # below. They use the Collection class to return their Properties. + + def _multiple_properties(self, name, value_type, values, + property_obj=None): + "Processes set/get for Properties that can have multiple instances." + + comp = self.inner_component() + + # Set value + if values!=None: + if not isinstance(values, TupleType) \ + and not isinstance(values, ListType): + raise TypeError, "%s is not a tuple or list." + + # Delete old properties + for p in comp.properties(name): + comp.remove_property(p) + + for v in values: + if property_obj: # Specialized properties + if not isinstance(v, property_obj): # Make new object + new_prop = property_obj() + new_prop.value(v) + else: # Use existing object + new_prop = v + else: # Generic properties + new_prop=Property(name) + # new_prop.value_type(value_type) + new_prop.value(v) + + comp.add_property(new_prop) + + # Get value + else: + return Collection(self, comp.properties(name)) + + def attachments(self, values=None): + """Sets or returns a Collection of Attach properties. + + 'values' can be a sequence containing URLs (strings) and/or file-ish + objects. + """ + return self._multiple_properties("ATTACH", "", value, Attach) + + def attendees(self, value=None): + """Sets attendees or returns a Collection of Attendee objects. + + If setting the attendees, pass a sequence as the argument. + Examples: + # Set using Attendee objects + attendees((attObj1, attObj2)) + # Set using a CAL-ADDRESS string + attendees(['MAILTO:jdoe@somewhere.com']) + # Set using a combination of Attendee objects and strings + attendees(['MAILTO:jdoe@somewhere.com', attObj1]) + # Returns a list of Attendee objects + attendees() + + When setting the attendees, any previous Attendee objects in the Event + are overwritten. If you want to add to the Attendees, one way to do it + is: + + attendees().append(Attendee('MAILTO:jdoe@nothere.com')) + """ + return self._multiple_properties("ATTENDEE", "", value, Attendee) + + def categories(self, value=None): + """Sets categories or returns a Collection of CATEGORIES properties. + + If setting the categories, pass a sequence as the argument. + Examples: + # Set using string[s] + categories(('APPOINTMENT', 'EDUCATION')) + # Returns a list of Category properites + categories() + + When setting the attendees, any previous category Properties in the + Event are overwritten. If you want to add to the categories, one way + to do it is: + + new_cat=Property('CATEGORIES') + new_cat.value_type('TEXT') + new_cat.value('PERSONAL') + categories().append(new_cat) + """ + return self._multiple_properties("CATEGORIES", "TEXT", value) + + def comments(self, value=None): + "Sets or returns a Collection of COMMENT properties." + return self._multiple_properties('COMMENT', 'TEXT', value) + + def contacts(self, value=None): + "Sets or returns a Collection of CONTACT properties." + return self._multiple_properties('CONTACT', 'TEXT', value) + + def related_tos(self, value=None): + "Sets or returns a Collection of RELATED-TO properties." + return self._multiple_properties('RELATED-TO', 'TEXT', value) + + def x_properties(self, name, value=None): + "Sets or returns a Collection of X- properties." + return self._multiple_properties(name, 'TEXT', value) + +class Event(GenericComponent): + "The iCalendar Event object." + + def __init__(self,ref=None): + if ref != None: + GenericComponent.__init__(self, ref=ref) + else: + GenericComponent.__init__(self, kind='VEVENT') + + def component_type(self): + "Returns the type of component for the object." + return "VEVENT" + + def dtend(self, v=None): + """Sets or returns the value of the DTEND property. + + Usage: + dtend(time_obj) # Set the value using a Time object + dtend('19970101T123000Z') # Set the value as an iCalendar string + dtend(982362522) # Set the value using seconds (time_t) + dtend() # Return the time as an iCalendar string + + If the dtend value is being set and duration() has a value, the + duration property will be removed. + """ + if v != None: + duration = self.properties('DURATION') + for d in duration: # Clear DURATION properties + self.remove_property(d) + return self._singular_property("DTEND", "DATE-TIME", v, Time) + + def duration(self, v=None): + """Sets or returns the value of the duration property. + + Usage: + duration(dur_obj) # Set the value using a Duration object + duration("P3DT12H") # Set value as an iCalendar string + duration(3600) # Set duration using seconds + duration() # Return duration as an iCalendar string + + If the duration value is being set and dtend() has a value, the dtend + property will be removed. + """ + + if v != None: + dtend = self.properties('DTEND') + for d in dtend: + self.remove_property(d) # Clear DTEND properties + return self._singular_property("DURATION", "DURATION", v, Duration) + + def status(self, v=None): + "Sets or returns the value of the STATUS property." + + # These values are only good for VEVENT components (i.e. don't copy + # & paste into VTODO or VJOURNAL + valid_values=('TENTATIVE', 'CONFIRMED', 'CANCELLED') + return self._singular_property("STATUS", "TEXT", v, + enumerated_values=valid_values) + + def geo(self, v=None): + """Sets or returns the value of the GEO property. + + Usage: + geo(value) or + geo() # Returns the icalendar string + + 'value' is either a icalendar GEO string or a sequence with two 'float' + numbers. + + Examples: + geo('40.232;-115.9531') # Set value using string + geo((40.232, -115.9531)) # Set value using a sequence + geo() # Returns "40.232;-115.9531" + + To get the GEO property represented as a tuple and numbers instead of + the iCalendar string, use geo_get_tuple(). + """ + + if isinstance(v, ListType) or isinstance(v, TupleType): + v = "%s;%s" % (float(v[0]), float(v[1])) + return self._singular_property("GEO", "FLOAT", v) + + def geo_get_tuple(self): + """Returns the GEO property as a tuple.""" + + geo = self.geo() + geo = split(geo, ';') + return float(geo[0]), float(geo[1]) + + def location(self, v=None): + """Sets or returns the LOCATION property.""" + return self._singular_property("LOCATION", "TEXT", v) + + def transp(self, v=None): + """Sets or returns the TRANSP property.""" + ok_values = ('OPAQUE', 'TRANSPARENT') + return self._singular_property('TRANSP', 'TEXT', v, + enumerated_values=ok_values) + + def resources(self, v=None): + pass + +class Todo(GenericComponent): + "The iCalendar TODO component." + + def __init__(self,ref=None): + if ref != None: + GenericComponent.__init__(self, ref=ref) + else: + GenericComponent.__init__(self, kind='VTODO') + + + def component_type(self): + "Returns the type of component for the object." + return "VTODO" + + def completed(self, value=None): + return self._singular_property('COMPLETED', 'DATE-TIME', value, Time) + + def geo(self, value=None): + if isinstance(v, ListType) or isinstance(v, TupleType): + v = "%s;%s" % (float(v[0]), float(v[1])) + return self._singular_property("GEO", "FLOAT", value) + + def location(self, value=None): + return self._singular_property('LOCATION', 'TEXT', value) + + def percent(self, value=None): + if value!=None: + value = str(int(value)) + return self._singular_property('PERCENT', 'INTEGER', value) + + def status(self, value=None): + if value!=None: + value=string.upper(value) + ok_values = ('NEEDS-ACTION', 'COMPLETED', 'IN-PROCESS', 'CANCELLED') + return self._singular_property('STATUS', 'TEXT', value, + enumerated_values=ok_values) + + def due(self, value=None): + if value != None: + duration = self.properties('DURATION') + for d in duration: + self.remove_property(d) # Clear DURATION properties + return self._singular_property('DUE', 'DATE-TIME', value, Time) + + def duration(self, value=None): + if value != None: + due = self.properites('DUE') + for d in due: + self.remove_property(d) # Clear DUE properties + return self._singular_property("DURATION", "DURATION", value, Duration) + + def resources(): + pass + +class Journal(GenericComponent): + "The iCalendar JOURNAL component." + + def __init__(self): + if ref != None: + GenericComponent.__init__(self, ref=ref) + else: + GenericComponent.__init__(self, kind='VJOURNAL') + + def component_type(self): + "Returns the type of component for the object." + return "VJOURNAL" + + def status(self, v=None): + if v!=None: + v = string.upper(v) + ok_values=('DRAFT', 'FINAL', 'CANCELLED') + return self._singular_property('STATUS', 'TEXT', v, + enumerated_values=ok_values) + diff --git a/src/python/DerivedProperties.py b/src/python/DerivedProperties.py new file mode 100644 index 00000000..71ad640e --- /dev/null +++ b/src/python/DerivedProperties.py @@ -0,0 +1,159 @@ +#!/usr/bin/env python +# -*- Mode: python -*- +#====================================================================== +# FILE: DerivedProperties.py +# CREATOR: eric +# +# DESCRIPTION: +# +# +# $Id: DerivedProperties.py,v 1.4 2001-04-03 15:18:42 ebusboom Exp $ +# $Locker: $ +# +# (C) COPYRIGHT 2001, Eric Busboom <eric@softwarestudio.org> +# (C) COPYRIGHT 2001, Patrick Lewis <plewis@inetarena.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of either: +# +# The LGPL as published by the Free Software Foundation, version +# 2.1, available at: http://www.fsf.org/copyleft/lesser.html +# +# Or: +# +# The Mozilla Public License Version 1.0. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +#====================================================================== + +from Property import Property +from Time import Time +from Period import Period +from Duration import Duration + +def RDate(arg): + + class RDate_Time(Time): + def __init__(self,arg): Time.__init__(self,arg,"RDATE") + + class RDate_Period(Period): + def __init__(self,arg): Period.__init__(self,arg,"RDATE") + + p = None + for c in [RDate_Time, RDate_Period]: + try: return c(arg) + except Property.ConstructorFailedError, d: pass + raise Property.ConstructorFailedError("Failed to construct RDATE from "+str(arg)) + + +def Trigger(arg): + class Trigger_Time(Time): + def __init__(self,arg): Time.__init__(self,arg,"TRIGGER") + + class Trigger_Duration(Duration): + def __init__(self,arg): Duration.__init__(self,arg,"TRIGGER") + + p = None + for c in [Trigger_Duration, Trigger_Time]: + try: return c(arg) + except Property.ConstructorFailedError, d: pass + raise Property.ConstructorFailedError("Failed to construct TRIGGER from "+str(arg)) + + + +class Recurrence_Id(Time): + """Class for RECURRENCE-ID property. + + Usage: + Reccurence_Id(dict) # A normal property dictionary + Reccurence_Id("19960401") # An iCalendar string + Reccurence_Id(8349873494) # Seconds from epoch + + If the 'dict' constructor is used, 'name' and 'value_type' + entries in dict are ignored and automatically set with the appropriate + values. + """ + + def __init__(self, dict={}): + Time.__init__(self, dict) + Property.name(self, 'RECURRENCE-ID') + + def name(self): + return Property.name(self) + + def _doParam(self, parameter, v): + if v!=None: + self[parameter]=v + return self[parameter] + + # Enumerated parameters + def value_parameter(self, v=None): + """Sets or gets the VALUE parameter value. + + The value passed should be either "DATE-TIME" or "DATE". Setting this + parameter has no impact on the property's value_type. Doing something + like: + + rid=Recurrence_Id("19960401") # Sets value & makes value_type="DATE" + rid.value_parameter("DATE-TIME") # Sets the parameter VALUE=DATE-TIME + + Would be allowed (even though it is wrong), so pay attention. + Verifying the component will reveal the error. + """ + if v!=None and v!="DATE" and v!="DATE-TIME": + raise ValueError, "%s is an invalid VALUE parameter value" % str(v) + self._doParam("VALUE", v) + + def tzid(self, v=None): + "Sets or gets the TZID parameter value." + self._doParam("TZID", v) + + def range_parameter(self, v=None): # 'range' is a builtin function + "Sets or gets the RANGE parameter value." + if v!=None and v!="THISANDPRIOR" and v!= "THISANDFUTURE": + raise ValueError, "%s is an invalid RANGE parameter value" % str(v) + self._doParam("RANGE", v) + +class Attach(Property): + """A class representing an ATTACH property. + + Usage: + Attach(uriString [, parameter_dict]) + Attach(fileObj [, parameter_dict]) + """ + + def __init__(self, value=None, parameter_dict={}): + Property.__init__(self, parameter_dict) + Property.name(self, 'ATTACH') + self.value(value) + + def value(self, v=None): + "Returns or sets the value of the property." + if v != None: + if isinstance(v, StringType): # Is a URI + self._desc['value']=v + Property.value_type(self, 'URI') + else: + try: + tempStr = v.read() + except: + raise TypeError,"%s must be a URL string or file-ish type"\ + % str(v) + self._desc['value'] = base64.encodestring(tempStr) + Property.value_type(self, 'BINARY') + else: + return self._desc['value'] + + def name(self): + "Returns the name of the property." + return Property.name(self) + + def value_type(self): + return Property.value_type(self) + + def fmttype(self, v=None): + "Gets or sets the FMTYPE parameter." + if v!= None: + self['FMTTYPE']=v + else: + return self['FMTTYPE'] + diff --git a/src/python/Duration.py b/src/python/Duration.py new file mode 100644 index 00000000..57fe25e6 --- /dev/null +++ b/src/python/Duration.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python +# -*- Mode: python -*- +#====================================================================== +# FILE: Duration.py +# CREATOR: eric +# +# DESCRIPTION: +# +# +# $Id: Duration.py,v 1.1 2001-04-03 15:18:42 ebusboom Exp $ +# $Locker: $ +# +# (C) COPYRIGHT 2001, Eric Busboom <eric@softwarestudio.org> +# (C) COPYRIGHT 2001, Patrick Lewis <plewis@inetarena.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of either: +# +# The LGPL as published by the Free Software Foundation, version +# 2.1, available at: http://www.fsf.org/copyleft/lesser.html +# +# Or: +# +# The Mozilla Public License Version 1.0. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +#=============================================================== + +from LibicalWrap import * +from Property import Property +from types import DictType, StringType, IntType + +class Duration(Property): + """ + Represent a length of time, like 3 minutes, or 6 days, 20 seconds. + + + """ + + def __init__(self, arg, name="DURATION"): + """ + Create a new duration from an RFC2445 string or number of seconds. + Construct the duration from an iCalendar string or a number of seconds. + + Duration("P3DT2H34M45S") Construct from an iCalendar string + Duration(3660) Construct from seconds + """ + + self.dur = None + + e=icalerror_supress("MALFORMEDDATA") + + if isinstance(arg, DictType): + + self.dur = icaldurationtype_from_string(arg['value']) + Property.__init__(self,ref=arg['ref']) + else: + if isinstance(arg, StringType): + self.dur = icaldurationtype_from_string(arg) + elif isinstance(arg, IntType): + self.dur = icaldurationtype_from_int(arg) + elif isinstance(arg,Duration): + self.dur = arg.dur + else: + self.dur = icaldurationtype_null_duration() + + Property.__init__(self,type=name) + + icalerror_restore("MALFORMEDDATA",e) + + if self.dur == None or icaldurationtype_is_null_duration(self.dur): + raise Property.ConstructorFailedError("Failed to construct Duration from " +str(arg)) + + try: + self._update_value() + except Property.UpdateFailedError: + raise Property.ConstructorFailedError("Failed to construct Duration from " + str(arg)) + + def _update_value(self): + + self.value(icaldurationtype_as_ical_string(self.dur),"DURATION") + + def valid(self): + "Return true if this is a valid duration" + + return not icaldurationtype_is_null_duration(self.dur) + + def seconds(self,v=None): + """Return or set duration in seconds""" + if(v != None): + self.dur = icaldurationtype_from_int(v); + self.dict['value'] = icaltimedurationtype_as_ical_string(self.dur) + return icaldurationtype_as_int(self.dur) diff --git a/src/python/Error.py b/src/python/Error.py new file mode 100644 index 00000000..912553d1 --- /dev/null +++ b/src/python/Error.py @@ -0,0 +1,10 @@ + + +class LibicalError(Exception): + "Libical Error" + + def __init__(self,str): + Exception.__init__(self,str) + + def __str__(self): + return Exception.__str__(self)+"\nLibical errno: "+icalerror_perror() diff --git a/src/python/Gauge.py b/src/python/Gauge.py new file mode 100644 index 00000000..c300232d --- /dev/null +++ b/src/python/Gauge.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python +# -*- Mode: python -*- +#====================================================================== +# FILE: Gauge.py +# CREATOR: mtearle +# +# DESCRIPTION: +# +# +# $Id: Gauge.py,v 1.2 2002-07-08 17:56:11 acampi Exp $ +# $Locker: $ +# +# (C) COPYRIGHT 2001, Eric Busboom <eric@softwarestudio.org> +# (C) COPYRIGHT 2001, Patrick Lewis <plewis@inetarena.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of either: +# +# The LGPL as published by the Free Software Foundation, version +# 2.1, available at: http://www.fsf.org/copyleft/lesser.html +# +# Or: +# +# The Mozilla Public License Version 1.0. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +#====================================================================== + +from LibicalWrap import * +from Error import LibicalError +from Component import Component + +class Gauge: + """ + Base class for gauge + """ + + class ConstructorFailedError(LibicalError): + "Failed to create a Guage " + + class CloneFailedError(LibicalError): + "Failed to clone a component given Gauge " + + class CompareFailedError(LibicalError): + "Failed to compare a component given Gauge " + + def __init__(self,ref=None,sql=None,expand=0): + if ref != None: + self._ref = ref + elif sql != None: + s = str(sql) + self._ref = icalgauge_new_from_sql(s,expand) + else: + Gauge.ConstructorFailedError("No SQL Specified") + + def __del__(self): + if self._ref != None: + icalgauge_free(self._ref) + self._ref = None + + def ref(self): + return self._ref + + def compare(self, comp): + if not isinstance(comp,Component): + raise Gauge.CompareFailedError("Argument is not a component") + + if comp.ref() == None: + raise Gauge.CompareFailedError("Argument is not a component") + + return icalgauge_compare(self._ref, comp.ref()) + + # Pending Implementation + #def as_sql_string(self): + # return self.__str__() + + #def __str__(self): + # return icalgauge_as_sql(self._ref) + + #def clone(self, comp): +# if not isinstance(comp,Component): +# raise Gauge.CloneFailedError("Argument is not a component") +# +# comp_ref = icalgauge_new_clone(self._ref, comp) +# +# if comp_ref == None: +# return None +# +# return Component(ref=comp_ref) diff --git a/src/python/Libical.py b/src/python/Libical.py new file mode 100644 index 00000000..5f4aae70 --- /dev/null +++ b/src/python/Libical.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python +# -*- Mode: python -*- +#====================================================================== +# FILE: Libical.py +# CREATOR: eric +# +# DESCRIPTION: +# +# +# $Id: Libical.py,v 1.19 2002-06-03 13:25:28 acampi Exp $ +# $Locker: $ +# +# (C) COPYRIGHT 2001, Eric Busboom <eric@softwarestudio.org> +# (C) COPYRIGHT 2001, Patrick Lewis <plewis@inetarena.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of either: +# +# The LGPL as published by the Free Software Foundation, version +# 2.1, available at: http://www.fsf.org/copyleft/lesser.html +# +# Or: +# +# The Mozilla Public License Version 1.0. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +#====================================================================== + +from LibicalWrap import ICAL_PACKAGE, ICAL_VERSION +from Component import Component, NewComponent, Event, Todo, Journal +from Property import Property, RecurrenceSet, test_enum +from Time import Time, UTC +from Period import Period +from Duration import Duration +from Attendee import Attendee, Organizer +from DerivedProperties import RDate, Trigger,Recurrence_Id, Attach +from Store import Store, FileStore +from Gauge import Gauge + +version = ICAL_VERSION diff --git a/src/python/LibicalWrap.i b/src/python/LibicalWrap.i new file mode 100644 index 00000000..bc1f199c --- /dev/null +++ b/src/python/LibicalWrap.i @@ -0,0 +1,193 @@ +/* -*- Mode: C -*-*/ +/*====================================================================== + FILE: ical.i + + (C) COPYRIGHT 1999 Eric Busboom + http://www.softwarestudio.org + + The contents of this file are subject to the Mozilla Public License + Version 1.0 (the "License"); you may not use this file except in + compliance with the License. You may obtain a copy of the License at + http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and + limitations under the License. + + The original author is Eric Busboom + + Contributions from: + Graham Davison (g.m.davison@computer.org) + + ======================================================================*/ + +%module LibicalWrap + + +%{ +#include "libical/ical.h" +#include "libicalss/icalss.h" + +#include <sys/types.h> /* for size_t */ +#include <time.h> + +%} + +%pythoncode %{ +import Error + +%} + +%feature("autodoc", "1"); + +typedef int time_t; + + +// This is declared as an extern, but never used in the library. +%ignore icalfileset_safe_saves; + + +// Ignore these declarations because there does not exist a definition for them +%ignore _icalerror_set_errno(icalerrorenum); +%ignore icalattachtype_add_reference(struct icalattachtype* v); +%ignore icalattachtype_get_binary(struct icalattachtype* v); +%ignore icalattachtype_set_binary(struct icalattachtype* v, char* binary, + int owns); +%ignore icalattachtype_get_url(struct icalattachtype* v); +%ignore icalattachtype_set_url(struct icalattachtype* v, char* url); +%ignore icalattachtype_free(struct icalattachtype* v); +%ignore icalattachtype_get_base64(struct icalattachtype* v); +%ignore icalattachtype_new(void); +%ignore icalattachtype_set_base64(struct icalattachtype* v, char* base64, + int owns); +%ignore icalclassify_class_to_string(icalproperty_xlicclass c); +%ignore icalfileset_new_from_cluster(const char* path, icalcluster *cluster); +%ignore icalgauge_as_sql(icalcomponent* gauge); +%ignore icalgauge_new_clone(icalgauge* g, icalcomponent* comp); +%ignore icallangbind_get_component(icalcomponent *c, const char* comp); +%ignore icallangbind_get_parameter(icalproperty *p, const char* parameter); +%ignore icallangbind_get_property(icalcomponent *c, int n, const char* prop); +%ignore icallangbind_get_property_val(icalproperty* p); +%ignore icalmessage_new_cancel_all(icalcomponent* c, + const char* user, + const char* msg); +%ignore icalmessage_new_cancel_event(icalcomponent* c, + const char* user, + const char* msg); +%ignore icalmessage_new_cancel_instance(icalcomponent* c, + const char* user, + const char* msg); +%ignore icalmime_as_mime_string(char* icalcomponent); +%ignore icalparameter_is_valid(icalparameter* parameter); +%ignore icalparser_parse_value(icalvalue_kind kind, + const char* str, icalcomponent** errors); +%ignore icalrecur_iterator_decrement_count(icalrecur_iterator*); +%ignore icalrestriction_is_parameter_allowed(icalproperty_kind property, + icalparameter_kind parameter); +%ignore icalset_clear_select(icalset* set); +%ignore icalspanlist_make_free_list(icalspanlist* sl); +%ignore icalspanlist_make_busy_list(icalspanlist* sl); +%ignore icalspanlist_next_busy_time(icalspanlist* sl, + struct icaltimetype t); +%ignore icaltime_compare_with_zone(const struct icaltimetype a, + const struct icaltimetype b); +%ignore icaltime_days_in_year (const int year); +%ignore icaltime_from_string_with_zone(const char* str, + const icaltimezone *zone); +%ignore icaltime_from_week_number(const int week_number, + const int year); +%ignore icaltime_is_floating(const struct icaltimetype t); +%ignore icaltimezonetype_free(struct icaltimezonetype tzt); + + +// Remove depreciated functions +%ignore icalproperty_string_to_enum(const char* str); +%ignore icaltimezone_get_utc_offset(icaltimezone *zone, + struct icaltimetype *tt, + int *is_daylight); +%ignore icaltimezone_get_utc_offset_of_utc_time (icaltimezone *zone, + struct icaltimetype *tt, + int *is_daylight); +%ignore icaltime_start_doy_of_week(const struct icaltimetype t); +%ignore icalcomponent_get_span(icalcomponent* comp); +%ignore icalproperty_remove_parameter(icalproperty* prop, icalparameter_kind kind); + +// Can't wrap va_list +%ignore icalproperty_add_parameters(struct icalproperty_impl *prop, va_list args); + +#ifndef _DLOPEN_TEST +%ignore icalset_register_class(icalset *set); +#endif + + +//#include "fcntl.h" /* For Open flags */ +%include "libical/ical.h" +%include "libicalss/icalss.h" + +%inline %{ +/* declare some internal functions which are not in the header file. */ +void icalproperty_set_parent(icalproperty* property, + icalcomponent* component); +icalcomponent* icalproperty_get_parent(const icalproperty* property); + +void icalvalue_set_parent(icalvalue* value, + icalproperty* property); +icalproperty* icalvalue_get_parent(icalvalue* value); + +void icalparameter_set_parent(icalparameter* param, + icalproperty* property); +icalproperty* icalparameter_get_parent(icalparameter* value); + +%} + + +%pythoncode %{ + +# Helper functions for overriding default swig property methods +def _swig_set_properties(cls, properties={}): + for propname, props in properties.items(): + if len(props) > 0: + cls.__swig_getmethods__[propname] = props[0] + if len(props) > 1: + cls.__swig_setmethods__[propname] = props[1] + # Currently not used by swig + if len(props) > 2: + cls.__swig_delmethods__[propname] = props[2] + + if _newclass: + setattr(cls, propname, _swig_property(*props)) + +def _swig_remove_private_properties(cls, properties=tuple()): + # By default remove all properties + if not properties: + props = cls.__swig_getmethods__.copy() + props.update(cls.__swig_setmethods__) + #props.update(cls.__swig_delmethods__) + properties = props.keys() + + for propname in properties: + if cls.__swig_getmethods__.has_key(propname): + del cls.__swig_getmethods__[propname] + if cls.__swig_setmethods__.has_key(propname): + del cls.__swig_setmethods__[propname] + # Currently not used by swig + #if cls.__swig_delmethods__.has_key(propname): + # del cls.__swig_delmethods__[propname] + + if _newclass and hasattr(cls, propname): + delattr(cls, propname) + +import new +def _swig_add_instance_methods(klass, meth_dict={}): + for methname, func in meth_dict.items(): + meth = new.instancemethod(func, None, klass) + if not methname: methname = func.__name__ + func.__name__ = methname + setattr(klass, methname, meth) +%} + + +%include "LibicalWrap_icaltimezone.i" +%include "LibicalWrap_icaltime.i" + diff --git a/src/python/LibicalWrap_icaltime.i b/src/python/LibicalWrap_icaltime.i new file mode 100644 index 00000000..6b446912 --- /dev/null +++ b/src/python/LibicalWrap_icaltime.i @@ -0,0 +1,204 @@ + +/*====================================================================== + FILE: LibicalWrap_icaltime.i + + (C) COPYRIGHT 2010 Glenn Washburn + + The contents of this file are subject to the Mozilla Public License + Version 1.0 (the "License"); you may not use this file except in + compliance with the License. You may obtain a copy of the License at + http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and + limitations under the License. + + The original author is Glenn Washburn (crass@berlios.de) + + Contributions from: + + ======================================================================*/ + +// Add some methods to the icaltimetype struct +%extend icaltimetype { + + /* ***** Special methods ***** */ + + int __cmp__(const icaltimetype b) { return icaltime_compare(*($self), b); } + + /* ***** Conversion methods ***** */ + + const char* as_ical_string() { return icaltime_as_ical_string(*($self)); } + time_t as_timet(const icaltimezone *zone=NULL) { + return icaltime_as_timet_with_zone(*($self), zone); + } + + /* ***** Accessor methods ***** */ + + const char *get_tzid() { return icaltime_get_tzid(*($self)); } + int day_of_year() { return icaltime_day_of_year(*($self)); } + int day_of_week() { return icaltime_day_of_week(*($self)); } + + /** Return the day of the year for the Sunday of the week that the + given time is within. */ + /* int start_doy_of_week() { return icaltime_start_doy_of_week(*($self)); } */ + + /** Return the day of the year for the first day of the week that the + given time is within. */ + int start_doy_week(int fdow) { + return icaltime_start_doy_week(*($self), fdow); + } + + /** Return the week number for the week the given time is within */ + int week_number() { return icaltime_week_number(*($self)); } + + + /* ***** Query methods ***** */ + + int is_null_time() { return icaltime_is_null_time(*($self)); } + + /** Returns false if the time is clearly invalid, but is not null. This + is usually the result of creating a new time type buy not clearing + it, or setting one of the flags to an illegal value. */ + int is_valid_time() { return icaltime_is_valid_time(*($self)); } + + /* is_date and is_utc are both over shadowed by the struct accessors, + but they do the same thing. */ + int is_date() { return icaltime_is_date(*($self)); } + int is_utc() { return icaltime_is_utc(*($self)); } + /* int is_floating() { return icaltime_is_floating(*($self)); } */ + + + /* ***** Modify, compare and utility methods ***** */ + + /** Return -1, 0, or 1 to indicate that a<b, a==b or a>b */ + int compare(const icaltimetype b) { return icaltime_compare(*($self), b); } + + /** like icaltime_compare, but only use the date parts. */ + int compare_date_only(const icaltimetype b, icaltimezone *tz=NULL) { + if (tz == NULL) + tz = icaltimezone_get_utc_timezone(); + return icaltime_compare_date_only_tz(*($self), b, tz); + } + + /** Adds or subtracts a number of days, hours, minutes and seconds. */ + void adjust(const int days, const int hours, const int minutes, const int seconds) { + return icaltime_adjust($self, days, hours, minutes, seconds); + } + + /** Normalize the icaltime, so that all fields are within the normal range. */ + icaltimetype normalize() { return icaltime_normalize(*($self)); } + + icaltimetype convert_to_zone(icaltimezone *zone) { + return icaltime_convert_to_zone(*($self), zone); + } + + /* ***** Static methods ***** */ + + static icaltimetype from_timet(const time_t tm, + const int is_date=0, const icaltimezone *zone=NULL) { + return icaltime_from_timet_with_zone(tm, is_date, zone); + } + + static icaltimetype null_time(void) { return icaltime_null_time(); } + static icaltimetype null_date(void) { return icaltime_null_date(); } + + static icaltimetype current_time(const icaltimezone *zone=NULL) { + return icaltime_current_time_with_zone(zone); + } + + static icaltimetype today(void) { return icaltime_today(); } + +#if 0 + static icaltimetype from_string(const char* str, const icaltimezone *zone=NULL) { + /* return _with_zone(str, zone); */ + (void)zone; + return icaltime_from_string(str); + } +#else + /* For the time being do not allow specifying a timezone because this + is unimplemented as of yet. */ + static icaltimetype from_string(const char* str) { + return icaltime_from_string(str); + } +#endif + + /** Return the number of days in the given month */ + static int days_in_month(const int month, const int year) { + return icaltime_days_in_month(month, year); + } + + /** Return whether you've specified a leapyear or not. */ + static int is_leap_year (const int year) { + return icaltime_is_leap_year(year); + } + + /** Return the number of days in this year */ + /* static int days_in_year (const int year) { return icaltime_days_in_year(year); } */ + +} + +// This is a hackish way to support adding the __str__ method to +// a class in python. Its much easier than writing in C (that +// I've figured out). +%pythoncode %{ + +def __icaltimetype_str__(self): + return "<icaltimetype (%d, %d, %d, %d, %d, %d, %d, %d)>" % ( + self.year, self.month, self.day, self.hour, self.minute, + self.second, self.is_date, self.is_daylight) +icaltimetype.__str__ = __icaltimetype_str__ + +import datetime +def icaltimetype_as_datetime(self): + "as_datetime() -> returns datetime object" + return datetime.datetime(self.year, self.month, self.day, self.hour, + self.minute, self.second, 0, self.timezone) +icaltimetype.as_datetime = icaltimetype_as_datetime + +def icaltimetype_from_datetime(dt): + "from_datetime() -> returns icaltimetype object" + tt = icaltimetype() + + tt.year = dt.year + tt.month = dt.month + tt.day = dt.day + tt.hour = dt.hour + tt.minute = dt.minute + tt.second = dt.second + if dt.tzinfo: + # TODO: convert to the right timezone, assume for now we are UTC + tt.zone = 0 + tt.is_utc = True + tt.is_date = False + tt.isdaylight = False + + return tt +icaltimetype.from_datetime = staticmethod(icaltimetype_from_datetime) + +# Remove accessors to private structure members +icaltimetype_delprops = ["is_date", "is_utc", "zone"] + +_swig_remove_private_properties(icaltimetype, icaltimetype_delprops) + + +# Set/Overwrite icaltimetype properties +icaltimetype_props = { + "zone": (_LibicalWrap.icaltime_get_timezone, _LibicalWrap.icaltime_set_timezone, ), + "is_null_time": (_LibicalWrap.icaltime_is_null_time, ), + "is_valid_time": (_LibicalWrap.icaltime_is_valid_time, ), + # These do essentially the same thing as the default swig generated + # accessors is_date and is_utc, but by not defining the setter, we + # make them immutable from python + "is_date": (_LibicalWrap.icaltime_is_date, ), + "is_utc": (_LibicalWrap.icaltime_is_utc, ), +# "is_floating": (_LibicalWrap.icaltime_is_floating, ), +} + +_swig_set_properties(icaltimetype, icaltimetype_props) + +%} + +// TODO: Add icaltime_span_* to icaltime_spantype + diff --git a/src/python/LibicalWrap_icaltimezone.i b/src/python/LibicalWrap_icaltimezone.i new file mode 100644 index 00000000..804a59e6 --- /dev/null +++ b/src/python/LibicalWrap_icaltimezone.i @@ -0,0 +1,216 @@ + +/*====================================================================== + FILE: LibicalWrap_icaltimezone.i + + (C) COPYRIGHT 2010 Glenn Washburn + + The contents of this file are subject to the Mozilla Public License + Version 1.0 (the "License"); you may not use this file except in + compliance with the License. You may obtain a copy of the License at + http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and + limitations under the License. + + The original author is Glenn Washburn (crass@berlios.de) + + Contributions from: + + ======================================================================*/ + +%rename(icaltimezone) _icaltimezone; + +%inline %{ +#include "libical/icaltimezone.h" +#include "libical/icaltimezoneimpl.h" +%} +%include "libical/icaltimezone.h" +%include "libical/icaltimezoneimpl.h" + + +%pythoncode %{ + +import time, datetime + +##### Support datetime.tzinfo API ##### +# This is a "good enough" implementation right now. Make better +# later, if needed. +class icaltzinfo(datetime.tzinfo): + def __init__(self, icaltimezone): + self.tz = icaltimezone + + def __cmp__(self, tzinfo): + return cmp(self.tz, self.tz) + + def utcoffset(self, dt): + timet = time.mktime(dt.timetuple()) + tt = icaltimetype.from_timet(int(timet),0,None) + utcoffset = _LibicalWrap.icaltimezone_get_utc_offset(self.tz, tt, None) + return datetime.timedelta(utcoffset) + + def dst(self, dt): + # FIXME: Since icaltimezone_get_utc_offset does all the + # calc for dst internally and there is not function which + # returns what we need here, we'll probably need to partly + # reimplement icaltimezone_get_utc_offset + return datetime.timedelta(0) + + def tzname(self, dt): + return _LibicalWrap.icaltimezone_get_tzid(self.tz) + +# def fromutc(self, dt): pass + +%} + + +#if 0 + +/** Sets the prefix to be used for tzid's generated from system tzdata. + Must be globally unique (such as a domain name owned by the developer + of the calling application), and begin and end with forward slashes. + Do not change or de-allocate the string buffer after calling this. + */ +void icaltimezone_set_tzid_prefix(const char *new_prefix); + +/** + * @par Accessing timezones. + */ + +/** Free any builtin timezone information **/ +void icaltimezone_free_builtin_timezones(void); + +/** Returns the array of builtin icaltimezones. */ +icalarray* icaltimezone_get_builtin_timezones (void); + +/** + * @par Converting times between timezones. + */ + +void icaltimezone_convert_time (struct icaltimetype *tt, + icaltimezone *from_zone, + icaltimezone *to_zone); + + +/** + * @par Getting offsets from UTC. + */ + +/** Calculates the UTC offset of a given local time in the given + timezone. It is the number of seconds to add to UTC to get local + time. The is_daylight flag is set to 1 if the time is in + daylight-savings time. */ +int icaltimezone_get_utc_offset (icaltimezone *zone, + struct icaltimetype *tt, + int *is_daylight); + +/** Calculates the UTC offset of a given UTC time in the given + timezone. It is the number of seconds to add to UTC to get local + time. The is_daylight flag is set to 1 if the time is in + daylight-savings time. */ +int icaltimezone_get_utc_offset_of_utc_time (icaltimezone *zone, + struct icaltimetype *tt, + int *is_daylight); + + +/* + * @par Handling the default location the timezone files + */ + +/** Set the directory to look for the zonefiles */ +void set_zone_directory(char *path); + +/** Free memory dedicated to the zonefile directory */ +void free_zone_directory(void); +void icaltimezone_release_zone_tab(void); + +/* + * @par Debugging Output. + */ + +/** Dumps information about changes in the timezone up to and including + max_year. */ +int icaltimezone_dump_changes (icaltimezone *zone, + int max_year, + FILE *fp); + +#endif + + +// Add some methods to the icaltimetype struct +%extend _icaltimezone { + + /* Might want to change this to somethingmore reasonable, + like longitude or utc offset. */ + int __cmp__(icaltimezone *zone) { + return strcmp(icaltimezone_get_tzid($self), + icaltimezone_get_tzid(zone)); + } + +} + +%pythoncode %{ + +# Remove accessors to private structure members, which is all of them +_swig_remove_private_properties(icaltimezone) + +def _icaltimezone_set_component_wrap(self, comp): + ret = _LibicalWrap.icaltimezone_set_component(self, comp) + if not ret: + # Not successful, raise an exception because setting a property + # has not return value to be checked. + raise Error.LibicalError("Failed to set component to timezone") + +# Set/Overwrite icaltimezone properties +icaltimezone_props = { + "tzid": (_LibicalWrap.icaltimezone_get_tzid, ), + "location": (_LibicalWrap.icaltimezone_get_location, ), + "tznames": (_LibicalWrap.icaltimezone_get_tznames, ), + "latitude": (_LibicalWrap.icaltimezone_get_latitude, ), + "longitude": (_LibicalWrap.icaltimezone_get_longitude, ), + "display_name": (_LibicalWrap.icaltimezone_get_display_name, ), + "component": (_LibicalWrap.icaltimezone_get_component, + _icaltimezone_set_component_wrap, ), +} + +_swig_set_properties(icaltimezone, icaltimezone_props) + +# UTC = _LibicalWrap.icaltimezone_get_utc_timezone() + +def icaltimezone_copy(self): + tz = _LibicalWrap.icaltimezone_copy(self) + tz.this.acquire() + return tz + +def icaltimezone_new(self): + # Hand off the underlying pointer by setting the this attribute + print "newing icaltimezone" + obj = _LibicalWrap.icaltimezone_new() + obj.this.acquire() + try: self.this.append(obj.this) + except: self.this = obj.this + +def icaltimezone_delete(self): + # do not delete the struct because swig will do this + if self.this.own(): + _LibicalWrap.icaltimezone_free(self, 0) + +icaltimezone_methods = { + 'as_tzinfo': icaltzinfo, + 'copy': icaltimezone_copy, + '__init__': icaltimezone_new, + '__del__': icaltimezone_delete, +} +_swig_add_instance_methods(icaltimezone, icaltimezone_methods) + +icaltimezone.get_builtin_timezone = staticmethod(_LibicalWrap.icaltimezone_get_builtin_timezone) +icaltimezone.get_builtin_timezone_from_offset = staticmethod(_LibicalWrap.icaltimezone_get_builtin_timezone_from_offset) +icaltimezone.get_builtin_timezone_from_tzid = staticmethod(_LibicalWrap.icaltimezone_get_builtin_timezone_from_tzid) + +#icaltimezone.free_builtin_timezones = staticmethod(_LibicalWrap.icaltimezone_free_builtin_timezones) +#icaltimezone.get_builtin_timezones = staticmethod(_LibicalWrap.icaltimezone_get_builtin_timezones) + + +%} + diff --git a/src/python/Makefile.am b/src/python/Makefile.am new file mode 100644 index 00000000..077e03de --- /dev/null +++ b/src/python/Makefile.am @@ -0,0 +1,55 @@ +# See xapian-bindings for an example of integrating autotools, swig and python + +BUILT_SOURCES = _LibicalWrap.c + +pyexec_LTLIBRARIES = _LibicalWrap.la + +common_FILES = \ +__init__.py \ +Libical.py \ +test.py \ +Attendee.py \ +Collection.py \ +Component.py \ +DerivedProperties.py \ +Duration.py \ +Error.py \ +Gauge.py \ +Period.py \ +Property.py \ +Store.py \ +Time.py + +# Install as python source so the code gets byte-compiled at install time. +pkgpython_PYTHON = \ +$(common_FILES) \ +LibicalWrap.py + +# To allow non-standard library names (ie those not prefixed by "lib") see: +# http://sources.redhat.com/automake/automake.html#Libtool-Modules +_LibicalWrap_la_SOURCES = _LibicalWrap.c +_LibicalWrap_la_LDFLAGS = -avoid-version -module -lc +_LibicalWrap_la_LIBADD = $(top_builddir)/src/libical/libical.la \ + $(top_builddir)/src/libicalss/libicalss.la + +AM_CPPFLAGS = \ + -I$(top_builddir) \ + -I$(top_srcdir)/src \ + -I$(top_builddir)/src \ + -I$(top_srcdir)/src/libical \ + -I$(top_builddir)/src/libical \ + -I$(top_srcdir)/src/libicalss \ + $(PY_CFLAGS) + +_LibicalWrap.c: $(srcdir)/LibicalWrap.i $(srcdir)/*.i $(top_builddir)/src/libical/ical.h $(top_builddir)/src/libicalss/icalss.h + swig -python -Wall $(AM_CPPFLAGS) -o _LibicalWrap.c $(srcdir)/LibicalWrap.i + +CLEANFILES = _LibicalWrap.c _LibicalWrap_wrap.doc Libical.pyc LibicalWrap.py _LibicalWrap.so + +EXTRA_DIST = \ +$(common_FILES) \ +LibicalWrap.i \ +python-binding.txt \ +ChangeLog + + diff --git a/src/python/Makefile.in b/src/python/Makefile.in new file mode 100644 index 00000000..c71c8f35 --- /dev/null +++ b/src/python/Makefile.in @@ -0,0 +1,651 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# See xapian-bindings for an example of integrating autotools, swig and python + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = src/python +DIST_COMMON = $(pkgpython_PYTHON) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in ChangeLog +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(pyexecdir)" "$(DESTDIR)$(pkgpythondir)" +LTLIBRARIES = $(pyexec_LTLIBRARIES) +_LibicalWrap_la_DEPENDENCIES = $(top_builddir)/src/libical/libical.la \ + $(top_builddir)/src/libicalss/libicalss.la +am__LibicalWrap_la_OBJECTS = _LibicalWrap.lo +_LibicalWrap_la_OBJECTS = $(am__LibicalWrap_la_OBJECTS) +_LibicalWrap_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(_LibicalWrap_la_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(_LibicalWrap_la_SOURCES) +DIST_SOURCES = $(_LibicalWrap_la_SOURCES) +py_compile = $(top_srcdir)/py-compile +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BDB_DIR = @BDB_DIR@ +BDB_DIR_INCLUDE = @BDB_DIR_INCLUDE@ +BDB_DIR_LIB = @BDB_DIR_LIB@ +BDB_LIB = @BDB_LIB@ +BDB_VERSION = @BDB_VERSION@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +JAR = @JAR@ +JAVA = @JAVA@ +JAVAC = @JAVAC@ +JAVAH = @JAVAH@ +JAVA_PLATFORM = @JAVA_PLATFORM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PTHREAD_LIBS = @PTHREAD_LIBS@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +PY_CFLAGS = @PY_CFLAGS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZONE_INFO = @ZONE_INFO@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +swig_val = @swig_val@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +BUILT_SOURCES = _LibicalWrap.c +pyexec_LTLIBRARIES = _LibicalWrap.la +common_FILES = \ +__init__.py \ +Libical.py \ +test.py \ +Attendee.py \ +Collection.py \ +Component.py \ +DerivedProperties.py \ +Duration.py \ +Error.py \ +Gauge.py \ +Period.py \ +Property.py \ +Store.py \ +Time.py + + +# Install as python source so the code gets byte-compiled at install time. +pkgpython_PYTHON = \ +$(common_FILES) \ +LibicalWrap.py + + +# To allow non-standard library names (ie those not prefixed by "lib") see: +# http://sources.redhat.com/automake/automake.html#Libtool-Modules +_LibicalWrap_la_SOURCES = _LibicalWrap.c +_LibicalWrap_la_LDFLAGS = -avoid-version -module -lc +_LibicalWrap_la_LIBADD = $(top_builddir)/src/libical/libical.la \ + $(top_builddir)/src/libicalss/libicalss.la + +AM_CPPFLAGS = \ + -I$(top_builddir) \ + -I$(top_srcdir)/src \ + -I$(top_builddir)/src \ + -I$(top_srcdir)/src/libical \ + -I$(top_builddir)/src/libical \ + -I$(top_srcdir)/src/libicalss \ + $(PY_CFLAGS) + +CLEANFILES = _LibicalWrap.c _LibicalWrap_wrap.doc Libical.pyc LibicalWrap.py _LibicalWrap.so +EXTRA_DIST = \ +$(common_FILES) \ +LibicalWrap.i \ +python-binding.txt \ +ChangeLog + +all: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/python/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/python/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-pyexecLTLIBRARIES: $(pyexec_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(pyexecdir)" || $(MKDIR_P) "$(DESTDIR)$(pyexecdir)" + @list='$(pyexec_LTLIBRARIES)'; test -n "$(pyexecdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pyexecdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pyexecdir)"; \ + } + +uninstall-pyexecLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(pyexec_LTLIBRARIES)'; test -n "$(pyexecdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pyexecdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pyexecdir)/$$f"; \ + done + +clean-pyexecLTLIBRARIES: + -test -z "$(pyexec_LTLIBRARIES)" || rm -f $(pyexec_LTLIBRARIES) + @list='$(pyexec_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +_LibicalWrap.la: $(_LibicalWrap_la_OBJECTS) $(_LibicalWrap_la_DEPENDENCIES) + $(_LibicalWrap_la_LINK) -rpath $(pyexecdir) $(_LibicalWrap_la_OBJECTS) $(_LibicalWrap_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/_LibicalWrap.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-pkgpythonPYTHON: $(pkgpython_PYTHON) + @$(NORMAL_INSTALL) + test -z "$(pkgpythondir)" || $(MKDIR_P) "$(DESTDIR)$(pkgpythondir)" + @list='$(pkgpython_PYTHON)'; dlist=; list2=; test -n "$(pkgpythondir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then b=; else b="$(srcdir)/"; fi; \ + if test -f $$b$$p; then \ + $(am__strip_dir) \ + dlist="$$dlist $$f"; \ + list2="$$list2 $$b$$p"; \ + else :; fi; \ + done; \ + for file in $$list2; do echo $$file; done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgpythondir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgpythondir)" || exit $$?; \ + done || exit $$?; \ + if test -n "$$dlist"; then \ + if test -z "$(DESTDIR)"; then \ + PYTHON=$(PYTHON) $(py_compile) --basedir "$(pkgpythondir)" $$dlist; \ + else \ + PYTHON=$(PYTHON) $(py_compile) --destdir "$(DESTDIR)" --basedir "$(pkgpythondir)" $$dlist; \ + fi; \ + else :; fi + +uninstall-pkgpythonPYTHON: + @$(NORMAL_UNINSTALL) + @list='$(pkgpython_PYTHON)'; test -n "$(pkgpythondir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + filesc=`echo "$$files" | sed 's|$$|c|'`; \ + fileso=`echo "$$files" | sed 's|$$|o|'`; \ + echo " ( cd '$(DESTDIR)$(pkgpythondir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkgpythondir)" && rm -f $$files || exit $$?; \ + echo " ( cd '$(DESTDIR)$(pkgpythondir)' && rm -f" $$filesc ")"; \ + cd "$(DESTDIR)$(pkgpythondir)" && rm -f $$filesc || exit $$?; \ + echo " ( cd '$(DESTDIR)$(pkgpythondir)' && rm -f" $$fileso ")"; \ + cd "$(DESTDIR)$(pkgpythondir)" && rm -f $$fileso + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(pyexecdir)" "$(DESTDIR)$(pkgpythondir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +clean: clean-am + +clean-am: clean-generic clean-libtool clean-pyexecLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-pkgpythonPYTHON + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-pyexecLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-pkgpythonPYTHON uninstall-pyexecLTLIBRARIES + +.MAKE: all check install install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-pyexecLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-pkgpythonPYTHON install-ps \ + install-ps-am install-pyexecLTLIBRARIES install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-pkgpythonPYTHON \ + uninstall-pyexecLTLIBRARIES + + +_LibicalWrap.c: $(srcdir)/LibicalWrap.i $(srcdir)/*.i $(top_builddir)/src/libical/ical.h $(top_builddir)/src/libicalss/icalss.h + swig -python -Wall $(AM_CPPFLAGS) -o _LibicalWrap.c $(srcdir)/LibicalWrap.i + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/python/Period.py b/src/python/Period.py new file mode 100644 index 00000000..fb998160 --- /dev/null +++ b/src/python/Period.py @@ -0,0 +1,214 @@ +#!/usr/bin/env python +# -*- Mode: python -*- +#====================================================================== +# FILE: Period.py +# CREATOR: eric +# +# DESCRIPTION: +# +# +# $Id: Period.py,v 1.1 2001-04-03 15:18:42 ebusboom Exp $ +# $Locker: $ +# +# (C) COPYRIGHT 2001, Eric Busboom <eric@softwarestudio.org> +# (C) COPYRIGHT 2001, Patrick Lewis <plewis@inetarena.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of either: +# +# The LGPL as published by the Free Software Foundation, version +# 2.1, available at: http://www.fsf.org/copyleft/lesser.html +# +# Or: +# +# The Mozilla Public License Version 1.0. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +#=========================================================== + +from LibicalWrap import * +from Property import Property +from types import DictType, StringType, IntType +from Time import Time +from Duration import Duration + +class Period(Property): + """Represent a span of time""" + def __init__(self,arg,name='FREEBUSY'): + """ """ + + Property.__init__(self, type = name) + + self.pt=None + + #icalerror_clear_errno() + e1=icalerror_supress("MALFORMEDDATA") + e2=icalerror_supress("BADARG") + + if isinstance(arg, DictType): + + + es=icalerror_supress("MALFORMEDDATA") + self.pt = icalperiodtype_from_string(arg['value']) + icalerror_restore("MALFORMEDDATA",es) + + Property.__init__(self, ref=arg['ref']) + else: + if isinstance(arg, StringType): + + self.pt = icalperiodtype_from_string(arg) + + else: + self.pt = icalperiodtype_null_period() + + Property.__init__(self,type=name) + + icalerror_restore("MALFORMEDDATA",e1) + icalerror_restore("BADARG",e2) + + + if self.pt == None or icalperiodtype_is_null_period(self.pt): + raise Property.ConstructorFailedError("Failed to construct Period") + + + try: + self._update_value() + except Property.UpdateFailedError: + raise Property.ConstructorFailedError("Failed to construct Period") + + def _end_is_duration(self): + dur = self.pt.duration + if not icaldurationtype_is_null_duration(dur): + return 1 + return 0 + + def _end_is_time(self): + end = self.pt.end + if not icaltime_is_null_time(end): + return 1 + return 0 + + def _update_value(self): + + self.value(icalperiodtype_as_ical_string(self.pt),"PERIOD") + + + def valid(self): + "Return true if this is a valid period" + + return not icalperiodtype_is_null_period(self.dur) + + def start(self,v=None): + """ + Return or set start time of the period. The start time may be + expressed as an RFC2445 format string or an instance of Time. + The return value is an instance of Time + """ + + if(v != None): + if isinstance(t,Time): + t = v + elif isinstance(t,StringType) or isinstance(t,IntType): + t = Time(v,"DTSTART") + else: + raise TypeError + + self.pt.start = t.tt + + self._update_value() + + + return Time(self.pt.start.as_timet(), + "DTSTART") + + def end(self,v=None): + """ + Return or set end time of the period. The end time may be + expressed as an RFC2445 format string or an instance of Time. + The return value is an instance of Time. + + If the Period has a duration set, but not an end time, this + method will caluculate the end time from the duration. """ + + if(v != None): + + if isinstance(t,Time): + t = v + elif isinstance(t,StringType) or isinstance(t,IntType): + t = Time(v) + else: + raise TypeError + + if(self._end_is_duration()): + start = self.pt.start.as_timet() + dur = t.utc_seconds()-start; + self.pt.duration = icaldurationtype_from_int(dur) + else: + self.pt.end = t.tt + + self._update_value() + + if(self._end_is_time()): + rt = Time(self.pt.end.as_timet(), + 'DTEND') + rt.timezone(self.timezone()) + return rt + elif(self._end_is_duration()): + start = self.pt.start.as_timet() + dur = icaldurationtype_as_int(self.pt.duration) + rt = Time(start+dur,'DTEND') + rt.timezone(self.timezone()) + return rt + else: + return Time({},'DTEND') + + + + def duration(self,v=None): + """ + Return or set the duration of the period. The duration may be + expressed as an RFC2445 format string or an instance of Duration. + The return value is an instance of Duration. + + If the period has an end time set, but not a duration, this + method will calculate the duration from the end time. """ + + if(v != None): + + if isinstance(t,Duration): + d = v + elif isinstance(t,StringType) or isinstance(t,IntType): + d = Duration(v) + else: + raise TypeError + + if(self._end_is_time()): + start = self.pt.start.as_timet() + end = start + d.seconds() + + self.pt.end = icaltimetype.from_timet(end) + else: + self.pt.duration = d.dur + + if(self._end_is_time()): + start = self.pt.start.as_timet() + end = self.pt.end.as_timet() + + print "End is time " + str(end-start) + + return Duration(end-start,"DURATION") + + elif(self._end_is_duration()): + dur = icaldurationtype_as_int(self.pt.duration) + + return Duration(dur,"DURATION") + else: + + + return Duration(0,"DURATION") + + + def timezone(self,v=None): + """ Return or set the timezone string for this time """ + if (v != None): + self['TZID'] = v + return self['TZID'] diff --git a/src/python/Property.py b/src/python/Property.py new file mode 100644 index 00000000..a53585ea --- /dev/null +++ b/src/python/Property.py @@ -0,0 +1,269 @@ +#!/usr/bin/env python +# -*- Mode: python -*- +#====================================================================== +# FILE: Property.py +# CREATOR: eric +# +# DESCRIPTION: +# +# +# $Id: Property.py,v 1.13 2002-10-24 13:44:30 acampi Exp $ +# $Locker: $ +# +# (C) COPYRIGHT 2001, Eric Busboom <eric@softwarestudio.org> +# (C) COPYRIGHT 2001, Patrick Lewis <plewis@inetarena.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of either: +# +# The LGPL as published by the Free Software Foundation, version +# 2.1, available at: http://www.fsf.org/copyleft/lesser.html +# +# Or: +# +# The Mozilla Public License Version 1.0. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +#====================================================================== + +from LibicalWrap import * +import re +import base64 +from string import index, upper, split +from types import StringType + +#def icalerror_supress(arg): +# pass + +#def icalerror_restore(a,b): +# pass + +def error_type(): + error = icalerror_perror() + return error[:index(error,':')] + +def test_enum(prop,enum): + + vkind = icalvalue_string_to_kind(prop) + e = icalproperty_kind_and_string_to_enum(vkind, enum) + + if e != 0: + return 1 + + return None + + +class Property(object): + """ Represent any iCalendar Property. + + Usage: + Property(dict) + + Where: + dict is a dictionary with keys of 'name', 'value_type', and 'value'. + In addition, parameter:parameter value entries may be included. + """ + + class ConstructorFailedError(Exception): + "Failed to construct a property" + + class UpdateFailedError(Exception): + "Failed to update the value of a property" + + + def __init__(self, type = None, ref = None): + + + #~ assert(ref == None or isinstance(ref,StringType)) + #~ assert(type == None or isinstance(type,StringType)) + + self._ref = None + + if ref != None: + self._ref = ref + elif type != None: + kind = icalproperty_string_to_kind(type) + self._ref = icalproperty_new(kind) + + if type.find("X-") == 0: + icalproperty_set_x_name(self._ref, type) + + if self._ref == None or self._ref == 'NULL': + raise Property.ConstructorFailedError("Failed to construct Property: %s (%s)"%(type, ref)) + + self._deleted = 0; + + # Initialize all of the required keys + + + def __del__(self): + + self._deleted = 1; + + if not self._deleted and \ + self.ref() and \ + icalproperty_get_parent(self.ref()) == 'NULL': + + icalproperty_free(self.ref()) + + def name(self,v=None): + """ Return the name of the property """ + return icalproperty_get_property_name(self._ref) + + def ref(self,v=None): + """ Return the internal reference to the libical icalproperty """ + if(v != None): + + if not self._deleted and self._ref and \ + icalproperty_get_parent(self._ref) == 'NULL': + + icalproperty_free(self._ref) + + self._ref = v + + return self._ref + + + def value(self,v=None, kind = None): + """ Return the RFC2445 representation of the value """ + + if(v != None): + + if kind != None: + # Get the default kind of value for this property + default_kind = icalvalue_kind_to_string( + icalproperty_kind_to_value_kind( + icalproperty_string_to_kind(self.name()))) + + if(kind != default_kind): + self.__setitem__('VALUE',kind) + vt = kind + elif self.__getitem__('VALUE'): + vt = self.__getitem__('VALUE') + print "###########", self + else: + vt = 'NO' # Use the kind of the existing value + + + icalerror_clear_errno() + + #e1=icalerror_supress("MALFORMEDDATA") + if (self.name() == None or self.name().find("X-") == 0) and type(v) is StringType: + v = icallangbind_quote_as_ical(v) + + if isinstance(v, unicode): + v = v.encode('utf8') + + icalproperty_set_value_from_string(self._ref,str(v),vt) + #icalerror_restore("MALFORMEDDATA",e1) + + if error_type() != "NO": + raise Property.UpdateFailedError(error_type()) + + s = icalproperty_get_value_as_string(self._ref) + + return icalproperty_get_value_as_string(self._ref) + + def parameters(self): + """ + Return a list of parameters + """ + + params = [] + + p = icallangbind_get_first_parameter(self._ref) + + while p != None: + kv = split(icalparameter_as_ical_string(p),'=',2) + params.append(kv[0]) + p = icallangbind_get_next_parameter(self._ref) + + return params + + def as_ical_string(self): + "Return the property in iCalendar text format." + return icalproperty_as_ical_string(self._ref) + + def __getitem__(self,key): + """ Return property values by name """ + key = upper(key) + str = icalproperty_get_parameter_as_string(self._ref,key) + + if(str == 'NULL'): return None + + return str + + def __setitem__(self,key,value): + """ Set Property Values by Name """ + key = upper(key) + + icalproperty_set_parameter_from_string(self._ref,key,value) + + return self.__getitem__(key) + + def __delitem__(self,key): + """ Remove Property Values by Name """ + key = upper(key) + + if self.__getitem__(key): + icalproperty_remove_parameter_by_name(self._ref,key) + + def __str__(self): + + str = self.as_ical_string() + return re.sub('\r?\n ?','',str) + + def __cmp__(self, other): + s_str = str(self) + o_str = str(other) + + return cmp(s_str,o_str) + + +class RecurrenceSet: + """ + Represents a set of event occurrences. This + class controls a component's RRULE, EXRULE, RDATE and EXDATE + properties and can produce from them a set of occurrences. + """ + + def __init__(self): + pass + + def include(self, **params): + """ + Include a date or rule to the set. + + Use date= or pass in a + Time instance to include a date. Included dates will add an + RDATE property or will remove an EXDATE property of the same + date. + + Use rule= or pass in a string to include a rule. Included + rules with either add a RRULE property or remove an EXRULE + property. + + """ + pass + + def exclude(self, **params): + """ + Exclude date or rule to the set. + + Use date= or pass in a Time instance to exclude a + date. Excluded dates will add an EXDATE property or will remove + an RDATE property of the same date. + + Use rule= or pass in a string to exclude a rule. Excluded + rules with either add an EXRULE property or remove an RRULE + property. + + """ + pass + + def occurrences(self, count=None): + """ + Return 'count' occurrences as a tuple of Time instances. + """ + pass + + diff --git a/src/python/Store.py b/src/python/Store.py new file mode 100644 index 00000000..9ecea991 --- /dev/null +++ b/src/python/Store.py @@ -0,0 +1,181 @@ +#!/usr/bin/env python +# -*- Mode: python -*- +#====================================================================== +# FILE: Store.py +# CREATOR: eric +# +# DESCRIPTION: +# +# +# $Id: Store.py,v 1.4 2002-07-08 17:56:11 acampi Exp $ +# $Locker: $ +# +# (C) COPYRIGHT 2001, Eric Busboom <eric@softwarestudio.org> +# (C) COPYRIGHT 2001, Patrick Lewis <plewis@inetarena.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of either: +# +# The LGPL as published by the Free Software Foundation, version +# 2.1, available at: http://www.fsf.org/copyleft/lesser.html +# +# Or: +# +# The Mozilla Public License Version 1.0. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +#====================================================================== + +from LibicalWrap import * +from Error import LibicalError +from Component import Component, CloneComponent +from Gauge import Gauge + +class Store: + """ + Base class for several component storage methods + """ + + class AddFailedError(LibicalError): + "Failed to add a property to the file store" + + class ConstructorFailedError(LibicalError): + "Failed to create a Store " + + def __init__(self): + pass + + def path(self): + pass + + def mark(self): + pass + + def commit(self): + pass + + def add_component(self, comp): + pass + + def remove_component(self, comp): + pass + + def count_components(self, kind): + pass + + def select(self, gauge): + pass + + def clearSelect(self): + pass + + def fetch(self, uid): + pass + + def fetchMatch(self, comp): + pass + + def modify(self, oldc, newc): + pass + + def current_component(self): + pass + + def first_component(self): + pass + + def next_component(self): + pass + + +class FileStore(Store): + + def __init__(self, file): + e1=icalerror_supress("FILE") + self._ref = icalfileset_new(file) + icalerror_restore("FILE",e1) + + if self._ref == None or self._ref == 'NULL': + raise Store.ConstructorFailedError(file) + + def __del__(self): + icalfileset_free(self._ref) + + def path(self): + return icalfileset_path(self._ref) + + def mark(self): + icalfileset_mark(self._ref) + + def commit(self): + icalfileset_commit(self._ref) + + def add_component(self, comp): + if not isinstance(comp,Component): + raise Store.AddFailedError("Argument is not a component") + + error = icalfileset_add_component(self._ref,comp.ref()) + + def remove_component(self, comp): + if not isinstance(comp,Component): + raise Store.AddFailedError("Argument is not a component") + + error = icalfileset_remove_component(self._ref,comp.ref()) + + def count_components(self, kind): + _kind = icalcomponent_string_to_kind(kind) + + return icalfileset_count_components(self._ref, _kind) + + def select(self, gauge): + error = icalfileset_select(self._ref, gauge.ref()) + + def clearSelect(self): + icalfileset_clear(self._ref) + + def fetch(self, uid): + comp_ref = icalfileset_fetch(self._ref, uid) + + if comp_ref == None: + return None + + return CloneComponent(comp_ref) + + def fetchMatch(self, comp): + if not isinstance(comp,Component): + raise Store.AddFailedError("Argument is not a component") + + comp_ref = icalfileset_fetch_match(self._ref,comp.ref()) + + if comp_ref == None: + return None + + return CloneComponent(comp_ref) + + def modify(self, oldc, newc): + pass + + def current_component(self): + comp_ref = icalfileset_get_current_component(self._ref) + + if comp_ref == None: + return None + + return CloneComponent(comp_ref) + + def first_component(self): + comp_ref = icalfileset_get_first_component(self._ref) + + if comp_ref == None: + return None + + return CloneComponent(comp_ref) + + def next_component(self): + + comp_ref = icalfileset_get_next_component(self._ref) + + if comp_ref == None: + return None + + return CloneComponent(comp_ref) + diff --git a/src/python/Time.py b/src/python/Time.py new file mode 100644 index 00000000..8e6e5f24 --- /dev/null +++ b/src/python/Time.py @@ -0,0 +1,226 @@ +#!/usr/bin/env python +# -*- Mode: python -*- +#====================================================================== +# FILE: Time.py +# CREATOR: eric +# +# DESCRIPTION: +# +# +# $Id: Time.py,v 1.3 2002-07-12 08:02:46 acampi Exp $ +# $Locker: $ +# +# (C) COPYRIGHT 2001, Eric Busboom <eric@softwarestudio.org> +# (C) COPYRIGHT 2001, Patrick Lewis <plewis@inetarena.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of either: +# +# The LGPL as published by the Free Software Foundation, version +# 2.1, available at: http://www.fsf.org/copyleft/lesser.html +# +# Or: +# +# The Mozilla Public License Version 1.0. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +#====================================================================== + +from LibicalWrap import * +from Property import Property +from types import DictType, StringType, IntType, FloatType +from Duration import Duration + +UTC = icaltimezone_get_utc_timezone() + +class Time(Property): + """ Represent iCalendar DATE, TIME and DATE-TIME """ + def __init__(self, arg, name="DTSTART", zone=None): + """ + Create a new Time from a string or number of seconds past the + POSIX epoch + + Time("19970325T123000Z") Construct from an iCalendar string + Time(8349873494) Construct from seconds past POSIX epoch + + """ + e1=icalerror_supress("MALFORMEDDATA") + e2=icalerror_supress("BADARG") + + if isinstance(arg, DictType): + # Dictionary -- used for creating from Component + self.tt = icaltime_from_string(arg['value']) + Property.__init__(self, ref=arg['ref']) + else: + if isinstance(arg, StringType): + # Create from an iCal string + self.tt = icaltime_from_string(arg) + elif isinstance(arg, IntType) or \ + isinstance(arg, FloatType): + # Create from seconds past the POSIX epoch + if zone: + self.tt = icaltime_from_timet_with_zone(int(arg),0,icaltimezone_get_builtin_timezone(zone)) + else: + self.tt = icaltime_from_timet_with_zone(int(arg),0,icaltimezone_get_utc_timezone()) + elif isinstance(arg, Time): + # Copy an instance + self.tt = arg.tt + else: + self.tt = icaltime_null_time() + + Property.__init__(self,type=name) + + icalerror_restore("MALFORMEDDATA",e1) + icalerror_restore("BADARG",e2) + + if icaltime_is_null_time(self.tt): + raise Property.ConstructorFailedError("Failed to construct a Time") + + try: + self._update_value() + except Property.UpdateFailedError: + raise Property.ConstructorFailedError("Failed to construct a Time") + + def _update_value(self): + self.normalize() + self.value(icaltime_as_ical_string(self.tt),"DATE-TIME") + + def valid(self): + " Return true if this is a valid time " + return not icaltime_is_null_time(self.tt) + + def utc_seconds(self,v=None): + """ Return or set time in seconds past POSIX epoch""" + tz = icaltimezone_get_builtin_timezone(self.timezone()) + if (v!=None): + self.tt = icaltime_from_timet_with_zone(v,0,tz) + self._update_value() + + return icaltime_as_timet_with_zone(self.tt, tz) + + def is_utc(self): + """ Return a boolean indicating if time is in UTC """ + return icaltime_is_utc(self.tt) + + def is_date(self): + """ Return a boolean indicating if time is actually a date """ + return icaltime_is_date(self.tt) + + def timezone(self,v=None): + """ Return, set (if none) or alter the timezone for this time """ + + origtz = icaltime_get_tzid(self.tt) + + if (v != None): + assert(isinstance(v,StringType) ) + if (v == "UTC"): + tz = icaltimezone_get_utc_timezone() + del self['TZID'] + else: + tz = icaltimezone_get_builtin_timezone(v) + + if not origtz: + self.tt = icaltime_set_timezone(self.tt, tz) + else: + self.tt = icaltime_convert_to_zone(self.tt,tz) + + if (icaltime_get_tzid(self.tt) != "UTC"): + self['TZID'] = icaltime_get_tzid(self.tt) + + self._update_value() + return icaltime_get_tzid(self.tt) + + def normalize(self): + self.tt = icaltime_normalize(self.tt) + + def __second_property(self,v=None): + """ Get or set the seconds component of this time """ + if(v != None): + self.tt.second = v + self._update_value() + return self.tt.second + second = property(__second_property, __second_property) + + def __minute_property(self,v=None): + """ Get or set the minute component of this time """ + if(v != None): + self.tt.minute = v + self._update_value() + return self.tt.minute + minute = property(__minute_property, __minute_property) + + def __hour_property(self,v=None): + """ Get or set the hour component of this time """ + if(v != None): + self.tt.hour = v + self._update_value() + return self.tt.hour + hour = property(__hour_property, __hour_property) + + def __day_property(self,v=None): + """ Get or set the month day component of this time """ + if(v != None): + self.tt.day = v + self._update_value() + return self.tt.day + day = property(__day_property, __day_property) + + def __month_property(self,v=None): + """ Get or set the month component of this time. January is month 1 """ + if(v != None): + self.tt.month = v + self._update_value() + return self.tt.month + month = property(__month_property, __month_property) + + def __year_property(self,v=None): + """ Get or set the year component of this time """ + if(v != None): + self.tt.year = v + self._update_value() + return self.tt.year + year = property(__year_property, __year_property) + + + def __cmp__(self,other): + + if other == None: + return cmp(self.utc_seconds(),None) + + return cmp(self.utc_seconds(),other.utc_seconds()) + + + def __add__(self,o): + + other = Duration(o,"DURATION") + + if not other.valid(): + return Duration(0,"DURATION") + + print self.utc_seconds(), other.seconds() + seconds = self.utc_seconds() + other.seconds() + + new = Time(seconds,self.name(),self.timezone()) + + return new + + def __radd_(self,o): + return self.__add__(o) + + + def __sub__(self,o): + + + if isinstance(o,Time): + # Subtract a time from this time and return a duration + seconds = self.utc_seconds() - other.utc_seconds() + return Duration(seconds) + elif isinstance(o,Duration): + # Subtract a duration from this time and return a time + other = Duration(o) + if(not other.valid()): + return Time() + + seconds = self.utc_seconds() - other.seconds() + return Time(seconds) + else: + raise TypeError, "subtraction with Time reqires Time or Duration" diff --git a/src/python/__init__.py b/src/python/__init__.py new file mode 100644 index 00000000..bbae718c --- /dev/null +++ b/src/python/__init__.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python +# -*- Mode: python -*- +#====================================================================== +# FILE: __init__.py +# CREATOR: glenn +# +# DESCRIPTION: +# +# +# (C) COPYRIGHT 2001, Eric Busboom <eric@softwarestudio.org> +# (C) COPYRIGHT 2001, Patrick Lewis <plewis@inetarena.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of either: +# +# The LGPL as published by the Free Software Foundation, version +# 2.1, available at: http://www.fsf.org/copyleft/lesser.html +# +# Or: +# +# The Mozilla Public License Version 1.0. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +#====================================================================== + +from Libical import * diff --git a/src/python/littlefile.txt b/src/python/littlefile.txt new file mode 100644 index 00000000..cba08911 --- /dev/null +++ b/src/python/littlefile.txt @@ -0,0 +1,3 @@ +This is just a small file to test mime encoding. + +There isn't much here at all. diff --git a/src/python/python-binding.txt b/src/python/python-binding.txt new file mode 100644 index 00000000..7f925e24 --- /dev/null +++ b/src/python/python-binding.txt @@ -0,0 +1,434 @@ + +Classes for python binding to libical +(Indentation indicates inheritance) + + Component + Event + JournalEntry + Todo + FreeBusy + Timezone + Alarm + AudioAlarm + EmailAlarm + ProcedureAlarm + DisplayAlarm + + Property + Attendee + Organizer + Status + Error + + Time + Period + Date + RecurrenceSet + + Timezone + TimezonePhase + + Store + FileStore + DirStore + CAPStore + HeapStore + MySQLStore + + + +Component is the central class in the design. The component can be +though of as a container for child components and properties, or as +representation of a specific kind of iCal object. The first +interface offers general property and component accessors, and the +second treats some types of objects in a special way. + +The general interface offers simple manipulators for child property +and components, and it only works with immediate children. So, given +the Component: + + BEGIN:VCALENDAR + METHOD:PUBLISH + BEGIN:VEVENT + BEGIN:VALARM + COMMENT: An Alarm + END:VALARM + END:VEVENT + END:VCALENDAR + +A caller would have to descend three levels to access the COMMENT +property in the alarm, but only one to access the METHOD property. + +Libical is almost entirely dedicated to the general interface; it +includes all of the *get_first_*, *_next_next_*, *_add_* and *_remove_* +routines. + +The specific interface works with derived classes of Property and +Component. In this interface, the caller could get the COMMENT in the +alarm in the example in two steps. First the caller would ask the +Event object for its alarms, then then the caller would ask the first +Alarm object for its comment. + +The Specific interface is part of the +derived classes of Component. This interface names all of the types of +properties and components that can be accessed from the derived +component type. + +In libical, the specific interface is primarily the "convenience +routines in icalcomponent.h, such as: + + + struct icaltimetype icalcomponent_get_dtend(icalcomponent* comp); + void icalcomponent_set_dtend(icalcomponent* comp, struct icaltimetype v); + + void icalcomponent_set_duration(icalcomponent* comp, + struct icaldurationtype v); + struct icaldurationtype icalcomponent_get_duration(icalcomponent* comp); + +These routines are smarter and do more work than the general +interface. From the general interface, you can set the DTEND +property of a component by creating the property and adding it to a +component. But, if the component already has a DURATION property, then +this is an error -- a component can't have both. + +icalcomponent_set_dtend determines if the component already has a +DURATION. If it does, it substracts the dtstart time from the new +dtend time and sets the duration to that. Otherwise, it creates aor +changes the DTEND. + +Also, icalcomponent_set_duration works the same regardless if the +component is a VCALENDAR or a VEVENT. If it is a VCALENDAR, the +routine descends into the VEVENT before making any changes. If it is +allready a VEVENT ( or VTODO or VJOURNAL ) the routine just makes the +changes. With icalcomponent_add_property, you need to do this check +yourself. + +( There should probably be a class between Component +and Event ,JournalEntry and Todo that names all of the properties and +components. Then Event, JournalEntry and Todo would remove the +accessors that did not apply to them. ) + +Parameters are accessed as dictionaries from Property or as attributes +of a derived class of Property. Both the names and the values of the +parameters are strings. + +The Store hierarchy is a interface to various ways to store iCal +components. Each of these has the same interface as its corresponding +libical module: + + FileStore icalfileset Store iCal components in a single file + DirStore icaldirset Use multiple files, one per month of + DTSTART + CAPStore Access components in a CAP server + HeapStore Components stored in memory + MySQLStore Components stored in a MySQL + database. + +The only iCal value objects that will be implemented as Python classes +are Time, Duration and Period. RecurrenceSet handles recurrence +rules. It replaces the properties RRULE, RDATE, EXRULE and EXDATE. + +(Not all of the libical modules are implemented ) + + +How to Use the library +---------------------- + +The most common usecases will be something like this: + +1)Caller opens a Store object on a file, server or database. The +caller retrieves one or more component. Some of the components will be +booked on the user's calendar. Other components will be messages that +other users have sent, like requests for meetings. + +2) The caller will use the Specific interface ( using methods specific +to each property ) to example the component and decide what to do with +it. + +3) Rarely, the caller will access the general interface to do things +that the specific interface has not implemented or cannot manage +well. + +4) Caller may create a new component, using a combination of the +general and specific interfaces. The caller may send the message to +another user via mail, or may submit it to the user's CAP server with +the CAPStore class. + + +Following are the methods in each of the classes. + +Component + Construct from string + Output string in ical form + + Get a Property by type + Get a set of Properties by type + Remove a Property by reference + + Get a Component by type + Get a set of Components by type + Remove a Component by reference + + Validate the component ( insert properties for errors ) + Count error properties + Remove error properties + Convert error properties into REQUEST-STATUS properties + +Event, JournalEntry, Todo + + Construct from string + Output string in ical form + + There are get/set accessors for every property. These are + listed in a later section + + +FreeBusy + + Construct from string + Construct from arguments + Output string in ical form + + Accessors for the following properties. See below for return + types for these properties: + + method + prodid + attendee + dtstamp + dtstart + freebusy + organizer + uid + comment + contact + request-status + url + duration + sequence + +TimezonePhase + + Construct from string + Construct from arguments + Output string in ical form + + Accessors for the following properties. See below for return + types for these properties: + + tzname + offsetto + offsetfrom + rrule + rdate + comment + +TimeZone + + Construct from string + Construct from arguments + Output string in ical form + + Accessors for the following properties. See below for return + types for these properties: + + tzid + last-modified + tzurl + standard (returns TimezonePhase) + daylight (returns TimezonePhase) + + +Property + + Construct from string + Construct from arguments + Output string in ical form + + Dictionary access to parameters + + Get/set value + +Attendee + + Construct from string + Construct from arguments + Output string in ical form + + Access to the following properties and parameters: + cuid + cutype + member + role + rsvp + delto + delfrom + sentby + cn + dir + language + +Organizer + + Access to the following properties: + common_name + dir + sentby + language + + +Time +Date +Period + + Same interfaces as libical modules. + +RecurenceSet + I don't know -- need to think about it more. + +Store + Similar methods to the icalset modules. + + +RFC2445 Properties + +This is a list of all of the RFC2445 properties and their associated +VALUE type. + + +Property Value +---------------------------- +CALSCALE TEXT +METHOD TEXT +PRODID TEXT +VERSION TEXT +CATEGORIES TEXT +CLASS TEXT +COMMENT TEXT +DESCRIPTION TEXT +LOCATION TEXT +PERCENT-COMPLETE INTEGER +PRIORITY INTEGER +RESOURCES TEXT +STATUS STATUS +SUMMARY TEXT +COMPLETED DATE-TIME +FREEBUSY PERIOD +TRANSP TEXT +TZNAME TEXT +TZOFFSETFROM UTC-OFFSET +TZOFFSETTO UTC-OFFSET +TZURL URI +TZID TEXT +ATTENDEE CAL-ADDRESS +CONTACT TEXT +ORGANIZER CAL-ADDRESS +RELATED-TO TEXT +URL URI +UID TEXT +EXRULE RECUR +RRULE RECUR +ACTION TEXT +REPEAT INTEGER +CREATED DATE-TIME +DTSTAMP DATE-TIME +LAST-MODIFIED DATE-TIME +SEQUENCE INTEGER +X TEXT +REQUEST-STATUS STRING +ATTACH URL, BINARY +GEO FLOAT +DTEND DATE-TIME +DUE DATE-TIME +DTSTART DATE-TIME +RECURRENCE-ID DATE-TIME +EXDATE DATE-TIME +RDATE DATE-TIME, PERIOD +TRIGGER DATE-TIME, DURATION +DURATION DURATION + +Some of the properties can appear multiple times in a component, other +can appear only once. For a particular component, the number of times +a property can apper may also change with the METHOD property +associated with the component. This list shows which properties can +appear multiple times for some ( but not all ) combinations of +component type and METHOD value: + +ATTACH +ATTENDEE +CATEGORIES +COMMENT +CONTACT +EXDATE +EXRULE +FREEBUSY +NONE +RDATE +RELATEDTO +REQUESTSTATUS +RESOURCES +RRULE +TZNAME +TZURL +X + + +This is a list of the value types and their associated python return +types. A lowercased return type is a python builtin, and an +uppercase-first-letter is a class in the library: + + +Value Return Type +----------------------------------- +BINARY file +BOOLEAN number +CAL-ADDRESS string +DATE Time +DATE-TIME Time +DURATION Duration +FLOAT number +GEO tuple +INTEGER number +METHOD string +PERIOD Period +RECUR RecurrenceSet +TEXT string +TIME Time +URI string +UTC-OFFSET number +STATUS string +X string + + +I suspect that the Component class should use the three previous +tables to create the property accessor methods on the fly. If the +method generation system is general enough, we could also use it for +other classes, such as Alarm, Timezone, Attendee, Organizer and +Freebusy. + + +Memory Handling +--------------- + +One of the things that made the perl binding to libcal difficult was +that if a Component (in perl) returns a reference to a child Component +(in perl), the child Component (in perl) will contain a reference to a +libical component. When the caller is done with the child component in +perl, the caller just drops it and lets perl reclaim the memory. + +The destructor for Component needs to free the libical component that +it holds a reference to, but the child's libical component is still +being used by libical. So perl frees the libical component and later, +libical tries to reference freed memory. + +The situation is actually a little better than that, because libical +will throw an error when you try to free a component that is still +attached to a parent. + +So, the perl library has to be able to determine when the destructor +should free a libical component or not. The perl library calls +icalcomponent_get_parent(), and if is it non-zero, it does not free +the component. + +It is not hard, just more code, and something to watch out for. + diff --git a/src/python/test.py b/src/python/test.py new file mode 100644 index 00000000..1d82062a --- /dev/null +++ b/src/python/test.py @@ -0,0 +1,606 @@ +#!/usr/bin/env python +# -*- Mode: python -*- +#====================================================================== +# FILE: test.py +# CREATOR: eric +# +# DESCRIPTION: +# +# +# $Id: test.py,v 1.24 2002-10-24 13:44:31 acampi Exp $ +# $Locker: $ +# +# (C) COPYRIGHT 2001, Eric Busboom <eric@softwarestudio.org> +# (C) COPYRIGHT 2001, Patrick Lewis <plewis@inetarena.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of either: +# +# The LGPL as published by the Free Software Foundation, version +# 2.1, available at: http://www.fsf.org/copyleft/lesser.html +# +# Or: +# +# The Mozilla Public License Version 1.0. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +#====================================================================== + +import LibicalWrap +from Libical import * + +def error_type(): + error = icalerror_perror() + return error[:index(error,':')] + +comp_str = """ +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//ABC Corporation//NONSGML My Product//EN +METHOD:REQUEST +BEGIN:VEVENT +ATTENDEE;RSVP=TRUE;ROLE=REQ-PARTICIPANT;CUTYPE=GROUP:MAILTO:employee-A@host.com +COMMENT: When in the course of writting comments and nonsense text\, it + becomes necessary to insert a newline +DTSTART:19972512T120000 +DTSTART:19970101T120000Z +DTSTART:19970101 +DURATION:P3DT4H25M +FREEBUSY:19970101T120000/19970101T120000 +FREEBUSY:19970101T120000/PT3H +FREEBUSY:19970101T120000/PT3H +END:VEVENT +END:VCALENDAR""" + + +def test_property(): + + print "--------------------------- Test Property ----------------------" + + + liw = LibicalWrap + icalprop = liw.icalproperty_new_from_string("ATTENDEE;RSVP=TRUE;ROLE=REQ-PARTICIPANT;CUTYPE=GROUP:MAILTO:employee-A@host.com") + + print liw.icalproperty_as_ical_string(icalprop) + + p = Property(ref=icalprop) + + print p.name() + print + print "Parameters:" + for param in p.parameters(): + print " ", param, " = ", p[param] + print + print p['ROLE'] + + p['ROLE'] = 'INDIVIDUAL' + + print p['ROLE'] + + p['ROLE'] = 'GROFROMBLATZ' + + print p['ROLE'] + + print + + p['X-MAN-FAVOURITE'] = 'Wolverine' + p['X-FILES-FAVOURITE'] = 'Mulder' + + print p['X-MAN-FAVOURITE'] + + assert(p['X-MAN-FAVOURITE'] == 'Wolverine') + assert(p['X-FILES-FAVOURITE'] == 'Mulder') + assert(p['X-FILES-FAVOURITE'] != 'Scully') + + print p.value() + p.value("mailto:Bob@bob.com") + print p.value() + + + print p.as_ical_string() + del p['ROLE'] + del p['X-MAN-FAVOURITE'] + + print p.as_ical_string() + + + try: + p = Property() + except Property.ConstructorFailedError: + pass + else: + assert(0) + + # X Property + p = Property("X-COMMENT") + + p.value("This is a sentence, with punctuation; indeed: it is") + print p + + p.value("This is not approved by the Ministry of Silly Walks") + print p + + + assert(test_enum('METHOD','PUBLISH')) + assert(not test_enum('METHOD','FOO')) + + assert(test_enum('ACTION','AUDIO')) + assert(not test_enum('ACTION','OPAQUE')) + +def test_time(): + "Test routine" + + print"-------------------Test Time --------------------------------" + + t = Time("19970325T123010Z",'DTSTART') + + assert(t.year == 1997) + assert(t.month == 3) + assert(t.day == 25) + assert(t.hour == 12) + assert(t.minute == 30) + assert(t.second == 10) + assert(t.is_utc()) + assert(not t.is_date()) + + print t + + t.timezone("America/Los_Angeles") + print str(t) + print t.timezone() + #assert(str(t)=='DTSTART;TZID=America/Los_Angeles:19970325T123010') + assert(str(t)=='DTSTART;TZID=/freeassociation.sourceforge.net/Tzfile/America/Los_Angeles:19970325T053010') + + t.second = t.second+80 + + t.timezone("UTC") + print t.minute, t.second + assert(t.minute == 31) + assert(t.second == 30) + + d = Duration(3600,"DURATION") + t2 = t + d + + print t2 + assert(t2.hour == 13) + + t2 = t - d + + print t2 + assert(isinstance(t2,Time)) + assert(t2.hour == 11) + + # test int args + t = Time(2) + print t + + # test float args + t = Time(2.5) + print t + +def test_period(): + + print"-------------------Test Period--------------------------------" + + p = Period("19970101T180000Z/19970101T233000Z") + + print p + + assert(str(p) == 'FREEBUSY:19970101T180000Z/19970101T233000Z') + + print p.start() + assert(str(p.start()) == 'DTSTART:19970101T180000Z') + + print p.end() + assert(str(p.end()) == 'DTEND:19970101T233000Z') + + print p.duration() + assert(str(p.duration()) == 'DURATION:PT5H30M') + p = None + + p = Period("19970101T180000Z/PT5H30M") + print p + + print p.start() + assert(str(p.start()) == 'DTSTART:19970101T180000Z') + + print p.end() + assert(str(p.end()) == 'DTEND:19970101T233000Z') + + print p.duration() + assert(str(p.duration()) == 'DURATION:PT5H30M') + + +def test_duration(): + + print "-------------- Test Duration ----------------" + + # Ical string + + d = Duration("P3DT4H25M") + + print str(d) + + assert(str(d) == "DURATION:P3DT4H25M") + + print d.seconds() + + assert(d.seconds() == 275100) + + # seconds + + d = Duration(-275100) + + print str(d) + + assert(str(d) == "DURATION:-P3DT4H25M") + + print d.seconds() + + assert(d.seconds() == -275100) + + #error + + try: + d = Duration("P10WT7M") + print str(d) + assert(0) + except: pass + + try: + d = Duration("Pgiberish") + print str(d) + assert(0) + except: + pass + + + +def test_attach(): + + file = open('littlefile.txt') + attachProp = Attach(file) + file.close() + attachProp.fmttype('text/ascii') + print "\n" + attachProp.name() + print attachProp.value_type() + print attachProp.fmttype() + attachProp['fmttype']=None + print "Calling value()" + print attachProp.value() + print "Calling asIcalString()" + print attachProp.as_ical_string() + + +def test_component(): + + print "------------------- Test Component ----------------------" + + + c = NewComponent(comp_str); + + props = c.properties() + + for p in props: + print p.as_ical_string() + + inner = c.components()[0] + + print inner + print type(inner) + + + props = inner.properties() + + for p in props: + print p.as_ical_string() + + dtstart = inner.properties('DTSTART')[0] + + print dtstart + + print "\n Orig hour: ", dtstart.hour + assert(dtstart.hour == 12) + + dtstart.hour = dtstart.hour + 5 + + print "\n New hour: ", dtstart.hour + assert(dtstart.hour == 17) + + attendee = inner.properties('ATTENDEE')[0] + + print attendee + + t = Time("20011111T123030") + t.name('DTEND') + + inner.add_property(t) + + + print c + + dtstart1 = inner.properties('DTSTART')[0] + dtstart2 = inner.properties('DTSTART')[0] + dtstart3 = inner.property('DTSTART') + + assert(dtstart1 is dtstart2) + assert(dtstart1 == dtstart2) + + assert(dtstart1 is dtstart3) + assert(dtstart1 == dtstart3) + + + p = Property(type="SUMMARY"); + p.value("This is a summary") + + inner.properties().append(p) + + print inner.as_ical_string() + + p = inner.properties("SUMMARY")[0] + assert(p!=None); + print str(p) + assert(str(p) == "SUMMARY:This is a summary") + + inner.properties()[:] = [p] + + print inner.as_ical_string() + + # test sequence + event = Event() + + try: + event.sequence("foo") + except TypeError: + pass + + event.sequence(-1) + print event.sequence() + + event.sequence(1) + event.sequence(88) + print event.sequence() + +def test_event(): + print "------------ Event Class ----------------------" + + event = Event() + + event.method('REQUEST') + event.version('2.0') + + event.created("20010313T123000Z") + print "created =", event.created() + assert (event.created() == Time("20010313T123000Z")) + + event.organizer("MAILTO:j_doe@nowhere.com") + org = event.organizer() + print org.cn() + org.cn('Jane Doe') + assert (isinstance(org, Organizer)) + print "organizer =", event.organizer() + assert (event.organizer().value() == "MAILTO:j_doe@nowhere.com") + + event.dtstart("20010401T183000Z") + print "dtstart =", event.dtstart() + assert (event.dtstart()== Time("20010401T183000Z")) + + dtend = Time('20010401T190000Z', 'DTEND') + event.dtend(dtend) + assert (event.dtend() ==dtend ) + assert (event.dtend() == Time('20010401T190000Z')) + + att = Attendee() + att.value('jsmith@nothere.com') + event.attendees(('ef_hutton@listenup.com', att)) + + event.x_properties('X-TEST',('foo', 'bar')) + event.x_properties('X-TEST2',('foo, biz', 'bar, biz')) + + inner = event.components()[0] + for e in inner.properties('X-TEST'): + print " ", e.as_ical_string() + + assert(len(event.x_properties('X-TEST'))==2) + + event.description("A short description. Longer ones break things. Really. What does it break. The code is supposed to handle realy long lines, longer, in fact, than any sane person would create except by writting a random text generator or by excerpting text from a less sane person. Actually, it did \"break\" and I had to remove an \n assert to fix it.") + event.status('TeNtAtIvE') + + print event.as_ical_string() + + +def test_derivedprop(): + + print "------------ Derived Properties -----------------" + + p = RDate("20011111T123030") + + print str(p) + + + p = RDate("19970101T120000/19970101T123000") + + print str(p) + + try: + p = RDate("P3DT4H25M") + print str(p) + assert(0) + except: pass + + + p = Trigger("P3DT4H25M") + + print str(p) + + p = Trigger("20011111T123030") + + print str(p) + + try: + p = Trigger("19970101T120000/19970101T123000") + print str(p) + assert(0) + except: pass + +def test_gauge(): + print "------------ Gauge -----------------" + event = Event() + + event.method('REQUEST') + event.version('2.0') + event.created("20010313T123000Z") + event.organizer("MAILTO:j_doe@nowhere.com") + org = event.organizer() + org.cn('Jane Doe') + event.dtstart("20010401T183000Z") + dtend = Time('20010401T190000Z', 'DTEND') + event.dtend(dtend) + event.description("A short description.") + event.status('TeNtAtIvE') + + print event.as_ical_string() + + gauge = Gauge(sql="SELECT * FROM VEVENT WHERE DTSTART > '20010401T180000Z'") + + assert(gauge.compare(event) == 1) + + gauge = Gauge(sql="SELECT * FROM VEVENT WHERE DTSTART > '20010401T190000Z'") + + assert(gauge.compare(event) == 0) + +def do_test_store(storeobj=None, *args): + assert(storeobj != None) + store = storeobj(*args) + assert(store != None) + + print ">------------ ", + print store.__class__, + print "Store -----------------" + + + # create fileset + + event = Event() + + event.method('REQUEST') + event.version('2.0') + event.created("20010313T123000Z") + event.organizer("MAILTO:j_doe@nowhere.com") + event.dtstart("20010401T183000Z") + event.duration('PT3H') + + event.description("A short description.") + + # for i = 1 to 10 + # copy event + # munge uid and increment month + for i in range(1,11): + newevent = event.clone() + newevent.uid("%d@localhost" % (i,)) + newevent.dtstart().month = newevent.dtstart().month + i + + #print ne + store.add_component(newevent) + + # commit + store.commit() + assert(store.count_components("VCALENDAR") == 10) + # free + del(store) + + # open again + store = storeobj(*args) + # assert count of components = 10 + assert(store.count_components("VCALENDAR") == 10) + + # print them out + # fetch by uid + n7 = store.fetch("7@localhost") + print n7 + # fetch by match + + n7m = store.fetchMatch(n7) + assert(str(n7) == str(n7m)) + + # modify in memory + n7.uid("42@localhost") + del(store) + del(n7) + + store = storeobj(*args) + assert(store.fetch("42@localhost") == None) + n7 = store.fetch("7@localhost") + n7.uid("42@localhost") + store.mark() + store.commit() + del(store) + store = storeobj(*args) + assert(store.fetch("7@localhost") == None) + + # fetch by gauge + + gauge = Gauge(sql="SELECT * FROM VEVENT WHERE DTSTART > '20010601T000000Z' AND DTSTART < '20010901T000000Z'") + + store.select(gauge) + + count = 0 + + c = store.first_component() + while c != None: + print c.uid() + print c.dtstart() + print + count = count + 1 + c = store.next_component() + + store.clearSelect() + + assert(count == 3) + + # remove all of them + c = store.first_component() + while c != None: + print c.uid() + store.remove_component(c) + c = store.first_component() + + assert(store.count_components("VCALENDAR") == 0) + store.commit() + assert(store.count_components("VCALENDAR") == 0) + # print them out + # assert count of components = 0 + + +def test_store(): + print "------------ Store -----------------" + do_test_store(FileStore,"filesetout.ics") + +def run_tests(): + print "Running unit tests for:", ICAL_PACKAGE, ICAL_VERSION + + test_property() + + test_time() + + test_period() + + test_component() + + test_duration() + + test_derivedprop() + + test_event() + + #test_attach() + + test_gauge() + + test_store() + + + + +if __name__ == "__main__": + run_tests() + |