Example #1
0
 def test_vtodo(self):
     vtodo = get_test_file("vtodo.ics")
     obj = base.readOne(vtodo)
     obj.vtodo.add('completed')
     obj.vtodo.completed.value = datetime.datetime(2015,5,5,13,30)
     self.assertEqual(obj.vtodo.completed.serialize()[0:23], 'COMPLETED:20150505T1330')
     obj = base.readOne(obj.serialize())
     self.assertEqual(obj.vtodo.completed.value, datetime.datetime(2015,5,5,13,30))
Example #2
0
 def test_wrapping(self):
     """
     Should support an input file with a long text field covering multiple lines
     """
     test_journal = get_test_file("journal.ics")
     vobj = base.readOne(test_journal)
     vjournal = base.readOne(vobj.serialize())
     self.assertTrue('Joe, Lisa, and Bob' in vjournal.description.value)
     self.assertTrue('Tuesday.\n2.' in vjournal.description.value)
Example #3
0
 def test_wrapping(self):
     """
     Should support an input file with a long text field covering multiple lines
     """
     test_journal = get_test_file("journal.ics")
     vobj = base.readOne(test_journal)
     vjournal = base.readOne(vobj.serialize())
     self.assertTrue('Joe, Lisa, and Bob' in vjournal.description.value)
     self.assertTrue('Tuesday.\n2.' in vjournal.description.value)
Example #4
0
 def test_vtodo(self):
     vtodo = get_test_file("vtodo.ics")
     obj = base.readOne(vtodo)
     obj.vtodo.add('completed')
     obj.vtodo.completed.value = datetime.datetime(2015, 5, 5, 13, 30)
     self.assertEqual(obj.vtodo.completed.serialize()[0:23],
                      'COMPLETED:20150505T1330')
     obj = base.readOne(obj.serialize())
     self.assertEqual(obj.vtodo.completed.value,
                      datetime.datetime(2015, 5, 5, 13, 30))
Example #5
0
    def test_unicode(self):
        test_cal = get_test_file("utf8_test.ics")
        vevent = base.readOne(test_cal).vevent
        vevent2 = base.readOne(vevent.serialize())
        self.assertEqual(str(vevent), str(vevent2))

        self.assertEqual(vevent.summary.value, 'The title こんにちはキティ')

        if sys.version_info[0] < 3:
            test_cal = test_cal.decode('utf-8')
            vevent = base.readOne(test_cal).vevent
            vevent2 = base.readOne(vevent.serialize())
            self.assertEqual(str(vevent), str(vevent2))
            self.assertEqual(vevent.summary.value, 'The title こんにちはキティ')
Example #6
0
def main():
    options, args = get_options()
    if PyICU is None:
        print("Failure. change_tz requires PyICU, exiting")
    elif options.list:
        for tz_string in PyICU.TimeZone.createEnumeration():
            print(tz_string)
    elif args:
        utc_only = options.utc
        if utc_only:
            which = "only UTC"
        else:
            which = "all"
        print("Converting {0!s} events".format(which))
        ics_file = args[0]
        if len(args) > 1:
            timezone = PyICU.ICUtzinfo.getInstance(args[1])
        else:
            timezone = PyICU.ICUtzinfo.default
        print("... Reading {0!s}".format(ics_file))
        cal = base.readOne(open(ics_file))
        change_tz(cal, timezone, PyICU.ICUtzinfo.default, utc_only)

        out_name = ics_file + '.converted'
        print("... Writing {0!s}".format(out_name))

        with open(out_name, 'wb') as out:
            cal.serialize(out)

        print("Done")
Example #7
0
 def setUpClass(cls):
     """
     Method for setting up class fixture before running tests in the class.
     Fetches test file.
     """
     cls.test_file = get_test_file("vcard_with_groups.ics")
     cls.card = base.readOne(cls.test_file)
Example #8
0
def ics2task() -> None:
    """Command line tool to convert from iCalendar to Taskwarrior."""
    from argparse import ArgumentParser, FileType
    from sys import stdin

    parser = ArgumentParser(
        description="Converter from iCalendar to Taskwarrior syntax.")
    parser.add_argument(
        "infile",
        nargs="?",
        type=FileType("r"),
        default=stdin,
        help="Input iCalendar file (default: stdin)",
    )
    parser.add_argument(
        "outdir",
        nargs="?",
        help="Output Taskwarrior directory (autodetect by default)",
        default="",
    )
    args = parser.parse_args()

    vobject = readOne(args.infile.read())
    task = IcsTask(args.outdir)
    for todo in vobject.vtodo_list:
        task.to_task(todo)
Example #9
0
    def test_importing(self):
        cal = get_test_file("standard_test.ics")
        c = base.readOne(cal, validate=True)
        self.assertEqual(
            str(c.vevent.valarm.trigger),
            "<TRIGGER{}-1 day, 0:00:00>"
        )

        self.assertEqual(
            str(c.vevent.dtstart.value),
            "2002-10-28 14:00:00-08:00"
        )
        self.assertTrue(
            isinstance(c.vevent.dtstart.value, datetime.datetime)
        )
        self.assertEqual(
            str(c.vevent.dtend.value),
            "2002-10-28 15:00:00-08:00"
        )
        self.assertTrue(
            isinstance(c.vevent.dtend.value, datetime.datetime)
        )
        self.assertEqual(
            c.vevent.dtstamp.value,
            datetime.datetime(2002, 10, 28, 1, 17, 6, tzinfo=tzutc())
        )

        vevent = c.vevent.transformFromNative()
        self.assertEqual(
            str(vevent.rrule),
            "<RRULE{}FREQ=Weekly;COUNT=10>"
        )
Example #10
0
 def test_recurrence_mixed_with_and_without_tz(self):
     """
     Ensure recurring vevent with DTSTART and EXDATE not both have or
     not have timezone information is parsing.
     """
     test_file = get_test_file("recurrence-mixed-with-and-without-tz.ics")
     vcalendar = base.readOne(test_file, validate=True)
     expected = None
     for vobj in vcalendar.getChildren():
         if vobj.name == 'VTIMEZONE':
             expected = iter([[
                 datetime.datetime(1991, 5, 20, 0, 0, 0),
                 datetime.datetime(1993, 5, 20, 0, 0, 0)
             ],
                              [
                                  datetime.datetime(
                                      2017,
                                      10,
                                      25,
                                      14,
                                      0,
                                      0,
                                      tzinfo=vobj.gettzinfo()),
                                  datetime.datetime(2017,
                                                    11,
                                                    8,
                                                    14,
                                                    0,
                                                    0,
                                                    tzinfo=vobj.gettzinfo())
                              ]])
         elif vobj.name == 'VEVENT':
             dates = list(vobj.getrruleset(addRDate=True))
             self.assertEqual(dates, next(expected))
Example #11
0
 def test_thunderbird_duration_pt0s_workaround(self):
     """
     Test parsing thundebird generated ics streams having both a duration of
     0 seconds and a dtend attribute.
     """
     cal = get_test_file("thunderbird_duration_pt0s_workaround.ics")
     c = base.readOne(cal, validate=True)
Example #12
0
def main():
    options, args = get_options()
    if PyICU is None:
        print("Failure. change_tz requires PyICU, exiting")
    elif options.list:
        for tz_string in PyICU.TimeZone.createEnumeration():
            print(tz_string)
    elif args:
        utc_only = options.utc
        if utc_only:
            which = "only UTC"
        else:
            which = "all"
        print("Converting {0!s} events".format(which))
        ics_file = args[0]
        if len(args) > 1:
            timezone = PyICU.ICUtzinfo.getInstance(args[1])
        else:
            timezone = PyICU.ICUtzinfo.default
        print("... Reading {0!s}".format(ics_file))
        cal = base.readOne(open(ics_file))
        change_tz(cal, timezone, PyICU.ICUtzinfo.default, utc_only)

        out_name = ics_file + '.converted'
        print("... Writing {0!s}".format(out_name))

        out = file(out_name, 'wb')
        cal.serialize(out)
        print("Done")
Example #13
0
    def test_importing(self):
        """
        Test importing ics
        """
        cal = get_test_file("standard_test.ics")
        c = base.readOne(cal, validate=True)
        self.assertEqual(
            str(c.vevent.valarm.trigger),
            "<TRIGGER{}-1 day, 0:00:00>"
        )

        self.assertEqual(
            str(c.vevent.dtstart.value),
            "2002-10-28 14:00:00-08:00"
        )
        self.assertTrue(
            isinstance(c.vevent.dtstart.value, datetime.datetime)
        )
        self.assertEqual(
            str(c.vevent.dtend.value),
            "2002-10-28 15:00:00-08:00"
        )
        self.assertTrue(
            isinstance(c.vevent.dtend.value, datetime.datetime)
        )
        self.assertEqual(
            c.vevent.dtstamp.value,
            datetime.datetime(2002, 10, 28, 1, 17, 6, tzinfo=tzutc())
        )

        vevent = c.vevent.transformFromNative()
        self.assertEqual(
            str(vevent.rrule),
            "<RRULE{}FREQ=Weekly;COUNT=10>"
        )
Example #14
0
def main():
    options, args = get_options()
    if PyICU is None:
        print "Failure. change_tz requires PyICU, exiting"
    elif options.list:
        for tz_string in PyICU.TimeZone.createEnumeration():
            print tz_string
    elif args:
        utc_only = options.utc
        if utc_only:
            which = "only UTC"
        else:
            which = "all"
        print "Converting %s events" % which
        ics_file = args[0]
        if len(args) > 1:
            timezone = PyICU.ICUtzinfo.getInstance(args[1])
        else:
            timezone = PyICU.ICUtzinfo.default
        print "... Reading %s" % ics_file
        cal = base.readOne(file(ics_file))
        change_tz(cal, timezone, PyICU.ICUtzinfo.default, utc_only)

        out_name = ics_file + ".converted"
        print "... Writing %s" % out_name
        out = file(out_name, "wb")
        cal.serialize(out)
        print "Done"
Example #15
0
def main():
    options, args = get_options()
    if PyICU is None:
        print "Failure. change_tz requires PyICU, exiting"
    elif options.list:
        for tz_string in PyICU.TimeZone.createEnumeration():
            print tz_string
    elif args:
        utc_only = options.utc
        if utc_only:
            which = "only UTC"
        else:
            which = "all"
        print "Converting %s events" % which
        ics_file = args[0]
        if len(args) > 1:
            timezone = PyICU.ICUtzinfo.getInstance(args[1])
        else:
            timezone = PyICU.ICUtzinfo.default
        print "... Reading %s" % ics_file
        cal = base.readOne(file(ics_file))
        change_tz(cal, timezone, PyICU.ICUtzinfo.default, utc_only)

        out_name = ics_file + '.converted'
        print "... Writing %s" % out_name
        out = file(out_name, 'wb')
        cal.serialize(out)
        print "Done"
Example #16
0
 def handle_admin_request(self, params, fields):
   if params["action"] == "add":
     self.db.table(self.table_prefix+"_items").insert(
       {'begin' : self.conc_date(fields,"begin"), 'end' : self.conc_date(fields,"end"), 'text' : fields['item_text'].value})
     return "admin.py?id=Calendars"
   elif params["action"] == "del":
     self.db.table(self.table_prefix+"_items").delete([("id", "=", params["item_id"])])
     return "admin.py?id=Calendars"
   elif params["action"] == "update":
     self.db.table(self.table_prefix+"_items").update({ 'id' : params["item_id"], 'begin' : self.conc_date(fields,"begin"), 'end' : self.conc_date(fields,"end"), 'text' : fields['item_text'].value}, [("id", "=", params["item_id"])])
   elif params["action"] == "import":
     try:
       self.db.drop(self.table_prefix+"_temp")
     except:
       pass
     self.db.create(self.table_prefix+"_temp", {"text" :"varchar","begin" :"datetime", "end":"datetime"});
     fcal = vobject.readOne(fields['cal'].file.read()).vevent_list
     for fev in fcal:
       self.db.table(self.table_prefix+"_temp").insert({'begin' : fev.dtstart.value ,
                                                        'end' : fev.dtend.value ,
                                                        'text' : fev.summary.value })
     return "admin.py?id=Calendars&amp;action=choose"
   elif params["action"] == "include":
     for i in range(int(fields["nb_it"].value)):
       if fields.has_key("check_"+str(i)):
         self.db.table(self.table_prefix+"_items").insert(
           {'begin' : fields["begin_"+str(i)].value, 'end' : fields["end_"+str(i)].value, 'text' : fields['text_'+str(i)].value})
     return "admin.py?id=Calendars"
   else:
     return "admin.py?id=Calendars"
Example #17
0
    def test_bad_line(self):
        cal = get_test_file("badline.ics")
        self.assertRaises(ParseError, base.readOne, cal)

        newcal = base.readOne(cal, ignoreUnreadable=True)
        self.assertEqual(str(newcal.vevent.x_bad_underscore),
                         '<X-BAD-UNDERSCORE{}TRUE>')
Example #18
0
 def setUpClass(cls):
     """
     Method for setting up class fixture before running tests in the class.
     Fetches test file.
     """
     cls.test_file = get_test_file("vcard_with_groups.ics")
     cls.card = base.readOne(cls.test_file)
Example #19
0
 def test_readOne(self):
     cal = get_test_file("silly_test.ics")
     silly = base.readOne(cal, findBegin=False)
     self.assertEqual(
         str(silly),
         "<SILLYPROFILE| [<MORESTUFF{}this line is not folded, but in practice probably ought to be, as it is exceptionally long, and moreover demonstratively stupid>, <SILLYNAME{}name>, <STUFF{}foldedline>]>"
     )
     self.assertEqual(str(silly.stuff), "<STUFF{}foldedline>")
Example #20
0
    def test_unicode(self):
        test_cal = get_test_file("utf8_test.ics")
        vevent = base.readOne(test_cal).vevent

        self.assertEqual(
            vevent.summary.value,
            'The title こんにちはキティ'
        )
Example #21
0
    def test_bad_line(self):
        cal = get_test_file("badline.ics")
        self.assertRaises(ParseError, base.readOne, cal)

        newcal = base.readOne(cal, ignoreUnreadable=True)
        self.assertEqual(
            str(newcal.vevent.x_bad_underscore),
            '<X-BAD-UNDERSCORE{}TRUE>'
        )
Example #22
0
 def test_recurrence_without_tz(self):
     """
     Test recurring vevent missing any time zone definitions.
     """
     test_file = get_test_file("recurrence-without-tz.ics")
     cal = base.readOne(test_file)
     dates = list(cal.vevent.getrruleset())
     self.assertEqual(dates[0], datetime.datetime(2013, 1, 17, 0, 0))
     self.assertEqual(dates[1], datetime.datetime(2013, 1, 24, 0, 0))
     self.assertEqual(dates[-1], datetime.datetime(2013, 3, 28, 0, 0))
Example #23
0
    def test_vcard_3_parsing(self):
        """
        VCARD 3.0 parse test
        """
        test_file = get_test_file("simple_3_0_test.ics")
        card = base.readOne(test_file)
        # value not rendering correctly?
        #self.assertEqual(
        #    card.adr.value,
        #    "<Address: Haight Street 512;\nEscape, Test\nNovosibirsk,  80214\nGnuland>"
        #)
        self.assertEqual(
            card.org.value,
            ["University of Novosibirsk", "Department of Octopus Parthenogenesis"]
        )

        for _ in range(3):
            new_card = base.readOne(card.serialize())
            self.assertEqual(new_card.org.value, card.org.value)
            card = new_card
Example #24
0
    def test_unicode(self):
        test_cal = get_test_file("utf8_test.ics")
        vevent = base.readOne(test_cal).vevent
        vevent2 = base.readOne(vevent.serialize())
        self.assertEqual(str(vevent), str(vevent2))

        self.assertEqual(
            vevent.summary.value,
            'The title こんにちはキティ'
        )

        if sys.version_info[0] < 3:
            test_cal = test_cal.decode('utf-8')
            vevent = base.readOne(test_cal).vevent
            vevent2 = base.readOne(vevent.serialize())
            self.assertEqual(str(vevent), str(vevent2))
            self.assertEqual(
                vevent.summary.value,
                'The title こんにちはキティ'
            )
Example #25
0
 def test_recurrence_offset_naive(self):
     """
     Ensure recurring vevent missing some time zone definitions is
     parsing. See isseu #75.
     """
     test_file = get_test_file("recurrence-offset-naive.ics")
     cal = base.readOne(test_file)
     dates = list(cal.vevent.getrruleset())
     self.assertEqual(dates[0], datetime.datetime(2013, 1, 17, 0, 0))
     self.assertEqual(dates[1], datetime.datetime(2013, 1, 24, 0, 0))
     self.assertEqual(dates[-1], datetime.datetime(2013, 3, 28, 0, 0))
Example #26
0
 def test_readOne(self):
     cal = get_test_file("silly_test.ics")
     silly = base.readOne(cal, findBegin=False)
     self.assertEqual(
         str(silly),
         "<SILLYPROFILE| [<MORESTUFF{}this line is not folded, but in practice probably ought to be, as it is exceptionally long, and moreover demonstratively stupid>, <SILLYNAME{}name>, <STUFF{}foldedline>]>"
     )
     self.assertEqual(
         str(silly.stuff),
         "<STUFF{}foldedline>"
     )
Example #27
0
    def test_vcard_3_parsing(self):
        """
        VCARD 3.0 parse test
        """
        test_file = get_test_file("simple_3_0_test.ics")
        card = base.readOne(test_file)
        # value not rendering correctly?
        #self.assertEqual(
        #    card.adr.value,
        #    "<Address: Haight Street 512;\nEscape, Test\nNovosibirsk,  80214\nGnuland>"
        #)
        self.assertEqual(
            card.org.value,
            ["University of Novosibirsk", "Department of Octopus Parthenogenesis"]
        )

        for _ in range(3):
            new_card = base.readOne(card.serialize())
            self.assertEqual(new_card.org.value, card.org.value)
            card = new_card
Example #28
0
 def test_recurrence(self):
     # Ensure date valued UNTILs in rrules are in a reasonable timezone,
     # and include that day (12/28 in this test)
     test_file = get_test_file("recurrence.ics")
     cal = base.readOne(test_file, findBegin=False)
     dates = list(cal.vevent.getrruleset())
     self.assertEqual(dates[0],
                      datetime.datetime(2006, 1, 26, 23, 0, tzinfo=tzutc()))
     self.assertEqual(dates[1],
                      datetime.datetime(2006, 2, 23, 23, 0, tzinfo=tzutc()))
     self.assertEqual(
         dates[-1], datetime.datetime(2006, 12, 28, 23, 0, tzinfo=tzutc()))
Example #29
0
 def test_vcard_3_parsing(self):
     """
     VCARD 3.0 parse test
     """
     test_file = get_test_file("simple_3_0_test.ics")
     card = base.readOne(test_file, findBegin=False)
     # value not rendering correctly?
     #self.assertEqual(
     #    card.adr.value,
     #    "<Address: Haight Street 512;\nEscape, Test\nNovosibirsk,  80214\nGnuland>"
     #)
     self.assertEqual(
         card.org.value,
         "University of Novosibirsk, Department of Octopus Parthenogenesis")
Example #30
0
 def test_vcard_3_parsing(self):
     """
     VCARD 3.0 parse test
     """
     test_file = get_test_file("simple_3_0_test.ics")
     card = base.readOne(test_file, findBegin=False)
     # value not rendering correctly?
     #self.assertEqual(
     #    card.adr.value,
     #    "<Address: Haight Street 512;\nEscape, Test\nNovosibirsk,  80214\nGnuland>"
     #)
     self.assertEqual(
         card.org.value,
         "University of Novosibirsk, Department of Octopus Parthenogenesis"
     )
Example #31
0
 def test_recurrence(self):
     # Ensure date valued UNTILs in rrules are in a reasonable timezone,
     # and include that day (12/28 in this test)
     test_file = get_test_file("recurrence.ics")
     cal = base.readOne(test_file, findBegin=False)
     dates = list(cal.vevent.getrruleset())
     self.assertEqual(
         dates[0],
         datetime.datetime(2006, 1, 26, 23, 0, tzinfo=tzutc())
     )
     self.assertEqual(
         dates[1],
         datetime.datetime(2006, 2, 23, 23, 0, tzinfo=tzutc())
     )
     self.assertEqual(
         dates[-1],
         datetime.datetime(2006, 12, 28, 23, 0, tzinfo=tzutc())
     )
Example #32
0
 def setUpClass(cls):
     cls.test_file = get_test_file("vcard_with_groups.ics")
     cls.card = base.readOne(cls.test_file)
    def verify(self, manager, uri, response, respdata, args): #@UnusedVariable
        # Get arguments
        files = args.get("filepath", [])
        
        # status code must be 200, 207
        if response.status not in (200,207):
            return False, "        HTTP Status Code Wrong: %d" % (response.status,)
        
        # look for response data
        if not respdata:
            return False, "        No response body"
        
        # look for one file
        if len(files) != 1:
            return False, "        No file to compare response to"
        
        # read in all data from specified file
        fd = open( files[0], "r" )
        try:
            try:
                data = fd.read()
            finally:
                fd.close()
        except:
            data = None

        if data is None:
            return False, "        Could not read data file"

        data = manager.server_info.subs(data)
        
        def removePropertiesParameters(component):
            
            for item in tuple(component.getChildren()):
                if isinstance(item, Component):
                    removePropertiesParameters(item)
                elif isinstance(item, ContentLine):
                    
                    # Always remove DTSTAMP
                    if item.name == "DTSTAMP":
                        component.remove(item)
                    elif item.name == "X-CALENDARSERVER-ATTENDEE-COMMENT":
                        if item.params.has_key("X-CALENDARSERVER-DTSTAMP"):
                            item.params["X-CALENDARSERVER-DTSTAMP"] = ["20080101T000000Z"]

        s = StringIO.StringIO(respdata)
        try:
            resp_calendar = readOne(s)
            removePropertiesParameters(resp_calendar)
            respdata = resp_calendar.serialize()
            
            s = StringIO.StringIO(data)
            data_calendar = readOne(s)
            removePropertiesParameters(data_calendar)
            data = data_calendar.serialize()
            
            result = respdata == data
                    
            if result:
                return True, ""
            else:
                error_diff = "\n".join([line for line in unified_diff(data.split("\n"), respdata.split("\n"))])
                return False, "        Response data does not exactly match file data%s" % (error_diff,)
        except:
            return False, "        Response data is not calendar data data"
            
Example #34
0
 def setUpClass(cls):
     cls.test_file = get_test_file("vcard_with_groups.ics")
     cls.card = base.readOne(cls.test_file)
Example #35
0
    def verify(self, manager, uri, response, respdata, args): #@UnusedVariable
        
        # Must have status 200
        if response.status != 200:
            return False, "        HTTP Status Code Wrong: %d" % (response.status,)

        # Get expected FREEBUSY info
        busy = args.get("busy", [])
        tentative = args.get("tentative", [])
        unavailable = args.get("unavailable", [])
        
        # Parse data as calendar object
        try:
            s = StringIO.StringIO(respdata)
            calendar = readOne(s)
            
            # Check for calendar
            if calendar.name != "VCALENDAR":
                raise ValueError("Top-level component is not a calendar: %s" % (calendar.name, ))
            
            # Only one component
            comps = list(calendar.components())
            if len(comps) != 1:
                raise ValueError("Wrong number of components in calendar")
            
            # Must be VFREEBUSY
            fb = comps[0]
            if fb.name != "VFREEBUSY":
                raise ValueError("Calendar contains unexpected component: %s" % (fb.name, ))
            
            # Extract periods
            busyp = []
            tentativep = []
            unavailablep = []
            for fp in [x for x in fb.lines() if x.name == "FREEBUSY"]:
                periods = fp.value
                # Convert start/duration to start/end
                for i in range(len(periods)):
                    if isinstance(periods[i][1], datetime.timedelta):
                        periods[i] = (periods[i][0], periods[i][0] + periods[i][1])
                # Check param
                fbtype = "BUSY"
                if "FBTYPE" in fp.params:
                    fbtype = fp.params["FBTYPE"][0]
                if fbtype == "BUSY":
                    busyp.extend(periods)
                elif fbtype == "BUSY-TENTATIVE":
                    tentativep.extend(periods)
                elif fbtype == "BUSY-UNAVAILABLE":
                    unavailablep.extend(periods)
                else:
                    raise ValueError("Unknown FBTYPE: %s" % (fbtype,))
            
            # Set sizes must match
            if ((len(busy) != len(busyp)) or
                (len(unavailable) != len(unavailablep)) or
                (len(tentative) != len(tentativep))):
                raise ValueError("Period list sizes do not match.")
            
            # Convert to string sets
            busy = set(busy)
            busyp[:] = [periodToString(x) for x in busyp]
            busyp = set(busyp)
            tentative = set(tentative)
            tentativep[:] = [periodToString(x) for x in tentativep]
            tentativep = set(tentativep)
            unavailable = set(unavailable)
            unavailablep[:] = [periodToString(x) for x in unavailablep]
            unavailablep = set(unavailablep)

            # Compare all periods
            if len(busyp.symmetric_difference(busy)):
                raise ValueError("Busy periods do not match")
            elif len(tentativep.symmetric_difference(tentative)):
                raise ValueError("Busy-tentative periods do not match")
            elif len(unavailablep.symmetric_difference(unavailable)):
                raise ValueError("Busy-unavailable periods do not match")
                
        except VObjectError:
            return False, "        HTTP response data is not a calendar"
        except ValueError, txt:
            return False, "        HTTP response data is invalid: %s" % (txt,)