UNPKG

@converse/headless

Version:

Converse.js Headless build

152 lines (142 loc) 5.48 kB
import log from '@converse/log'; import { Strophe } from 'strophe.js'; import _converse from './_converse.js'; import api from './api/index.js'; import converse from './api/public.js'; import { CHAT_STATES, MARKER_TYPES } from './constants.js'; const { u, stx, Stanza } = converse.env; /** * Reject an incoming message by replying with an error message of type "cancel". * @param {Element} stanza * @param {string} text * @return void */ export function rejectMessage(stanza, text) { api.send( stx`<message to="${stanza.getAttribute('from')}" type="error" id="${stanza.getAttribute('id')}" xmlns="jabber:client"> <error type="cancel"> <not-allowed xmlns="${Strophe.NS.STANZAS}"/> <text xmlns="${Strophe.NS.STANZAS}">${text}</text> </error> </message>`, ); log.warn(`Rejecting message stanza with the following reason: ${text}`); log.warn(stanza); } /** * Send out a XEP-0333 chat marker. * @fires sendMarker * @param {string} to_jid * @param {string} id - The id of the message being marked * @param {import("./types").MessageMarkerType} type - The marker type * @param {string} [msg_type] */ export async function sendMarker(to_jid, id, type, msg_type) { if (!MARKER_TYPES.includes(type)) { log.error(`Invalid marker type: ${type}`); return; } const bare_jid = Strophe.getBareJidFromJid(to_jid); const chatbox = _converse.state.chatboxes?.get(bare_jid); /** * Hook which lets plugins handle sending a chat marker (such as OMEMO * which sends an encrypted version). If any hook listener returns * `{ handled: true }` the cleartext stanza is suppressed. * * Context: the {@link ChatBox} / {@link MUC} model for `to_jid`, or * `undefined` if not found. * * Hook data: `{ to_jid, id, type, msg_type, handled: false }` * * @example * api.listen.on('sendMarker', async (chatbox, data) => { * if (!chatbox?.get('omemo_active')) return data; * await sendEncryptedMarker(chatbox, data); * return { ...data, handled: true }; * }); */ const { handled } = await api.hook('sendMarker', chatbox, { to_jid, id, type, msg_type, handled: false }); if (handled) return; const stanza = stx` <message from="${api.connection.get().jid}" id="${u.getUniqueId()}" to="${to_jid}" type="${msg_type ? msg_type : 'chat'}" xmlns="jabber:client"> <${Stanza.unsafeXML(type)} xmlns="${Strophe.NS.MARKERS}" id="${id}"/> </message>`; api.send(stanza); } /** * @param {string} to_jid * @param {string} id * @return void */ export function sendReceiptStanza(to_jid, id) { const receipt_stanza = stx` <message from="${api.connection.get().jid}" id="${u.getUniqueId()}" to="${to_jid}" type="chat" xmlns="jabber:client"> <received xmlns="${Strophe.NS.RECEIPTS}" id="${id}"/> <store xmlns="${Strophe.NS.HINTS}"/> </message>`; api.send(receipt_stanza); } /** * Sends a message with the given XEP-0085 chat state. * @param {string} jid * @param {import("./types").ChatStateType} chat_state */ export function sendChatState(jid, chat_state) { if (!jid) { log.error(`sendChatState called with no JID`); return; } else if (!CHAT_STATES.includes(chat_state)) { log.error(`Invalid chat state: ${chat_state}`); return; } if (api.settings.get('send_chat_state_notifications') && chat_state) { const allowed = api.settings.get('send_chat_state_notifications'); if (Array.isArray(allowed) && !allowed.includes(chat_state)) { return; } // When OMEMO is active the OMEMO plugin sends an encrypted SCE version; // suppress the cleartext stanza so only one notification goes out. if (_converse.state.chatboxes?.get(jid)?.get('omemo_active')) return; api.send( stx`<message id="${u.getUniqueId()}" to="${jid}" type="chat" xmlns="jabber:client"> <${Stanza.unsafeXML(chat_state)} xmlns="${Strophe.NS.CHATSTATES}"/> <no-store xmlns="${Strophe.NS.HINTS}"/> <no-permanent-store xmlns="${Strophe.NS.HINTS}"/> </message>`, ); } } /** * Sends a message stanza to retract a message in this chat * @param {string} jid * @param {import('../shared/message').default} message - The message which we're retracting. * @param {string} retraction_id - Unique ID for the retraction message */ export function sendRetractionMessage(jid, message, retraction_id) { const origin_id = message.get('origin_id'); if (!origin_id) { throw new Error("Can't retract message without a XEP-0359 Origin ID"); } const stanza = stx` <message id="${retraction_id}" to="${jid}" type="chat" xmlns="jabber:client"> <retract id="${origin_id}" xmlns="${Strophe.NS.RETRACT}"/> <body>/me retracted a message</body> <store xmlns="${Strophe.NS.HINTS}"/> <fallback xmlns="${Strophe.NS.FALLBACK}" for="${Strophe.NS.RETRACT}" /> </message>`; return api.connection.get().send(stanza); }