Beispiel #1
0
def get_vcard_property(property_line):
    """
    Get a single property.

    @param property_line: Single unfolded vCard line
    @return: Dictionary with name, parameters and values
    """
    prop = {}

    property_parts = vcard_utils.split_unescaped(property_line, ':')
    if len(property_parts) < 2:
        raise VCardFormatError(
            '{0}: {1}'.format(MSG_MISSING_VALUE_STRING, property_line),
            {})
    elif len(property_parts) > 2:
        # Merge - Colon doesn't have to be escaped in values
        property_parts[1] = ':'.join(property_parts[1:])
        property_parts = property_parts[:2]
    property_string, values_string = property_parts

    # Split property name and property parameters
    property_name_and_params = vcard_utils.split_unescaped(
        property_string,
        ';')

    prop['name'] = property_name_and_params.pop(0)

    # String validation
    if not prop['name'].upper() in ALL_PROPERTIES and not re.match(
        '^X-[{0}]+$'.format(re.escape(ID_CHARS)),
        prop['name'],
        re.IGNORECASE
    ):
        raise VCardFormatError(
            '{0}: {1[name]}'.format(MSG_INVALID_PROPERTY_NAME, prop),
            {})

    try:
        if len(property_name_and_params) != 0:
            prop['parameters'] = get_vcard_property_params(
                ';'.join(property_name_and_params))
        prop['values'] = get_vcard_property_values(values_string)

        # Validate
        vcard_validators.validate_vcard_property(prop)
    except VCardFormatError as error:
        # Add parameter name to error
        error.context['Property line'] = property_line
        raise VCardFormatError(error.message, error.context)

    return prop
Beispiel #2
0
def get_vcard_property_param(param_string):
    """
    Get the parameter name and value(s). RFC 2426 page 29.

    @param param_string: Single parameter and values
    @return: Dictionary with a parameter name and values
    """
    try:
        param_name, values_string = vcard_utils.split_unescaped(
            param_string,
            '=')
    except ValueError as error:
        raise vcard_validators.VCardFormatError(
            '{0}: {1}'.format(MSG_MISSING_PARAM_VALUE, str(error)),
            {})

    values = get_vcard_property_param_values(values_string)

    # Validate
    if not re.match('^[' + ID_CHARS + ']+$', param_name):
        raise vcard_validators.VCardFormatError(
            '{0}: {1}'.format(
                MSG_INVALID_PARAM_NAME,
                param_name),
            {})

    return {'name': param_name, 'values': values}
Beispiel #3
0
def get_vcard_property_values(values_string):
    """
    Get the property values.

    @param values_string: Multiple value string
    @return: List of values (RFC 2426 page 12)
    """
    values = []

    # Strip line ending
    values_string = values_string[:-len(CRLF_CHARS)]

    subvalue_strings = vcard_utils.split_unescaped(values_string, ';')
    for sub in subvalue_strings:
        values.append(get_vcard_property_subvalues(sub))

    return values
Beispiel #4
0
def get_vcard_property_subvalues(value_string):
    """
    Get the parts of the value.

    @param value_string: Single value string
    @return: List of values (RFC 2426 page 9)
    """
    subvalues = vcard_utils.split_unescaped(value_string, ',')

    # Validate string
    for subvalue in subvalues:
        if not re.match('^[' + VALUE_CHARS + ']*$', subvalue):
            raise vcard_validators.VCardFormatError(
                '{0}: {1}'.format(MSG_INVALID_SUBVALUE, subvalue),
                {})

    return subvalues
Beispiel #5
0
def get_vcard_property_param_values(values_string):
    """
    Get the parameter values. RFC 2426 page 29.

    @param values_string: Comma separated values
    @return: Set of values. Assumes that sequence doesn't matter and that
    duplicate values can be discarded, even though RFC 2426 doesn't explicitly
    say this. I.e., assumes that TYPE=WORK,VOICE,WORK === TYPE=VOICE,WORK.
    """
    values = set(vcard_utils.split_unescaped(values_string, ','))

    # Validate
    for value in values:
        if not re.match(u'^[{0}]+$|^"[{1}]+"$'.format(re.escape(SAFE_CHARS), re.escape(QSAFE_CHARS)), value):
            raise VCardFormatError(
                '{0}: {1}'.format(MSG_INVALID_VALUE, value),
                {})

    return values
Beispiel #6
0
def get_vcard_property_params(params_string):
    """
    Get the parameters and their values. RFC 2426 page 28.

    @param params_string: Part of a vCard line between the first semicolon
    and the first colon.
    @return: Dictionary of parameters. Assumes that
    TYPE=WORK;TYPE=WORK,VOICE === TYPE=VOICE,WORK === TYPE=VOICE;TYPE=WORK.
    """
    params = {}
    if not params_string:
        return params

    for param_string in vcard_utils.split_unescaped(params_string, ';'):
        param = get_vcard_property_param(param_string)
        param_name = param['name'].upper()  # To be able to merge TYPE & type
        if param_name not in params:
            params[param_name] = param['values']
        else:
            # Merge
            params[param_name] = params[param_name].union(
                param['values'])

    return params