def event_reminder_to_airsync(ctx): parser_ctx, transform_ctx = xml2util.ExtractContexts(ctx) src_node = transform_ctx.current() content_node = xml2util.FindChildNode(src_node, "Content") value_node = xml2util.FindChildNode(src_node, "Value") related_node = xml2util.FindChildNode(src_node, "Related") if value_node == None or xml2util.GetNodeValue(value_node).lower() != "duration": return "" if related_node != None and xml2util.GetNodeValue(related_node).lower() != "start": return "" s = xml2util.GetNodeValue(content_node) s = s.lstrip("-PT") s = s.upper() days=0 hours=0 minutes=0 if s.rfind("D") != -1: days = int(s[:s.rfind("D")]) s = s[s.rfind("D")+1:] if s.rfind("H") != -1: hours = int(s[:s.rfind("H")]) s = s[s.rfind("H")+1:] if s.rfind("M") != -1: minutes = int(s[:s.rfind("M")]) s = s[s.rfind("M")+1:] return str(days * MINUTES_PER_DAY + hours * MINUTES_PER_HOUR + minutes)
def TZFromAirsync(ctx): parser_ctx, transform_ctx = xml2util.ExtractContexts(ctx) tznode = transform_ctx.current() tzdata = base64.b64decode(xml2util.GetNodeValue(tznode)) # Some AS timezones fail to include a year. See if we can # graft this from the AS body datenode = xml2util.FindChildNode(tznode.parent,"StartTime") if datenode == None: datenode = xml2util.FindChildNode(tznode.parent,"DtStamp") if datenode == None: year = datetime.datetime.now().year else: txtyear = xml2util.GetNodeValue(datenode) year = int(txtyear[0:4]) tz = tzdatabase.TZFromAirsync(tzdata,year) # only add it if we have a valid timezone if tz!=None: tzdatabase.tzdb.PutTimezone(tz) return ""
def ExceptionDateTimeFromAirsync(ctx): parser_ctx, transform_ctx = xml2util.ExtractContexts(ctx) src_node = transform_ctx.current() dst_node = transform_ctx.insertNode() exception_deleted = xml2util.GetNodeValue( xml2util.FindChildNode(src_node, "Deleted")) exception_date = xml2util.GetNodeValue( xml2util.FindChildNode(src_node, "ExceptionStartTime")) if exception_deleted != "1": raise ValueError( "Opensync does not support exceptions for modified occurrences") # We need to convert to current timezone if one is provided, else # we can assume UTC date = dateutil.TextToDate(exception_date) curtz = tzdatabase.tzdb.GetCurrentTimezone() if curtz != None: date = date.astimezone(curtz) dst_node.setProp("TimezoneID", curtz.name) dst_node = transform_ctx.insertNode() dst_node.setProp("Value", "DATE") tznode = dst_node.newChild(None, "Content", date.strftime(DATE_FORMAT_SHORT)) return ""
def AttendeeFromAirsync(ctx): parser_ctx, transform_ctx = xml2util.ExtractContexts(ctx) src_node = transform_ctx.current() dst_node = transform_ctx.insertNode() email = xml2util.GetNodeValue(xml2util.FindChildNode(src_node, "Email")) name = xml2util.GetNodeValue(xml2util.FindChildNode(src_node, "Name")) if email != "": dst_node.newChild(None, "Content", "MAILTO:%s" % email) dst_node.newChild(None, "CommonName", name) return ""
def AttendeeToAirsync(ctx): parser_ctx, transform_ctx = xml2util.ExtractContexts(ctx) src_node = transform_ctx.current() dst_node = transform_ctx.insertNode() email = xml2util.GetNodeValue(xml2util.FindChildNode(src_node, "Content"))[7:] name = xml2util.GetNodeValue(xml2util.FindChildNode( src_node, "CommonName")) if name != "": dst_node.newChild(None, "Name", name) dst_node.newChild(None, "Email", email) return ""
def task_due_date_from_airsync(ctx): parser_ctx, transform_ctx = xml2util.ExtractContexts(ctx) src_node = transform_ctx.current() asdate = tzutils.TaskTextToDate(xml2util.GetNodeValue(transform_ctx.current())) if tzconv.curtz() != None: # if we have a tz, we must insert the ID and convert to it dst_node.newChild(None,"TimezoneID",tzconv.curtz().name) asdate = tzconv.ConvertToLocal(asdate,tzconv.curtz()) result = asdate.strftime(DATE_FORMAT_VCALTASKLOCAL) else: # if not, does the source have a UtcStartDate element? nd = xml2util.FindChildNode(src_node.parent,"UtcDueDate") if nd != None: result = tzutils.TaskTextToDate(xml2util.GetNodeValue(nd)).strftime(DATE_FORMAT_VCALTASK) else: # we don't have this either. Better hope that the DueDate value # is correct. result = asdate.strftime(DATE_FORMAT_VCALTASKLOCAL) dst_node = transform_ctx.insertNode() dst_node.newChild(None,"Content",result) return ""
def FindASDateElementContent(doc,element): up = xml2util.FindChildNode(doc,element) if up != None: return xml2util.GetNodeValue(up) else: return None
def event_recurrence_from_airsync(ctx): parser_ctx, transform_ctx = xml2util.ExtractContexts(ctx) src_node = transform_ctx.current() dst_node = transform_ctx.insertNode() interval_node = xml2util.FindChildNode(src_node, "Interval") until_node = xml2util.FindChildNode(src_node, "Until") occurrences_node = xml2util.FindChildNode(src_node, "Occurrences") type_node = xml2util.FindChildNode(src_node, "Type") dayofweek_node = xml2util.FindChildNode(src_node, "DayOfWeek") dayofmonth_node = xml2util.FindChildNode(src_node, "DayOfMonth") weekofmonth_node = xml2util.FindChildNode(src_node, "WeekOfMonth") monthofyear_node = xml2util.FindChildNode(src_node, "MonthOfYear") # Add the common nodes that don't really require conversion if interval_node != None: dst_node.newChild(None, "Rule", "INTERVAL=%s" % xml2util.GetNodeValue(interval_node)) if until_node != None: dst_node.newChild(None, "Rule", "UNTIL=%s" % xml2util.GetNodeValue(until_node)) if occurrences_node != None: dst_node.newChild(None, "Rule", "COUNT=%s" % xml2util.GetNodeValue(occurrences_node)) if type_node != None: type = int(xml2util.GetNodeValue(type_node)) # Special case: we can treat this as simple weekly event if type == 0 and dayofweek_node != None: type = 1 if type == 0: dst_node.newChild(None, "Rule", "FREQ=DAILY") elif type == 1: dst_node.newChild(None, "Rule", "FREQ=WEEKLY") dst_node.newChild(None, "Rule", "BYDAY=%s" % airsync_days_to_vcal_days(xml2util.GetNodeValue(dayofweek_node))) elif type == 2: dst_node.newChild(None, "Rule", "FREQ=MONTHLY") dst_node.newChild(None, "Rule", "BYMONTHDAY=%s" % xml2util.GetNodeValue(dayofmonth_node)) elif type == 3: dst_node.newChild(None, "Rule", "FREQ=MONTHLY") dst_node.newChild(None, "Rule", "BYDAY=%s" % generate_vcal_byday(xml2util.GetNodeValue(weekofmonth_node), xml2util.GetNodeValue(dayofweek_node))) elif type == 5: dst_node.newChild(None, "Rule", "FREQ=YEARLY") dst_node.newChild(None, "Rule", "BYMONTH=%s" % xml2util.GetNodeValue(monthofyear_node)) dst_node.newChild(None, "Rule", "BYMONTHDAY=%s" % xml2util.GetNodeValue(dayofmonth_node)) elif type == 6: dst_node.newChild(None, "Rule", "FREQ=YEARLY") dst_node.newChild(None, "Rule", "BYMONTH=%s" % xml2util.GetNodeValue(monthofyear_node)) dst_node.newChild(None, "Rule", "BYDAY=%s" % generate_vcal_byday(xml2util.GetNodeValue(weekofmonth_node), xml2util.GetNodeValue(dayofweek_node))) else: # Unsupported type raise ValueError("Unknown recurrence type %d from Airsync" % type) else: # If we don't know what type of recurrence it is, we # can't construct its vcal rules raise ValueError("No recurrence type specified from Airsync") return ""
def ConvertDateNodeToUTC(node): date = None tdate = None udate = None ctnode = xml2util.FindChildNode(node,"Content") if ctnode != None: tdate = xml2util.GetNodeValue(ctnode).upper() if tdate != "": date = tzutils.TextToDate(tdate) udate = date if date.tzname() != "UTC": tzn=xml2util.FindChildNode(node,"TimezoneID") if tzn!=None: udate = ConvertToUTC(date,xml2util.GetNodeValue(tzn)) else: raise ValueError("Bad date content") return date,udate
def StatusToAirsync(ctx): parser_ctx, transform_ctx = xml2util.ExtractContexts(ctx) curnode = transform_ctx.current() s = xml2util.GetNodeValue(curnode) if s == "COMPLETED": return "1" else: # check that PercentComplete == 100% - mark it completed if # this is the case. up = xml2util.FindChildNode(curnode.parent.parent, "PercentComplete") if up != None: ct = xml2util.FindChildNode(up, "Content") if ct != None: if xml2util.GetNodeValue(ct) == "100": return "1" return "0"
def AllDayEventToAirsync(ctx): parser_ctx, transform_ctx = xml2util.ExtractContexts(ctx) src_node = transform_ctx.current() datetext = xml2util.GetNodeValue( xml2util.FindChildNode(src_node, "Content")) if datetext.find("T") >= 0: return "0" else: return "1"
def all_description_to_airsync(ctx): parser_ctx, transform_ctx = xml2util.ExtractContexts(ctx) src_node = transform_ctx.current() content_node = xml2util.FindChildNode(src_node, "Content") s = xml2util.GetNodeValue(content_node) ec = "" if len(s) > 0: try: asnote = pyrtfcomp.RTFConvertFromUTF8(s,RTFHDR,1) ec=base64.b64encode(asnote) except pyrtfcomp.RTFException, ConvErr: pass
def task_start_date_to_airsync(ctx): parser_ctx, transform_ctx = xml2util.ExtractContexts(ctx) # StartDate without DueDate is not allowed duedate_node = xml2util.FindChildNode(transform_ctx.current().parent, "DateDue") if not duedate_node: return "" localDate,utcDate = tzconv.ConvertDateNodeToUTC(transform_ctx.current()) dst_node = transform_ctx.insertNode() tasks_ns = dst_node.searchNsByHref(transform_ctx.outputDoc(), "http://synce.org/formats/airsync_wm5/tasks") n=dst_node.newChild(tasks_ns,"StartDate",localDate.strftime(DATE_FORMAT_TASKLOCAL)) n=dst_node.newChild(tasks_ns,"UtcStartDate",utcDate.strftime(DATE_FORMAT_TASK)) return ""
def AlarmToAirsync(ctx): parser_ctx, transform_ctx = xml2util.ExtractContexts(ctx) src_node = transform_ctx.current() desc_node = xml2util.FindChildNode(src_node,"Description") content_node = xml2util.FindChildNode(src_node, "AlarmTrigger") # value attribute is mandatory. Convert to blank string if not # present. We only handle 'DURATION' values here, DATE-TIME is a # TODO (we can convert this into a duration for AS) value_node = xml2util.GetNodeAttr(src_node,"Value") if value_node == None: return "" if value_node.lower() != "duration": return "" s = xml2util.GetNodeValue(content_node).lstrip("-PT").upper() days=0 hours=0 minutes=0 if s.rfind("D") != -1: days = int(s[:s.rfind("D")]) s = s[s.rfind("D")+1:] if s.rfind("H") != -1: hours = int(s[:s.rfind("H")]) s = s[s.rfind("H")+1:] if s.rfind("M") != -1: minutes = int(s[:s.rfind("M")]) s = s[s.rfind("M")+1:] return str(days * MINUTES_PER_DAY + hours * MINUTES_PER_HOUR + minutes)
def DateFromAirsync(ctx): parser_ctx, transform_ctx = xml2util.ExtractContexts(ctx) src_node = transform_ctx.current() asdate = dateutil.TaskTextToDate(xml2util.GetNodeValue(src_node)) datetext = asdate.strftime(DATE_FORMAT_VCALTASK) dst_node = transform_ctx.insertNode() curtz = tzdatabase.tzdb.GetCurrentTimezone() if curtz != None: # if we have a tz, we must insert the ID and convert to it dst_node.setProp("TimezoneID", curtz.name) else: # if not, does the source have a UtcStartDate or UtcDueDate element? if src_node.name == "StartDate": utcdatenode = xml2util.FindChildNode(src_node.parent, "UtcStartDate") elif src_node.name == "DueDate": utcdatenode = xml2util.FindChildNode(src_node.parent, "UtcDueDate") else: utcdatenode = None if utcdatenode != None: asdate = dateutil.TaskTextToDate( xml2util.GetNodeValue(utcdatenode)) datetext = asdate.strftime(DATE_FORMAT_VCALTASK) + "Z" dst_node = transform_ctx.insertNode() dst_node.newChild(None, "Content", datetext) return ""
def event_starttime_from_airsync(ctx): parser_ctx, transform_ctx = xml2util.ExtractContexts(ctx) src_node = transform_ctx.current() dst_node = transform_ctx.insertNode() allday_node = xml2util.FindChildNode(src_node.parent, "AllDayEvent") asdate = tzutils.TextToDate(xml2util.GetNodeValue(transform_ctx.current())) if tzconv.curtz() != None: # if we have a tz, we must insert the ID and convert to it dst_node.newChild(None,"TimezoneID",tzconv.curtz().name) asdate = tzconv.ConvertToLocal(asdate,tzconv.curtz()) result = asdate.strftime(DATE_FORMAT_EVLOCAL) else: result = asdate.strftime(DATE_FORMAT_EVENT) if allday_node != None and xml2util.GetNodeValue(allday_node) != "0": result=result[0:8] dst_node.newChild(None,"Content",result) return ""
def RecurrenceRuleFromAirsync(ctx): parser_ctx, transform_ctx = xml2util.ExtractContexts(ctx) src_node = transform_ctx.current() dst_node = transform_ctx.insertNode() interval_node = xml2util.FindChildNode(src_node, "Interval") until_node = xml2util.FindChildNode(src_node, "Until") occurrences_node = xml2util.FindChildNode(src_node, "Occurrences") type_node = xml2util.FindChildNode(src_node, "Type") dayofweek_node = xml2util.FindChildNode(src_node, "DayOfWeek") dayofmonth_node = xml2util.FindChildNode(src_node, "DayOfMonth") weekofmonth_node = xml2util.FindChildNode(src_node, "WeekOfMonth") monthofyear_node = xml2util.FindChildNode(src_node, "MonthOfYear") if type_node != None: type = int(xml2util.GetNodeValue(type_node)) # Special case: we can treat this as simple weekly event if type == 0 and dayofweek_node != None: type = 1 if type == 0: dst_node.newChild(None, "Frequency", "DAILY") if until_node != None: dst_node.newChild(None, "Until", "%s" % xml2util.GetNodeValue(until_node)) if occurrences_node != None: dst_node.newChild(None, "Count", "%s" % xml2util.GetNodeValue(occurrences_node)) if interval_node != None: dst_node.newChild(None, "Interval", "%s" % xml2util.GetNodeValue(interval_node)) elif type == 1: dst_node.newChild(None, "Frequency", "WEEKLY") if until_node != None: dst_node.newChild(None, "Until", "%s" % xml2util.GetNodeValue(until_node)) if occurrences_node != None: dst_node.newChild(None, "Count", "%s" % xml2util.GetNodeValue(occurrences_node)) if interval_node != None: dst_node.newChild(None, "Interval", "%s" % xml2util.GetNodeValue(interval_node)) dst_node.newChild(None, "ByDay", "%s" % AirsyncDaysToVcalDays(xml2util.GetNodeValue(dayofweek_node))) elif type == 2: dst_node.newChild(None, "Frequency", "MONTHLY") if until_node != None: dst_node.newChild(None, "Until", "%s" % xml2util.GetNodeValue(until_node)) if occurrences_node != None: dst_node.newChild(None, "Count", "%s" % xml2util.GetNodeValue(occurrences_node)) if interval_node != None: dst_node.newChild(None, "Interval", "%s" % xml2util.GetNodeValue(interval_node)) dst_node.newChild(None, "ByMonthDay", "%s" % xml2util.GetNodeValue(dayofmonth_node)) elif type == 3: dst_node.newChild(None, "Frequency", "MONTHLY") if until_node != None: dst_node.newChild(None, "Until", "%s" % xml2util.GetNodeValue(until_node)) if occurrences_node != None: dst_node.newChild(None, "Count", "%s" % xml2util.GetNodeValue(occurrences_node)) if interval_node != None: dst_node.newChild(None, "Interval", "%s" % xml2util.GetNodeValue(interval_node)) dst_node.newChild(None, "ByDay", "%s" % GenerateVcalByDay(xml2util.GetNodeValue(weekofmonth_node), xml2util.GetNodeValue(dayofweek_node))) elif type == 5: dst_node.newChild(None, "Frequency", "YEARLY") if until_node != None: dst_node.newChild(None, "Until", "%s" % xml2util.GetNodeValue(until_node)) if occurrences_node != None: dst_node.newChild(None, "Count", "%s" % xml2util.GetNodeValue(occurrences_node)) if interval_node != None: dst_node.newChild(None, "Interval", "%s" % xml2util.GetNodeValue(interval_node)) dst_node.newChild(None, "ByMonth", "%s" % xml2util.GetNodeValue(monthofyear_node)) dst_node.newChild(None, "ByMonthDay", "%s" % xml2util.GetNodeValue(dayofmonth_node)) elif type == 6: dst_node.newChild(None, "Frequency", "YEARLY") if until_node != None: dst_node.newChild(None, "Until", "%s" % xml2util.GetNodeValue(until_node)) if occurrences_node != None: dst_node.newChild(None, "Count", "%s" % xml2util.GetNodeValue(occurrences_node)) if interval_node != None: dst_node.newChild(None, "Interval", "%s" % xml2util.GetNodeValue(interval_node)) dst_node.newChild(None, "ByMonth", "%s" % xml2util.GetNodeValue(monthofyear_node)) dst_node.newChild(None, "ByDay", "%s" % GenerateVcalByDay(xml2util.GetNodeValue(weekofmonth_node), xml2util.GetNodeValue(dayofweek_node))) else: # Unsupported type raise ValueError("Unknown recurrence type %d from Airsync" % type) else: # If we don't know what type of recurrence it is, we # can't construct its vcal rules raise ValueError("No recurrence type specified from Airsync") return ""
def event_recurrence_to_airsync(ctx): parser_ctx, transform_ctx = xml2util.ExtractContexts(ctx) src_node = transform_ctx.current() dst_node = transform_ctx.insertNode() # Extract the rules src_rules = {} child = src_node.children while child != None: if child.name == "Rule": rrule_val = xml2util.GetNodeValue(child) sep = rrule_val.index("=") key = rrule_val[:sep] val = rrule_val[sep+1:] src_rules[key.lower()] = val.lower() child = child.next # Interval, Count, and Until rules have straightforward conversions if src_rules.has_key("interval"): dst_node.newChild(None, "Interval", src_rules["interval"]) if src_rules.has_key("until"): dst_node.newChild(None, "Until", tzutils.TextToDate(src_rules["until"]).strftime(DATE_FORMAT_EVENT)) if src_rules.has_key("count"): dst_node.newChild(None, "Occurrences", src_rules["count"]) # Handle different types of recurrences on a case-by-case basis if src_rules["freq"].lower() == "daily": # There really isn't much to convert in this case.. dst_node.newChild(None, "Type", "0") elif src_rules["freq"].lower() == "weekly": dst_node.newChild(None, "Type", "1") dst_node.newChild(None, "DayOfWeek", str(vcal_days_to_airsync_days(src_rules["byday"]))) elif src_rules["freq"].lower() == "monthly": if src_rules.has_key("bymonthday"): dst_node.newChild(None, "Type", "2") dst_node.newChild(None, "DayOfMonth", src_rules["bymonthday"]) elif src_rules.has_key("byday"): week, day = vcal_split_byday(src_rules["byday"]) dst_node.newChild(None, "Type", "3") dst_node.newChild(None, "DayOfWeek", str(vcal_days_to_airsync_days(day))) if week >= 0: dst_node.newChild(None, "WeekOfMonth", week) elif week == -1: # Airsync deals with this as a special case dst_node.newChild(None, "WeekOfMonth", "5") else: # Not supported (as far as I can tell...) # Airsync cannot count backwards from the end of the # month in general raise ValueError("Airsync does not support counting from end of month") else: # It seems like this should be against the rules, and filling in # a default might not make sense because either of the above interpretations # is equally valid. raise ValueError("Monthly events must either specify BYMONTHDAY or BYDAY rules") elif src_rules["freq"].lower() == "yearly": if src_rules.has_key("bymonth"): if src_rules.has_key("bymonthday"): dst_node.newChild(None, "Type", "5") dst_node.newChild(None, "MonthOfYear", src_rules["bymonth"]) dst_node.newChild(None, "DayOfMonth", src_rules["bymonthday"]) elif src_rules.has_key("byday"): week, day = vcal_split_byday(src_rules["byday"]) dst_node.newChild(None, "Type", "6") dst_node.newChild(None, "MonthOfYear", src_rules["bymonth"]) dst_node.newChild(None, "DayOfWeek", str(vcal_days_to_airsync_days(day))) if week >= 0: dst_node.newChild(None, "WeekOfMonth", week) elif week == -1: # Airsync deals with this as a special case dst_node.newChild(None, "WeekOfMonth", "5") else: # Not supported (as far as I can tell...) # Airsync cannot count backwards from the end of the # month in general raise ValueError("Airsync does not support counting from end of month") else: # It seems like this should be against the rules, and filling in # a default might not make sense because either of the above interpretations # is equally valid. raise ValueError("Yearly events which are by month must either specify BYMONTHDAY or BYDAY rules") elif src_rules.has_key("byyearday"): # Not supported (as far as I can tell...) # Airsync does not have a 'DayOfYear' field raise ValueError("Airsync does not support day-of-year yearly events") else: # we need to get the start/recurrence date from the start date # Get the start date - we need this to expand yearly rules # We should always have a start date in a legal event! start = xml2util.FindChildNode(src_node.parent,"DateStarted") utcdate=tzconv.ConvertDateNodeToUTC(start)[1] # We need the month and the day dst_node.newChild(None,"Type", "5") dst_node.newChild(None,"MonthOfYear",str(utcdate.month)) dst_node.newChild(None,"DayOfMonth",str(utcdate.day)) return ""