def _getAliases(self, uuid, dtlist, allDay=False):
     view = self.view
     aliases = []
     for dt in dtlist:
         if allDay or dt.tzinfo == self.floating:
             real_dt = formatDateTime(self.view, dt, allDay, False)
         else:
             real_dt = formatDateTime(self.view, dt.astimezone(self.utc),
                                      False, False)
         aliases.append(uuid + ":" + real_dt)
     return aliases
Example #2
0
    def deserialize(cls, view, text, silentFailure=True):
        """
        Parse an ICalendar blob into a list of record sets
        """

        recordSets = {}
        extra = {'forceDateTriage' : True}

        calname = None
    
        # iterate over calendars, usually only one, but more are allowed
        for calendar in vobject.readComponents(text, validate=False,
                                               ignoreUnreadable=True):
            if calname is None:
                calname = calendar.getChildValue('x_wr_calname')
                if calname is not None:
                    extra['name'] = calname
    
        masters = {}
        for vobj in getattr(calendar, 'vevent_list', []):
            uid = vobj.getChildValue('uid')
            if vobj.getChildValue('recurrence_id') is None:
                masters[uid] = vobj

        uid_to_uuid_map = {}
        
        for vobj in chain(
                                getattr(calendar, 'vevent_list', []),
                                getattr(calendar, 'vtodo_list', [])
                            ):
            try:
                recurrenceID = vobj.getChildValue('recurrence_id')
                summary      = vobj.getChildValue('summary', eim.NoChange)
                description  = vobj.getChildValue('description', eim.NoChange)
                status       = vobj.getChildValue('status', eim.NoChange)
                duration     = vobj.getChildValue('duration')
                uid          = vobj.getChildValue('uid')
                dtstart      = vobj.getChildValue('dtstart')
                location     = vobj.getChildValue('location', eim.NoChange)
                
                # bug 10821, Google serializes modifications with no master;
                # treat these as normal events, not modifications
                if not masters.get(uid):
                    recurrenceID = None
                
                # can't just compare recurrenceID and dtstart, timezone could
                # have changed, and comparing floating to non-floating would
                # raise an exception
                if recurrenceID is None:
                    dtstart_changed = True
                elif dtstart is None:
                    dtstart_changed = False
                elif type(recurrenceID) == date or type(dtstart) == date:
                    dtstart_changed = recurrenceID != dtstart
                else:
                    dtstart_changed = (dtstart.tzinfo != recurrenceID.tzinfo or
                                       dtstart != recurrenceID)
                    
                if status is not eim.NoChange:
                    status = status.upper()

                start_obj = getattr(vobj, 'dtstart', None)

                isVtodo = (vobj.name == 'VTODO')
                osafStarred = vobj.getChildValue('x_osaf_starred')
                if osafStarred:
                    osafStarred = (u"TRUE" == osafStarred.upper())

                if dtstart is None or isVtodo:
                    # due takes precedence over dtstart
                    due = vobj.getChildValue('due')
                    if due is not None:
                        dtstart = due
                        start_obj = getattr(vobj, 'due', None)
                    
                anyTime = False
                if dtstart is not None:
                    anyTimeParam = getattr(start_obj, 'x_osaf_anytime_param',
                                           '')
                    anyTime = anyTimeParam.upper() == 'TRUE'

                isDate = type(dtstart) == date
                allDay = isDate and not anyTime

                
                emitEvent = (dtstart is not None)
                
                if duration is None:
                    dtend = vobj.getChildValue('dtend')
                
                    def getDifference(left, right):
                        leftIsDate = (type(left) == date)
                        rightIsDate = (type(right) == date)
                        
                        if leftIsDate:
                            if rightIsDate:
                                return left - right
                            else:
                                left = forceToDateTime(view, left)
                                
                        elif rightIsDate:
                            right = forceToDateTime(view, right)
        
                        return makeNaiveteMatch(view,
                                                left, right.tzinfo) - right
                        
                    if dtend is not None and dtstart is not None:
                        duration = getDifference(dtend, dtstart)
                            
                    elif anyTime or isDate:
                        duration = timedelta(1)
                    else:
                        duration = timedelta(0)

                # handle the special case of a midnight-to-midnight floating
                # event, treat it as allDay, bug 9579
                if (not isDate and dtstart is not None and
                      dtstart.tzinfo is None and dtstart.time() == midnight and
                      duration.days >= 1 and
                      duration == timedelta(duration.days)):
                    allDay = True
                
                if isDate:
                    dtstart = forceToDateTime(view, dtstart)
                    # originally, duration was converted to Chandler's notion of
                    # all day duration, but this step will be done by the
                    # translator
                    #duration -= oneDay

                if dtstart is not None:
                    dtstart = convertToICUtzinfo(view, dtstart)
                    dtstart = toICalendarDateTime(view, dtstart, allDay, anyTime)
    
                # convert to EIM value
                duration = toICalendarDuration(duration)                

                uuid = UUIDFromICalUID(view, uid_to_uuid_map, uid)

                valarm = getattr(vobj, 'valarm', None)
                
                if valarm is not None:
                    remValue        = valarm.getChildValue('trigger')
                    remDuration     = valarm.getChildValue('duration')
                    remRepeat       = valarm.getChildValue('repeat')
                    remDescription  = valarm.getChildValue('description',
                                                           "Event Reminder")
                    trigger = None
                    
                    if remValue is not None:
                        if type(remValue) is datetime:
                            icutzinfoValue = convertToICUtzinfo(view, remValue)
                            trigger = toICalendarDateTime(view, icutzinfoValue, False)
                        else:
                            assert type(remValue) is timedelta
                            trigger = toICalendarDuration(remValue)
                            
                    if remDuration is not None:
                        remDuration = toICalendarDuration(remDuration)
                        
                    if remRepeat is not None:
                        remRepeat = int(remRepeat)

                recurrence = {}
            
                for rule_name in ('rrule', 'exrule'):
                    rules = []
                    for line in vobj.contents.get(rule_name, []):
                        rules.append(line.value)
                    recurrence[rule_name] = (":".join(rules) if len(rules) > 0 
                                             else eim.NoChange)
            
                for date_name in ('rdate', 'exdate'):
                    dates = []
                    for line in vobj.contents.get(date_name, []):
                        dates.extend(line.value)
                    if len(dates) > 0:
                        if not (allDay or anyTime):
                            dates = [convertToICUtzinfo(view, dt)
                                     for dt in dates]
                        dt_value = toICalendarDateTime(view, dates, allDay, anyTime)
                    else:
                        dt_value = eim.NoChange
                    recurrence[date_name] = dt_value
            

                if recurrenceID is not None:
                    range = getattr(vobj.recurrence_id, 'range_param', 'THIS')
                    if range != 'THIS':
                        logger.info("Skipping a THISANDFUTURE or "
                                    "THISANDPRIOR modification")
                        continue
                    
                    dateValue = allDay or anyTime
                    recurrenceID = forceToDateTime(view, recurrenceID)
                    recurrenceID = convertToICUtzinfo(view, recurrenceID)
                    if recurrenceID.tzinfo != view.tzinfo.floating:
                        recurrenceID = recurrenceID.astimezone(view.tzinfo.UTC)
                    rec_string = translator.formatDateTime(view, recurrenceID,
                                                           dateValue, dateValue)

                    uuid += ":" + rec_string
                    master = masters[uid]
                    uid = eim.Inherit
                    if (master.getChildValue('duration') == 
                          vobj.getChildValue('duration')):
                        duration = eim.Inherit
                    masterAnyTime = (getattr(master.dtstart, 
                                          'x_osaf_anytime_param', '') == 'TRUE')
                    
                    masterAllDay = (not masterAnyTime and 
                                    type(master.dtstart.value) == date)
                    
                    if (masterAllDay == allDay and masterAnyTime == anyTime and
                        not dtstart_changed):
                        dtstart = eim.Inherit
                
                triage = eim.NoChange
                needsReply = eim.NoChange
                
                if isVtodo and status is not eim.NoChange:
                    status = status.lower()
                    code = vtodo_status_to_triage_code.get(status, "100")
                    completed = vobj.getChildValue('completed')
                    if completed is not None:
                        if type(completed) == date:
                            completed = TimeZone.forceToDateTime(view, completed)
                        timestamp = str(Triageable.makeTriageStatusChangedTime(view, completed))
                    else:
                        timestamp = getattr(vobj.status, 'x_osaf_changed_param',
                                            "0.0")
                    auto = getattr(vobj.status, 'x_osaf_auto_param', 'FALSE')
                    auto = ("1" if auto == 'TRUE' else "0")
                    triage =  code + " " + timestamp + " " + auto
                    
                    needsReply = (1 if status == 'needs-action' else 0)

                    # VTODO's status doesn't correspond to EventRecord's status
                    status = eim.NoChange
                
                icalExtra = eim.NoChange
                if not isVtodo:
                    # not processing VTODOs
                    icalExtra = extractUnrecognized(calendar, vobj)
                    if icalExtra is None:
                        icalExtra = ''
                    else:
                        icalExtra = icalExtra.serialize().decode('utf-8')

                records = [model.NoteRecord(uuid,
                                            description,  # body
                                            uid,          # icalUid
                                            None,         # icalProperties
                                            None,         # icalParameters
                                            icalExtra,    # icalExtra
                                            ),
                           model.ItemRecord(uuid, 
                                            summary,        # title
                                            triage,         # triage
                                            eim.NoChange,   # createdOn
                                            eim.NoChange,   # hasBeenSent (TODO)
                                            needsReply,     # needsReply (TODO)
                                            eim.NoChange,   # read
                                            )]
                if emitEvent:
                    records.append(model.EventRecord(uuid,
                                            dtstart,
                                            duration,
                                            location,
                                            recurrence['rrule'],   # rrule
                                            recurrence['exrule'],  # exrule
                                            recurrence['rdate'],   # rdate
                                            recurrence['exdate'],  # exdate
                                            status,                # status
                                            eim.NoChange    # lastPastOccurrence
                                            ))
                if osafStarred:
                    records.append(model.TaskRecord(uuid))
                           
                if valarm is not None:
                    records.append(
                           model.DisplayAlarmRecord(
                                             uuid,
                                             remDescription,
                                             trigger,
                                             remDuration,
                                             remRepeat
                                             ))
                else:
                    records.append(
                        model.DisplayAlarmRecord(
                            uuid,
                            None,
                            None,
                            None,
                            None))

                recordSets[uuid] = RecordSet(records)


            except vobject.base.VObjectError, e:
                icalendarLines = text.splitlines()
                logger.error("Exception when importing icalendar, first 300 lines: \n%s"
                             % "\n".join(icalendarLines[:300]))
                logger.exception("import failed to import one event with exception: %s" % str(e))
                if not silentFailure:
                    raise