def prepareVobj(view, uuid, recordSet, vobjs): """ Determine if a recordset is for a vtodo, or a vevent, then create it. Modifications may not have event records OR task records, so for modifications, check what was done for the master. This relies on recordsets for masters being processed before modifications. """ master_uuid, recurrenceID = translator.splitUUID(view, uuid) if recurrenceID is None: note, event = hasNoteOrEvent(recordSet) else: if vobjs.get(master_uuid).name.lower() == 'vevent': task, event = False, True else: task, event = True, False if event: vevent = vobject.newFromBehavior('vevent') vevent.isNative = True vobjs[uuid] = vevent else: # @@@ assert note? vtodo = vobject.newFromBehavior('vtodo') vtodo.isNative = True vobjs[uuid] = vtodo
def recordSetsToVObject(cls, view, recordSets, **extra): """ Convert a list of record sets to an ICalendar blob """ vobj_mapping = {} cal = vobject.iCalendar() masterRecordSets = [] nonMasterRecordSets = [] # masters need to be handled first, so modifications have access to them for uuid, recordSet in recordSets.iteritems(): # skip over record sets with neither an EventRecord nor a TaskRecord note, event = hasNoteOrEvent(recordSet) if note or event: uid, recurrenceID = translator.splitUUID(view, uuid) if recurrenceID is None: masterRecordSets.append((uuid, recordSet)) else: nonMasterRecordSets.append((uuid, recordSet)) injectTopLevel = True for uuid, recordSet in chain(masterRecordSets, nonMasterRecordSets): prepareVobj(view, uuid, recordSet, vobj_mapping) icalExtra = None for record in recordSet.inclusions: recordHandlers.get(type(record), Nil)(view, record, vobj_mapping) if type(record) == model.NoteRecord: icalExtra = record.icalExtra if icalExtra not in translator.emptyValues: injectUnrecognized(icalExtra, cal, vobj_mapping.get(uuid), injectTopLevel) # only include unrecognized content lines once per cluster injectTopLevel = False # Tweak SEQUENCE for Google if extra.get('incrementSequence', False): setHigherSequence(vobj_mapping.values()) cal.vevent_list = [ obj for obj in vobj_mapping.values() if obj.name.lower() == 'vevent' ] cal.vtodo_list = [ obj for obj in vobj_mapping.values() if obj.name.lower() == 'vtodo' ] name = extra.get('name') if name is not None: cal.add('x-wr-calname').value = name if extra.get('monolithic', False): # don't add a METHOD to CalDAV serializations, because CalDAV # forbids them, but do add one when serializing monolithic ics files # because Outlook requires them (bug 7121) cal.add('method').value = "PUBLISH" #handle icalendarExtra return cal
def recordSetsToVObject(cls, view, recordSets, **extra): """ Convert a list of record sets to an ICalendar blob """ vobj_mapping = {} cal = vobject.iCalendar() masterRecordSets = [] nonMasterRecordSets = [] # masters need to be handled first, so modifications have access to them for uuid, recordSet in recordSets.iteritems(): # skip over record sets with neither an EventRecord nor a TaskRecord note, event = hasNoteOrEvent(recordSet) if note or event: uid, recurrenceID = translator.splitUUID(view, uuid) if recurrenceID is None: masterRecordSets.append( (uuid, recordSet) ) else: nonMasterRecordSets.append( (uuid, recordSet) ) injectTopLevel = True for uuid, recordSet in chain(masterRecordSets, nonMasterRecordSets): prepareVobj(view, uuid, recordSet, vobj_mapping) icalExtra = None for record in recordSet.inclusions: recordHandlers.get(type(record), Nil)(view, record, vobj_mapping) if type(record) == model.NoteRecord: icalExtra = record.icalExtra if icalExtra not in translator.emptyValues: injectUnrecognized(icalExtra, cal, vobj_mapping.get(uuid), injectTopLevel) # only include unrecognized content lines once per cluster injectTopLevel = False # Tweak SEQUENCE for Google if extra.get('incrementSequence', False): setHigherSequence(vobj_mapping.values()) cal.vevent_list = [obj for obj in vobj_mapping.values() if obj.name.lower() == 'vevent'] cal.vtodo_list = [obj for obj in vobj_mapping.values() if obj.name.lower() == 'vtodo'] name = extra.get('name') if name is not None: cal.add('x-wr-calname').value = name if extra.get('monolithic', False): # don't add a METHOD to CalDAV serializations, because CalDAV # forbids them, but do add one when serializing monolithic ics files # because Outlook requires them (bug 7121) cal.add('method').value = "PUBLISH" #handle icalendarExtra return cal
def readNoteRecord(view, noteRecord, vobjs): vobj = getVobj(noteRecord, vobjs) if noteRecord.body not in translator.emptyValues: vobj.add('description').value = noteRecord.body icalUID = noteRecord.icalUid if icalUID in translator.emptyValues: # empty icalUID for a master means use uuid, for a modification it means # inherit icalUID uuid, recurrenceID = translator.splitUUID(view, noteRecord.uuid) if recurrenceID is None: icalUID = uuid else: icalUID = vobjs[uuid].uid.value vobj.add('uid').value = icalUID
def readEventRecord(view, eventRecord, vobjs): vevent = getVobj(eventRecord, vobjs) master = None uuid, recurrenceID = translator.splitUUID(view, eventRecord.uuid) if recurrenceID is not None: master = vobjs[uuid] m_start = master.dtstart anyTime = False if getattr(m_start, 'value_param', '') == 'DATE': recurrenceID = recurrenceID.date() anyTime = (getattr(m_start, 'x_osaf_anytime_param', '') == 'TRUE') elif recurrenceID.tzinfo == view.tzinfo.floating: recurrenceID = recurrenceID.replace(tzinfo=None) elif recurrenceID.tzinfo == view.tzinfo.UTC: # convert UTC recurrence-id (which is legal, but unusual in # iCalendar) to the master's dtstart timezone tzid = getattr(m_start, 'tzid_param', None) if tzid is not None: tzinfo = view.tzinfo.getInstance(tzid) recurrenceID = recurrenceID.astimezone(tzinfo) vevent.add('recurrence-id').value = recurrenceID if eventRecord.dtstart in translator.emptyValues: if recurrenceID is not None: dtstart = vevent.add('dtstart') dtstart.value = recurrenceID if anyTime: dtstart.x_osaf_anytime_param = "TRUE" else: vevent.dtstart = textLineToContentLine("DTSTART" + eventRecord.dtstart) pruneDateTimeParam(vevent.dtstart) registerTZID(view, vevent.dtstart) for name in ['duration', 'status', 'location']: eimValue = getattr(eventRecord, name) if eimValue not in translator.emptyValues: line = vevent.add(name) line.value = eimValue line.isNative = False if hasattr(vevent, 'duration'): vevent.duration.value = vevent.duration.value.upper() elif recurrenceID: vevent.add('duration').value = master.duration.value vevent.duration.isNative = False timestamp = datetime.utcnow() vevent.add('dtstamp').value = timestamp.replace(tzinfo=view.tzinfo.UTC) # rruleset for rule_name in ('rrule', 'exrule'): rules = [] record_value = getattr(eventRecord, rule_name) if record_value not in translator.emptyValues: for rule_value in record_value.split(':'): rule_value = freq_first(rule_value) # EIM concatenates multiple rules with : rules.append( textLineToContentLine(rule_name + ":" + rule_value)) vevent.contents[rule_name] = rules for date_name in ('rdate', 'exdate'): record_value = getattr(eventRecord, date_name) if record_value not in translator.emptyValues: # multiple dates should always be on one line setattr(vevent, date_name, textLineToContentLine(date_name + record_value)) pruneDateTimeParam(getattr(vevent, date_name))
def readEventRecord(view, eventRecord, vobjs): vevent = getVobj(eventRecord, vobjs) master = None uuid, recurrenceID = translator.splitUUID(view, eventRecord.uuid) if recurrenceID is not None: master = vobjs[uuid] m_start = master.dtstart anyTime = False if getattr(m_start, 'value_param', '') == 'DATE': recurrenceID = recurrenceID.date() anyTime = (getattr(m_start, 'x_osaf_anytime_param', '') == 'TRUE') elif recurrenceID.tzinfo == view.tzinfo.floating: recurrenceID = recurrenceID.replace(tzinfo=None) elif recurrenceID.tzinfo == view.tzinfo.UTC: # convert UTC recurrence-id (which is legal, but unusual in # iCalendar) to the master's dtstart timezone tzid = getattr(m_start, 'tzid_param', None) if tzid is not None: tzinfo = view.tzinfo.getInstance(tzid) recurrenceID = recurrenceID.astimezone(tzinfo) vevent.add('recurrence-id').value = recurrenceID if eventRecord.dtstart in translator.emptyValues: if recurrenceID is not None: dtstart = vevent.add('dtstart') dtstart.value = recurrenceID if anyTime: dtstart.x_osaf_anytime_param = "TRUE" else: vevent.dtstart = textLineToContentLine("DTSTART" + eventRecord.dtstart) pruneDateTimeParam(vevent.dtstart) registerTZID(view, vevent.dtstart) for name in ['duration', 'status', 'location']: eimValue = getattr(eventRecord, name) if eimValue not in translator.emptyValues: line = vevent.add(name) line.value = eimValue line.isNative = False if hasattr(vevent, 'duration'): vevent.duration.value = vevent.duration.value.upper() elif recurrenceID: vevent.add('duration').value = master.duration.value vevent.duration.isNative = False timestamp = datetime.utcnow() vevent.add('dtstamp').value = timestamp.replace(tzinfo=view.tzinfo.UTC) # rruleset for rule_name in ('rrule', 'exrule'): rules = [] record_value = getattr(eventRecord, rule_name) if record_value not in translator.emptyValues: for rule_value in record_value.split(':'): rule_value = freq_first(rule_value) # EIM concatenates multiple rules with : rules.append(textLineToContentLine(rule_name + ":" + rule_value)) vevent.contents[rule_name] = rules for date_name in ('rdate', 'exdate'): record_value = getattr(eventRecord, date_name) if record_value not in translator.emptyValues: # multiple dates should always be on one line setattr(vevent, date_name, textLineToContentLine(date_name + record_value)) pruneDateTimeParam(getattr(vevent, date_name))