All Downloads are FREE. Search and download functionalities are using the official Maven repository.

it.auties.whatsapp.model.contact.ContactCard Maven / Gradle / Ivy

package it.auties.whatsapp.model.contact;

import ezvcard.Ezvcard;
import ezvcard.VCard;
import ezvcard.VCardVersion;
import ezvcard.property.SimpleProperty;
import ezvcard.property.Telephone;
import it.auties.protobuf.annotation.ProtobufConverter;
import it.auties.whatsapp.model.jid.Jid;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static it.auties.whatsapp.util.Specification.Whatsapp.*;


/**
 * A model class to represent and build the vcard of a contact
 */
public sealed interface ContactCard {
    @ProtobufConverter
    static ContactCard ofProtobuf(String vcard) {
        return vcard == null ? null : of(vcard);
    }

    /**
     * Parses a vcard
     * If the vCard dependency wasn't included, or a parsing error occurs, a raw representation is returned
     *
     * @param vcard the non-null vcard to parse
     * @return a non-null vcard
     */
    static ContactCard of(String vcard) {
        try {
            var parsed = Ezvcard.parse(vcard).first();
            var version = Optional.ofNullable(parsed.getVersion().getVersion());
            var name = Optional.ofNullable(parsed.getFormattedName().getValue());
            var phoneNumbers = parsed.getTelephoneNumbers()
                    .stream()
                    .filter(ContactCard::isValidPhoneNumber)
                    .collect(Collectors.toUnmodifiableMap(ContactCard::getPhoneType, ContactCard::getPhoneValue, ContactCard::joinPhoneNumbers));
            var businessName = Optional.ofNullable(parsed.getExtendedProperty(BUSINESS_NAME_VCARD_PROPERTY))
                    .map(SimpleProperty::getValue);
            return new Parsed(version, name, phoneNumbers, businessName);
        } catch (Throwable ignored) {
            return new Raw(vcard);
        }
    }

    private static boolean isValidPhoneNumber(Telephone entry) {
        return getPhoneType(entry) != null && entry.getParameter(PHONE_NUMBER_VCARD_PROPERTY) != null;
    }

    private static String getPhoneType(Telephone entry) {
        return entry.getParameters().getType();
    }

    private static List getPhoneValue(Telephone entry) {
        return List.of(Jid.of(entry.getParameter(PHONE_NUMBER_VCARD_PROPERTY)));
    }

    private static List joinPhoneNumbers(List first, List second) {
        return Stream.of(first, second).flatMap(Collection::stream).toList();
    }

    @ProtobufConverter
    String toVcard();

    /**
     * A parsed representation of the vcard
     */
    record Parsed(
            Optional version,
            Optional name,
            Map> phoneNumbers,
            Optional businessName
    ) implements ContactCard {
        public List getPhoneNumber(Jid contact) {
            return Objects.requireNonNullElseGet(phoneNumbers.get(DEFAULT_NUMBER_VCARD_TYPE), List::of);
        }

        private void addPhoneNumber(VCard vcard, String type, Jid contact) {
            var telephone = new Telephone(contact.toPhoneNumber());
            telephone.getParameters().setType(type);
            telephone.getParameters().put(PHONE_NUMBER_VCARD_PROPERTY, contact.user());
            vcard.addTelephoneNumber(telephone);
        }

        public void addPhoneNumber(Jid contact) {
            addPhoneNumber(DEFAULT_NUMBER_VCARD_TYPE, contact);
        }

        public void addPhoneNumber(String category, Jid contact) {
            var oldValue = phoneNumbers.get(category);
            if (oldValue == null) {
                phoneNumbers.put(category, List.of(contact));
                return;
            }

            var values = new ArrayList<>(oldValue);
            values.add(contact);
            phoneNumbers.put(category, Collections.unmodifiableList(values));
        }

        /**
         * Converts this object in a valid vcard
         *
         * @return a non-null String
         */
        @Override
        @ProtobufConverter
        public String toVcard() {
            var vcard = new VCard();
            vcard.setVersion(version().map(VCardVersion::valueOfByStr).orElse(VCardVersion.V3_0));
            vcard.setFormattedName(name.orElse(null));
            phoneNumbers().forEach((type, contacts) -> contacts.forEach(contact -> addPhoneNumber(vcard, type, contact)));
            businessName.ifPresent(value -> vcard.addExtendedProperty(BUSINESS_NAME_VCARD_PROPERTY, value));
            return Ezvcard.write(vcard).go();
        }
    }

    /**
     * A raw representation of the vcard
     */
    record Raw(String toVcard) implements ContactCard {
        @Override
        @ProtobufConverter
        public String toVcard() {
            return toVcard;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy