Пример #1
0
    def propFilter(self, properties, vcard):
        """
        Returns a vCard component object filtered according to the properties.
        """

        result = Component("VCARD")

        xml_properties = properties

        # Empty element means do all properties and components
        if xml_properties is None:
            xml_properties = AllProperties()

        if xml_properties is not None:
            if xml_properties == AllProperties():
                for vcard_property in vcard.properties():
                    result.addProperty(vcard_property)
            else:
                for xml_property in xml_properties:
                    name = xml_property.property_name
                    for vcard_property in vcard.properties(name):
                        result.addProperty(vcard_property)

                # add required properties
                for requiredProperty in ('N', 'FN', 'VERSION'):
                    if not result.hasProperty(requiredProperty):
                        result.addProperty(vcard.getProperty(requiredProperty))

        return result
Пример #2
0
def vCardFromRecord(record, forceKind=None, addProps=None, parentURI=None):
    def isUniqueProperty(newProperty, ignoredParameters={}):
        existingProperties = vcard.properties(newProperty.name())
        for existingProperty in existingProperties:
            if ignoredParameters:
                existingProperty = existingProperty.duplicate()
                for paramName, paramValues in ignoredParameters.iteritems():
                    for paramValue in paramValues:
                        existingProperty.removeParameterValue(
                            paramName, paramValue)
            if existingProperty == newProperty:
                return False
        return True

    def addUniqueProperty(newProperty, ignoredParameters=None):
        if isUniqueProperty(newProperty, ignoredParameters):
            vcard.addProperty(newProperty)
        else:
            log.info("Ignoring property {prop!r} it is a duplicate",
                     prop=newProperty)

    #=======================================================================
    # start
    #=======================================================================

    log.debug(
        "vCardFromRecord: record={record}, forceKind={forceKind}, addProps={addProps}, parentURI={parentURI}",
        record=record,
        forceKind=forceKind,
        addProps=addProps,
        parentURI=parentURI)

    if forceKind is None:
        kind = recordTypeToVCardKindMap.get(record.recordType, "individual")
    else:
        kind = forceKind

    constantProperties = vCardConstantProperties.copy()
    if addProps:
        for key, value in addProps.iteritems():
            if key not in constantProperties:
                constantProperties[key] = value

    # create vCard
    vcard = Component("VCARD")

    # add constant properties
    for key, value in constantProperties.items():
        vcard.addProperty(Property(key, value))

    #===========================================================================
    # 2.1 Predefined Type Usage
    #===========================================================================
    # 2.1.4 SOURCE Type http://tools.ietf.org/html/rfc2426#section-2.1.4
    if parentURI:
        uri = joinURL(parentURI,
                      record.fields[FieldName.uid].encode("utf-8") + ".vcf")

        # seems like this should be in some standard place.
        if config.EnableSSL and config.SSLPort:
            if config.SSLPort == 443:
                source = "https://{server}{uri}".format(
                    server=config.ServerHostName, uri=uri)
            else:
                source = "https://{server}:{port}{uri}".format(
                    server=config.ServerHostName, port=config.SSLPort, uri=uri)
        else:
            if config.HTTPPort == 80:
                source = "https://{server}{uri}".format(
                    server=config.ServerHostName, uri=uri)
            else:
                source = "https://{server}:{port}{uri}".format(
                    server=config.ServerHostName,
                    port=config.HTTPPort,
                    uri=uri)
        vcard.addProperty(Property("SOURCE", source))

    #===================================================================
    # 3.1 IDENTIFICATION TYPES http://tools.ietf.org/html/rfc2426#section-3.1
    #===================================================================
    # 3.1.1 FN
    vcard.addProperty(
        Property("FN", record.fields[FieldName.fullNames][0].encode("utf-8")))

    # 3.1.2 N
    # TODO: Better parsing
    fullNameParts = record.fields[FieldName.fullNames][0].split()
    first = fullNameParts[0] if len(fullNameParts) >= 2 else None
    last = fullNameParts[len(fullNameParts) - 1]
    middle = fullNameParts[1] if len(fullNameParts) == 3 else None
    prefix = None
    suffix = None

    nameObject = N(
        first=first.encode("utf-8") if first else None,
        last=last.encode("utf-8") if last else None,
        middle=middle.encode("utf-8") if middle else None,
        prefix=prefix.encode("utf-8") if prefix else None,
        suffix=suffix.encode("utf-8") if suffix else None,
    )
    vcard.addProperty(Property("N", nameObject))

    # 3.1.3 NICKNAME
    nickname = record.fields.get(CalFieldName.abbreviatedName)
    if nickname:
        vcard.addProperty(Property("NICKNAME", nickname.encode("utf-8")))

    # UNIMPLEMENTED
    #     3.1.4 PHOTO
    #     3.1.5 BDAY

    #===========================================================================
    # 3.2 Delivery Addressing Types http://tools.ietf.org/html/rfc2426#section-3.2
    #===========================================================================
    # 3.2.1 ADR
    #
    # Experimental:
    #     Use vCard 4.0 ADR: http://tools.ietf.org/html/rfc6350#section-6.3.1
    params = {}
    geo = record.fields.get(CalFieldName.geographicLocation)
    if geo:
        params["GEO"] = geo.encode("utf-8")
    label = record.fields.get(CalFieldName.streetAddress)
    if label:
        params["LABEL"] = label.encode("utf-8")

    #
    extended = record.fields.get(CalFieldName.floor)

    # TODO: Parse?
    street = record.fields.get(CalFieldName.streetAddress)
    city = None
    region = None
    postalcode = None
    country = None

    if extended or street or city or region or postalcode or country or params:
        params["TYPE"] = (
            "WORK",
            "PREF",
            "POSTAL",
            "PARCEL",
        )
        vcard.addProperty(
            Property(
                "ADR",
                Adr(
                    #pobox = box,
                    extended=extended.encode("utf-8") if extended else None,
                    street=street.encode("utf-8") if street else None,
                    locality=city.encode("utf-8") if city else None,
                    region=region.encode("utf-8") if region else None,
                    postalcode=postalcode.encode("utf-8")
                    if postalcode else None,
                    country=country.encode("utf-8") if country else None,
                ),
                params=params))

    #    3.2.2 LABEL
    #label = record.fields.get(CalFieldName.streetAddress)
    if label:
        vcard.addProperty(
            Property("LABEL",
                     label.encode("utf-8"),
                     params={"TYPE": [
                         "POSTAL",
                         "PARCEL",
                     ]}))

    #===================================================================
    # 3.3 TELECOMMUNICATIONS ADDRESSING TYPES http://tools.ietf.org/html/rfc2426#section-3.3
    #===================================================================
    #
    # UNIMPLEMENTED
    #     3.3.1 TEL

    # 3.3.2 EMAIL
    preferredWorkParams = {
        "TYPE": (
            "WORK",
            "PREF",
            "INTERNET",
        ),
    }
    workParams = {
        "TYPE": (
            "WORK",
            "INTERNET",
        ),
    }
    params = preferredWorkParams
    for emailAddress in record.fields.get(FieldName.emailAddresses, ()):
        addUniqueProperty(Property("EMAIL",
                                   emailAddress.encode("utf-8"),
                                   params=params),
                          ignoredParameters={"TYPE": ("PREF", )})
        params = workParams

    # UNIMPLEMENTED:
    #     3.3.3 MAILER
    #
    #===================================================================
    # 3.4 GEOGRAPHICAL TYPES http://tools.ietf.org/html/rfc2426#section-3.4
    #===================================================================
    #
    # UNIMPLEMENTED:
    #     3.4.1 TZ
    #
    # 3.4.2 GEO
    geographicLocation = record.fields.get(CalFieldName.geographicLocation)
    if geographicLocation:
        vcard.addProperty(Property("GEO", geographicLocation.encode("utf-8")))

    #===================================================================
    # 3.5 ORGANIZATIONAL TYPES http://tools.ietf.org/html/rfc2426#section-3.5
    #===================================================================
    #
    # UNIMPLEMENTED:
    #     3.5.1 TITLE
    #     3.5.2 ROLE
    #     3.5.3 LOGO
    #     3.5.4 AGENT
    #     3.5.5 ORG
    #
    #===================================================================
    # 3.6 EXPLANATORY TYPES http://tools.ietf.org/html/rfc2426#section-3.6
    #===================================================================
    #
    # UNIMPLEMENTED:
    #     3.6.1 CATEGORIES
    #     3.6.2 NOTE
    #
    # ADDED WITH CONTSTANT PROPERTIES:
    #     3.6.3 PRODID
    #
    # UNIMPLEMENTED:
    #     3.6.5 SORT-STRING
    #     3.6.6 SOUND

    # 3.6.7 UID
    vcard.addProperty(
        Property("UID", record.fields[FieldName.uid].encode("utf-8")))

    # UNIMPLEMENTED:
    #     3.6.8 URL

    # ADDED WITH CONTSTANT PROPERTIES:
    #     3.6.9 VERSION

    #===================================================================
    # 3.7 SECURITY TYPES http://tools.ietf.org/html/rfc2426#section-3.7
    #===================================================================
    # UNIMPLEMENTED:
    #     3.7.1 CLASS
    #     3.7.2 KEY

    #===================================================================
    # X Properties
    #===================================================================
    # UNIMPLEMENTED:
    #    X-<instant messaging type> such as:
    #        "AIM", "FACEBOOK", "GAGU-GAGU", "GOOGLE TALK", "ICQ", "JABBER", "MSN", "QQ", "SKYPE", "YAHOO",
    #    X-MAIDENNAME
    #    X-PHONETIC-FIRST-NAME
    #    X-PHONETIC-MIDDLE-NAME
    #    X-PHONETIC-LAST-NAME
    #    X-ABRELATEDNAMES

    # X-ADDRESSBOOKSERVER-KIND
    if kind == "group":
        vcard.addProperty(Property("X-ADDRESSBOOKSERVER-KIND", kind))

    # add members
    # FIXME:  members() is a deferred, so all of vCardFromRecord is deferred.
    for memberRecord in (yield record.members()):
        cua = memberRecord.canonicalCalendarUserAddress(False)
        if cua:
            vcard.addProperty(
                Property("X-ADDRESSBOOKSERVER-MEMBER", cua.encode("utf-8")))

    #===================================================================
    # vCard 4.0  http://tools.ietf.org/html/rfc6350
    #===================================================================
    # UNIMPLEMENTED:
    #     6.4.3 IMPP http://tools.ietf.org/html/rfc6350#section-6.4.3
    #
    # 6.1.4 KIND http://tools.ietf.org/html/rfc6350#section-6.1.4
    #
    # see also: http://www.iana.org/assignments/vcard-elements/vcard-elements.xml
    #
    vcard.addProperty(Property("KIND", kind))

    # one more X- related to kind
    if kind == "org":
        vcard.addProperty(Property("X-ABShowAs", "COMPANY"))

    log.debug("vCardFromRecord: vcard=\n{vcard}", vcard=vcard)
    returnValue(vcard)