Support length and last-modified attributes
authorKeith Packard <keithp@keithp.com>
Sun, 18 Dec 2011 06:35:56 +0000 (22:35 -0800)
committerKeith Packard <keithp@keithp.com>
Sun, 18 Dec 2011 06:35:56 +0000 (22:35 -0800)
Deal with re-encoding to ascii.
Handle parse failures.

Signed-off-by: Keith Packard <keithp@keithp.com>
calypso/__init__.py
calypso/ical.py
calypso/xmlutils.py

index f9d777c5b105069936837d64949428165f4da8ef..0eb727b413e5e67f10a32ec5d8d7767869394bd3 100644 (file)
@@ -224,7 +224,7 @@ class CalendarHTTPHandler(server.BaseHTTPRequestHandler):
             answer_text = self._calendar.text
             etag = self._calendar.etag
 
-        self._answer = answer_text.encode(self._encoding)
+        self._answer = answer_text.encode(self._encoding,"xmlcharrefreplace")
         print ("answer %s" % self._answer)
         self.send_response(client.OK)
         self.send_header("Content-Length", len(self._answer))
index 6a5e9ebabca29517e9ec45c4c7019e1e90b0c5be..75eef8bfa27721867233a48b4b547d99364b832c 100644 (file)
@@ -47,24 +47,31 @@ def open(path, mode="r"):
     return codecs.open(path, mode, config.get("encoding", "stock"))
 # pylint: enable=W0622
 
+def find_vobject_value(vobject, name):
+
+    if vobject.name == name:
+        return vobject.value
+
+    for child in vobject.getChildren():
+        value = find_vobject_value(child, name)
+        if value:
+            return value
+    return None
+
 class Item(object):
-    """Internal iCal item."""
+
+    """Internal item. Wraps a vObject"""
+
     def __init__(self, text, name=None, path=None):
         """Initialize object from ``text`` and different ``kwargs``."""
 
         print ("New item name %s path %s\n" % (name, path))
 
-        lines = text.splitlines(True)
-        newlines=""
-        for line in lines:
-            if line.startswith(" ") or line.find(":") >= 0:
-                newlines = newlines + line
-
         try:
-            self.object = vobject.readOne(newlines)
+            self.object = vobject.readOne(text)
         except Exception:
-            self.object = None
             print ("parse error\n")
+            return None
 
         self.path = path
 
@@ -74,7 +81,7 @@ class Item(object):
                     if child.name == 'VEVENT' or child.name == 'VCARD':
                         if not child.contents.has_key('uid'):
                             if not name:
-                                h = hashlib.sha1(self.object.serialize())
+                                h = hashlib.sha1(text)
                                 name = h.hexdigest()
                             child.add('UID').value = name
                         name = child.uid.value
@@ -86,8 +93,11 @@ class Item(object):
 
         self.name = self.object.x_calypso_name.value
             
-        h = hashlib.sha1(self.object.serialize())
-        self.etag = h.hexdigest()
+        try:
+            self.etag = hashlib.sha1(self.object.serialize()).hexdigest()
+        except Exception:
+            print ("serialize error\n")
+            return None
 
         print ("name %s\n" % self.name)
 
@@ -129,13 +139,25 @@ class Item(object):
             return self.object.tzid_list
         return []
 
+    @property
+    def length(self):
+        return "%d" % len(self.text)
+
+    @property
+    def last_modified(self):
+        value = find_vobject_value(self.object, "LAST-MODIFIED")
+        if value:
+            return value.utctimetuple()
+        return time.gmtime()
+        
 class Calendar(object):
     """Internal calendar class."""
     tag = "VCALENDAR"
 
     def insert_text(self, text, path):
         new_item = Item(text, None, path)
-        self.my_items.append(new_item)
+        if new_item:
+            self.my_items.append(new_item)
             
     def insert_file(self, path):
         try:
@@ -318,6 +340,8 @@ class Calendar(object):
         """
 
         new_item = Item(text, name, None)
+        if not new_item:
+            return
         if new_item.name not in (item.name for item in self.my_items):
                 self.create_file(new_item)
 
@@ -341,6 +365,9 @@ class Calendar(object):
                 path = old_item.path
                 break
         new_item = Item(text, name, path)
+        if not new_item:
+            return
+
         if path is not None:
             self.rewrite_file(new_item, path)
         else:
@@ -379,22 +406,15 @@ class Calendar(object):
     def text(self):
         """Calendar as plain text."""
         self.scan_dir()
-        headers = []
-
-#        headers.append(Item("PRODID:-//Calypso//NONSGML Calypso Server//EN"))
-#        headers.append(Item("VERSION:2.0"))
-
-        return ""
+        _text = ""
+        for item in self.my_items:
+            _text = _text + item.text
+        return _text
 
     @property
     def headers(self):
         """Find headers items in calendar."""
-        header_lines = []
-
-#        header_lines.append(Item("PRODID:-//Calypso//NONSGML Calypso Server//EN"))
-#        header_lines.append(Item("VERSION:2.0"))
-
-        return header_lines
+        return []
 
     @property
     def items(self):
@@ -410,5 +430,8 @@ class Calendar(object):
 
         """
         self.scan_dir()
-        modification_time = time.gmtime(self.mtime)
-        return time.strftime("%a, %d %b %Y %H:%M:%S +0000", modification_time)
+        return time.gmtime(self.mtime)
+
+    @property
+    def length(self):
+        return "%d" % len(self.text)
index 6ebae47dcd32d425db90af1b179095c87143ce7e..382e8ae4bc6876bd02adf78e7a8c0d1849e5b874 100644 (file)
@@ -28,6 +28,7 @@ in them for XML requests (all but PUT).
 """
 
 import xml.etree.ElementTree as ET
+import time
 
 import urllib
 
@@ -162,6 +163,10 @@ def propfind(path, xml_request, calendar, depth):
                 privilege = ET.Element(_tag("D", "privilege"))
                 privilege.append(ET.Element(_tag("D", "all")))
                 element.append(privilege)
+            elif tag == _tag("D", "getcontentlength"):
+                element.text = item.length
+            elif tag == _tag("D", "getlastmodified"):
+                element.text = time.strftime("%a, %d %b %Y %H:%M:%S +0000", item.last_modified)
             prop.append(element)
 
         status = ET.Element(_tag("D", "status"))