Converse converse.js

Source: headless/plugins/vcard/utils.js

import log from "@converse/headless/log";
import { _converse, api, converse } from "../../core.js";
import { initStorage } from '@converse/headless/utils/storage.js';
import { shouldClearCache } from '@converse/headless/utils/core.js';

const { Strophe, $iq, u } = converse.env;


async function onVCardData (jid, iq) {
    const vcard = iq.querySelector('vCard');
    let result = {};
    if (vcard !== null) {
        result = {
            'stanza': iq,
            'fullname': vcard.querySelector('FN')?.textContent,
            'nickname': vcard.querySelector('NICKNAME')?.textContent,
            'image': vcard.querySelector('PHOTO BINVAL')?.textContent,
            'image_type': vcard.querySelector('PHOTO TYPE')?.textContent,
            'url': vcard.querySelector('URL')?.textContent,
            'role': vcard.querySelector('ROLE')?.textContent,
            'email': vcard.querySelector('EMAIL USERID')?.textContent,
            'vcard_updated': (new Date()).toISOString(),
            'vcard_error': undefined
        };
    }
    if (result.image) {
        const buffer = u.base64ToArrayBuffer(result['image']);
        const ab = await crypto.subtle.digest('SHA-1', buffer);
        result['image_hash'] = u.arrayBufferToHex(ab);
    }
    return result;
}


export function createStanza (type, jid, vcard_el) {
    const iq = $iq(jid ? {'type': type, 'to': jid} : {'type': type});
    if (!vcard_el) {
        iq.c("vCard", {'xmlns': Strophe.NS.VCARD});
    } else {
        iq.cnode(vcard_el);
    }
    return iq;
}


export function onOccupantAvatarChanged (occupant) {
    const hash = occupant.get('image_hash');
    const vcards = [];
    if (occupant.get('jid')) {
        vcards.push(_converse.vcards.get(occupant.get('jid')));
    }
    vcards.push(_converse.vcards.get(occupant.get('from')));
    vcards.forEach(v => (hash && v?.get('image_hash') !== hash) && api.vcard.update(v, true));
}


export async function setVCardOnModel (model) {
    let jid;
    if (model instanceof _converse.Message) {
        if (['error', 'info'].includes(model.get('type'))) {
            return;
        }
        jid = model.get('from');
    } else {
        jid = model.get('jid');
    }

    if (!jid) {
        log.warn(`Could not set VCard on model because no JID found!`);
        return;
    }

    await api.waitUntil('VCardsInitialized');
    model.vcard = _converse.vcards.get(jid) || _converse.vcards.create({ jid });
    model.vcard.on('change', () => model.trigger('vcard:change'));
    model.trigger('vcard:add');
}


function getVCardForOccupant (occupant) {
    const muc = occupant?.collection?.chatroom;
    const nick = occupant.get('nick');

    if (nick && muc?.get('nick') === nick) {
        return _converse.xmppstatus.vcard;
    } else {
        const jid = occupant.get('jid') || occupant.get('from');
        if (jid) {
            return _converse.vcards.get(jid) || _converse.vcards.create({ jid });
        } else {
            log.warn(`Could not get VCard for occupant because no JID found!`);
            return;
        }
    }
}

export async function setVCardOnOccupant (occupant) {
    await api.waitUntil('VCardsInitialized');
    occupant.vcard = getVCardForOccupant(occupant);
    if (occupant.vcard) {
        occupant.vcard.on('change', () => occupant.trigger('vcard:change'));
        occupant.trigger('vcard:add');
    }
}


function getVCardForMUCMessage (message) {
    const muc = message?.collection?.chatbox;
    const nick = Strophe.getResourceFromJid(message.get('from'));

    if (nick && muc?.get('nick') === nick) {
        return _converse.xmppstatus.vcard;
    } else {
        const jid = message.occupant?.get('jid') || message.get('from');
        if (jid) {
            return _converse.vcards.get(jid) || _converse.vcards.create({ jid });
        } else {
            log.warn(`Could not get VCard for message because no JID found! msgid: ${message.get('msgid')}`);
            return;
        }
    }
}

export async function setVCardOnMUCMessage (message) {
    if (['error', 'info'].includes(message.get('type'))) {
        return;
    } else {
        await api.waitUntil('VCardsInitialized');
        message.vcard = getVCardForMUCMessage(message);
        if (message.vcard) {
            message.vcard.on('change', () => message.trigger('vcard:change'));
            message.trigger('vcard:add');
        }
    }
}


export async function initVCardCollection () {
    _converse.vcards = new _converse.VCards();
    const id = `${_converse.bare_jid}-converse.vcards`;
    initStorage(_converse.vcards, id);
    await new Promise(resolve => {
        _converse.vcards.fetch({
            'success': resolve,
            'error': resolve
        }, {'silent': true});
    });
    const vcards = _converse.vcards;
    if (_converse.session) {
        const jid = _converse.session.get('bare_jid');
        const status = _converse.xmppstatus;
        status.vcard = vcards.get(jid) || vcards.create({'jid': jid});
        if (status.vcard) {
            status.vcard.on('change', () => status.trigger('vcard:change'));
            status.trigger('vcard:add');
        }
    }
    /**
     * Triggered as soon as the `_converse.vcards` collection has been initialized and populated from cache.
     * @event _converse#VCardsInitialized
     */
    api.trigger('VCardsInitialized');
}


export function clearVCardsSession () {
    if (shouldClearCache()) {
        api.promises.add('VCardsInitialized');
        if (_converse.vcards) {
            _converse.vcards.clearStore();
            delete _converse.vcards;
        }
    }
}

export async function getVCard (jid) {
    const to = Strophe.getBareJidFromJid(jid) === _converse.bare_jid ? null : jid;
    let iq;
    try {
        iq = await api.sendIQ(createStanza("get", to))
    } catch (iq) {
        return {
            jid,
            'stanza': iq,
            'vcard_error': (new Date()).toISOString()
        }
    }
    return onVCardData(jid, iq);
}