def parseTextParameters(self, txt, data): """ Parse parameters, return string point at value. """ try: stripValueSpaces = False # Fix for AB.app base PHOTO properties that use two spaces at start of line while txt: if txt[0] == ';': # Parse parameter # Move past delimiter txt = txt[1:] # Get quoted string or token - in iCalendar we only look for "=" here # but for "broken" vCard BASE64 property we need to also terminate on # ":;" parameter_name, txt = stringutils.strduptokenstr(txt, "=:;") if parameter_name is None: raise InvalidProperty("Invalid property", data) if txt[0] != "=": # Deal with parameters without values if ParserContext.VCARD_2_NO_PARAMETER_VALUES == ParserContext.PARSER_RAISE: raise InvalidProperty("Invalid property parameter", data) elif ParserContext.VCARD_2_NO_PARAMETER_VALUES == ParserContext.PARSER_ALLOW: parameter_value = None else: # PARSER_IGNORE and PARSER_FIX parameter_name = None if parameter_name.upper() == "BASE64" and ParserContext.VCARD_2_BASE64 == ParserContext.PARSER_FIX: parameter_name = definitions.Parameter_ENCODING parameter_value = definitions.Parameter_Value_ENCODING_B stripValueSpaces = True else: txt = txt[1:] parameter_value, txt = stringutils.strduptokenstr(txt, ":;,") if parameter_value is None: raise InvalidProperty("Invalid property", data) # Now add parameter value (decode ^-escaping) if parameter_name is not None: attrvalue = Parameter(name=parameter_name, value=decodeParameterValue(parameter_value)) self.mParameters.setdefault(parameter_name.upper(), []).append(attrvalue) # Look for additional values while txt[0] == ',': txt = txt[1:] parameter_value2, txt = stringutils.strduptokenstr(txt, ":;,") if parameter_value2 is None: raise InvalidProperty("Invalid property", data) attrvalue.addValue(decodeParameterValue(parameter_value2)) elif txt[0] == ':': txt = txt[1:] if stripValueSpaces: txt = txt.replace(" ", "") return txt except IndexError: raise InvalidProperty("Invalid property", data)
def parseJSON(cls, jobject): """ Parse a JSON property of the form: [name, attrs, type, value1, value2, ...] @param jobject: a JSON array @type jobject: C{list} """ try: prop = cls() # Get the name prop.mName = jobject[0].encode("utf-8").upper() # Get the parameters if jobject[1]: for name, value in jobject[1].items(): # Now add parameter value name = name.upper() attrvalue = Parameter(name=name.encode("utf-8"), value=value.encode("utf-8")) prop.mParameters.setdefault(name, []).append(attrvalue) # Get default value type from property name and insert a VALUE parameter if current value type is not default value_type = cls.sValueTypeMap.get(jobject[2].upper(), Value.VALUETYPE_UNKNOWN) default_type = cls.sDefaultValueTypeMap.get(prop.mName.upper(), Value.VALUETYPE_UNKNOWN) if default_type != value_type: attrvalue = Parameter(name=cls.sValue, value=jobject[2].encode("utf-8").upper()) prop.mParameters.setdefault(cls.sValue, []).append(attrvalue) # Get value type from property name value_type = prop.determineValueType() # Check for multivalued values = jobject[3:] if prop.mName.upper() in cls.sMultiValues: prop.mValue = MultiValue(value_type) prop.mValue.parseJSONValue(values) else: # Create the type prop.mValue = Value.createFromType(value_type) prop.mValue.parseJSONValue(values[0]) # Special post-create for some types prop._postCreateValue(value_type) return prop except Exception as e: raise InvalidProperty("Invalid property: '{}'".format(e), jobject)
def testParameterEncodingDecoding(self): prop = Property("X-FOO", "Test") prop.addParameter(Parameter("X-BAR", "\"Check\"")) self.assertEqual(str(prop), "X-FOO;X-BAR=^'Check^':Test\r\n") prop.addParameter(Parameter("X-BAR2", "Check\nThis\tOut\n")) self.assertEqual(str(prop), "X-FOO;X-BAR=^'Check^';X-BAR2=Check^nThis\tOut^n:Test\r\n") data = "X-FOO;X-BAR=^'Check^':Test" prop = Property.parseText(data) self.assertEqual(prop.getParameterValue("X-BAR"), "\"Check\"") data = "X-FOO;X-BAR=^'Check^';X-BAR2=Check^nThis\tOut^n:Test" prop = Property.parseText(data) self.assertEqual(prop.getParameterValue("X-BAR"), "\"Check\"") self.assertEqual(prop.getParameterValue("X-BAR2"), "Check\nThis\tOut\n")
def parseTextParameters(self, txt, data): """ Parse parameters, return string point at value. """ try: while txt: if txt[0] == ';': # Parse parameter # Move past delimiter txt = txt[1:] # Get quoted string or token parameter_name, txt = stringutils.strduptokenstr(txt, "=") if parameter_name is None: raise InvalidProperty("Invalid property: empty parameter name", data) txt = txt[1:] parameter_value, txt = stringutils.strduptokenstr(txt, ":;,") if parameter_value is None: raise InvalidProperty("Invalid property: empty parameter value", data) # Now add parameter value (decode ^-escaping) attrvalue = Parameter(name=parameter_name, value=decodeParameterValue(parameter_value)) self.mParameters.setdefault(parameter_name.upper(), []).append(attrvalue) # Look for additional values while txt[0] == ',': txt = txt[1:] parameter_value2, txt = stringutils.strduptokenstr(txt, ":;,") if parameter_value2 is None: raise InvalidProperty("Invalid property: empty parameter multi-value", data) attrvalue.addValue(decodeParameterValue(parameter_value2)) elif txt[0] == ':': return txt[1:] else: # We should never get here but if we do we need to terminate the loop raise InvalidProperty("Invalid property: missing value separator", data) except IndexError: raise InvalidProperty("Invalid property: 'parameter index error'", data)
def parseTextParameters(self, txt, data): """ Parse parameters, return string point at value. """ try: while txt: if txt[0] == ';': # Parse parameter # Move past delimiter txt = txt[1:] # Get quoted string or token parameter_name, txt = stringutils.strduptokenstr(txt, "=") if parameter_name is None: raise InvalidProperty("Invalid property", data) txt = txt[1:] parameter_value, txt = stringutils.strduptokenstr(txt, ":;,") if parameter_value is None: raise InvalidProperty("Invalid property", data) # Now add parameter value (decode ^-escaping) attrvalue = Parameter(name=parameter_name, value=decodeParameterValue(parameter_value)) self.mParameters.setdefault(parameter_name.upper(), []).append(attrvalue) # Look for additional values while txt[0] == ',': txt = txt[1:] parameter_value2, txt = stringutils.strduptokenstr(txt, ":;,") if parameter_value2 is None: raise InvalidProperty("Invalid property", data) attrvalue.addValue(decodeParameterValue(parameter_value2)) elif txt[0] == ':': return txt[1:] else: # We should never get here but if we do we need to terminate the loop raise InvalidProperty("Invalid property", data) except IndexError: raise InvalidProperty("Invalid property", data)
def _init_attr_value_datetime(self, dt): # Value self.mValue = DateTimeValue(value=dt) # Parameters self.setupValueParameter() # Look for timezone if not dt.isDateOnly() and dt.local(): if definitions.cICalParameter_TZID in self.mParameters: del self.mParameters[definitions.cICalParameter_TZID] self.mParameters.setdefault( definitions.cICalParameter_TZID, []).append( Parameter(name=definitions.cICalParameter_TZID, value=dt.getTimezoneID()))
def testAddCN(self): data = ( """BEGIN:VCALENDAR VERSION:2.0 CALSCALE:GREGORIAN PRODID:-//mulberrymail.com//Mulberry v4.0//EN BEGIN:VEVENT UID:C3184A66-1ED0-11D9-A5E0-000A958A3252 DTSTART;VALUE=DATE:20020101 DTEND;VALUE=DATE:20020102 DTSTAMP:20020101T000000Z RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1 ORGANIZER:[email protected] SUMMARY:New Year's Day END:VEVENT END:VCALENDAR """.replace("\n", "\r\n"), "まだ", """BEGIN:VCALENDAR VERSION:2.0 CALSCALE:GREGORIAN PRODID:-//mulberrymail.com//Mulberry v4.0//EN BEGIN:VEVENT UID:C3184A66-1ED0-11D9-A5E0-000A958A3252 DTSTART;VALUE=DATE:20020101 DTEND;VALUE=DATE:20020102 DTSTAMP:20020101T000000Z RRULE:FREQ=YEARLY;UNTIL=20031231;BYMONTH=1 ORGANIZER;CN=まだ:[email protected] SUMMARY:New Year's Day END:VEVENT END:VCALENDAR """.replace("\n", "\r\n"), ) cal1 = Calendar() cal1.parse(StringIO.StringIO(data[0])) vevent = cal1.getComponents("VEVENT")[0] organizer = vevent.getProperties("ORGANIZER")[0] organizer.addParameter(Parameter("CN", data[1])) cal2 = Calendar() cal2.parse(StringIO.StringIO(data[2])) self.assertEqual(str(cal1), str(cal2))
def editTriggerBy(self, duration, trigger_start): # Remove existing self.removeProperties(definitions.cICalProperty_TRIGGER) # Updated cached values self.mTriggerAbsolute = False self.mTriggerBy = duration self.mTriggerOnStart = trigger_start # Add new (with parameter) prop = Property(definitions.cICalProperty_TRIGGER, duration) attr = Parameter( definitions.cICalParameter_RELATED, (definitions.cICalParameter_RELATED_START, definitions.cICalParameter_RELATED_END)[not trigger_start]) prop.addParameter(attr) self.addProperty(prop)
def removePropertiesParameters(component): if not doTimezones: for subcomponent in tuple(component.getComponents()): if subcomponent.getType() == "VTIMEZONE": component.removeComponent(subcomponent) for subcomponent in component.getComponents(): removePropertiesParameters(subcomponent) if component.getType() == "VEVENT": if component.hasEnd(): component.editTimingStartDuration( component.getStart(), component.getEnd() - component.getStart()) allProps = [] for properties in component.getProperties().itervalues(): allProps.extend(properties) for property in allProps: # Always reset DTSTAMP on these properties if property.getName() in ("ATTENDEE", "X-CALENDARSERVER-ATTENDEE-COMMENT"): if property.hasParameter("X-CALENDARSERVER-DTSTAMP"): property.replaceParameter( Parameter("X-CALENDARSERVER-DTSTAMP", "20080101T000000Z")) for filter in filters: if ":" in filter: propname, parameter = filter.split(":") if property.getName() == propname: if property.hasParameter(parameter): property.removeParameters(parameter) else: if "=" in filter: filter_name, filter_value = filter.split("=") if property.getName( ) == filter_name and property.getValue().getValue( ) == filter_value: component.removeProperty(property) else: if property.getName() == filter: component.removeProperty(property)
def setupValueParameter(self): if self.sValue in self.mParameters: del self.mParameters[self.sValue] # Only if we have a value right now if self.mValue is None: return # See if current type is default for this property. If there is no mapping available, # then always add VALUE if it is not TEXT. Always add the value if listed in the # C{sAlwaysValueTypes} attribute. default_type = self.sDefaultValueTypeMap.get(self.mName.upper()) if self.mName.upper() in self.sSpecialVariants: actual_type = default_type else: actual_type = self.mValue.getType() if default_type is None or default_type != actual_type or self.mName.upper() in self.sAlwaysValueTypes: actual_value = self.sTypeValueMap.get(actual_type) if actual_value is not None and (default_type is not None or actual_type != Value.VALUETYPE_TEXT): self.mParameters.setdefault(self.sValue, []).append(Parameter(name=self.sValue, value=actual_value))
def _init_attr_value_datetimelist(self, dtl): # Value date_only = (len(dtl) > 0) and dtl[0].isDateOnly() if date_only: self.mValue = MultiValue(Value.VALUETYPE_DATE) else: self.mValue = MultiValue(Value.VALUETYPE_DATETIME) for dt in dtl: self.mValue.addValue(DateTimeValue(dt)) # Parameters self.setupValueParameter() # Look for timezone if ((len(dtl) > 0) and not dtl[0].isDateOnly() and dtl[0].local()): if definitions.cICalParameter_TZID in self.mParameters: del self.mParameters[definitions.cICalParameter_TZID] self.mParameters.setdefault( definitions.cICalParameter_TZID, []).append( Parameter(name=definitions.cICalParameter_TZID, value=dtl[0].getTimezoneID()))
def parseTextParameters(self, txt, data): """ Parse parameters, return string point at value. """ try: stripValueSpaces = False # Fix for AB.app base PHOTO properties that use two spaces at start of line while txt: if txt[0] == ';': # Parse parameter # Move past delimiter txt = txt[1:] # Get quoted string or token - in iCalendar we only look for "=" here # but for "broken" vCard BASE64 property we need to also terminate on # ":;" parameter_name, txt = stringutils.strduptokenstr( txt, "=:;") if parameter_name is None: raise InvalidProperty( "Invalid property: empty parameter name", data) if txt[0] != "=": # Deal with parameters without values if ParserContext.VCARD_2_NO_PARAMETER_VALUES == ParserContext.PARSER_RAISE: raise InvalidProperty("Invalid property parameter", data) elif ParserContext.VCARD_2_NO_PARAMETER_VALUES == ParserContext.PARSER_ALLOW: parameter_value = None else: # PARSER_IGNORE and PARSER_FIX parameter_name = None if parameter_name.upper( ) == "BASE64" and ParserContext.VCARD_2_BASE64 == ParserContext.PARSER_FIX: parameter_name = definitions.Parameter_ENCODING parameter_value = definitions.Parameter_Value_ENCODING_B stripValueSpaces = True else: txt = txt[1:] parameter_value, txt = stringutils.strduptokenstr( txt, ":;,") if parameter_value is None: raise InvalidProperty( "Invalid property: empty parameter name", data) # Now add parameter value (decode ^-escaping) if parameter_name is not None: attrvalue = Parameter( name=parameter_name, value=decodeParameterValue(parameter_value)) self.mParameters.setdefault(parameter_name.upper(), []).append(attrvalue) # Look for additional values while txt[0] == ',': txt = txt[1:] parameter_value2, txt = stringutils.strduptokenstr( txt, ":;,") if parameter_value2 is None: raise InvalidProperty( "Invalid property: empty parameter multi-value", data) attrvalue.addValue( decodeParameterValue(parameter_value2)) elif txt[0] == ':': txt = txt[1:] if stripValueSpaces: txt = txt.replace(" ", "") return txt except IndexError: raise InvalidProperty("Invalid property: index error", data)
# Replace with anonymized CUAs: for propName in ('organizer', 'attendee'): try: for prop in tuple(comp.getProperties(propName)): cua = prop.getValue().getValue() record = directoryMap.lookupCUA(cua) if record is None: # print("Can't find record for", cua) record = directoryMap.addRecord(cua=cua) if record is None: comp.removeProperty(prop) continue prop.setValue("urn:uuid:%s" % (record['guid'], )) if prop.hasParameter('X-CALENDARSERVER-EMAIL'): prop.replaceParameter( Parameter('X-CALENDARSERVER-EMAIL', record['email'])) else: prop.removeParameters('EMAIL') prop.addParameter(Parameter('EMAIL', record['email'])) prop.removeParameters('CN') prop.addParameter(Parameter('CN', record['name'])) except KeyError: pass # Replace with anonymized text: for propName in ('summary', 'location', 'description'): try: for prop in comp.getProperties(propName): prop.setValue(anonymize(prop.getValue().getValue())) except KeyError: pass