Path: blob/master/node_modules/@adiwajshing/baileys/lib/LegacySocket/chats.js
2593 views
"use strict";1var __importDefault = (this && this.__importDefault) || function (mod) {2return (mod && mod.__esModule) ? mod : { "default": mod };3};4Object.defineProperty(exports, "__esModule", { value: true });5const Types_1 = require("../Types");6const generics_1 = require("../Utils/generics");7const WABinary_1 = require("../WABinary");8const auth_1 = __importDefault(require("./auth"));9const makeChatsSocket = (config) => {10const { logger } = config;11const sock = auth_1.default(config);12const { ev, ws: socketEvents, currentEpoch, setQuery, query, sendNode, state } = sock;13const chatsDebounceTimeout = generics_1.debouncedTimeout(10000, () => sendChatsQuery(1));14const sendChatsQuery = (epoch) => (sendNode({15json: {16tag: 'query',17attrs: { type: 'chat', epoch: epoch.toString() }18},19binaryTag: [Types_1.WAMetric.queryChat, Types_1.WAFlag.ignore]20}));21const profilePictureUrl = async (jid, timeoutMs) => {22const response = await query({23json: ['query', 'ProfilePicThumb', jid],24expect200: false,25requiresPhoneConnection: false,26timeoutMs27});28return response.eurl;29};30const executeChatModification = (node) => {31const { attrs: attributes } = node;32const updateType = attributes.type;33const jid = WABinary_1.jidNormalizedUser(attributes === null || attributes === void 0 ? void 0 : attributes.jid);34switch (updateType) {35case 'delete':36ev.emit('chats.delete', [jid]);37break;38case 'clear':39if (node.content) {40const ids = node.content.map(({ attrs }) => attrs.index);41ev.emit('messages.delete', { keys: ids.map(id => ({ id, remoteJid: jid })) });42}43else {44ev.emit('messages.delete', { jid, all: true });45}46break;47case 'archive':48ev.emit('chats.update', [{ id: jid, archive: true }]);49break;50case 'unarchive':51ev.emit('chats.update', [{ id: jid, archive: false }]);52break;53case 'pin':54ev.emit('chats.update', [{ id: jid, pin: attributes.pin ? +attributes.pin : null }]);55break;56case 'star':57case 'unstar':58const starred = updateType === 'star';59const updates = node.content.map(({ attrs }) => ({60key: {61remoteJid: jid,62id: attrs.index,63fromMe: attrs.owner === 'true'64},65update: { starred }66}));67ev.emit('messages.update', updates);68break;69case 'mute':70if (attributes.mute === '0') {71ev.emit('chats.update', [{ id: jid, mute: null }]);72}73else {74ev.emit('chats.update', [{ id: jid, mute: +attributes.mute }]);75}76break;77default:78logger.warn({ node }, 'received unrecognized chat update');79break;80}81};82const applyingPresenceUpdate = (update) => {83const id = WABinary_1.jidNormalizedUser(update.id);84const participant = WABinary_1.jidNormalizedUser(update.participant || update.id);85const presence = {86lastSeen: update.t ? +update.t : undefined,87lastKnownPresence: update.type88};89return { id, presences: { [participant]: presence } };90};91const chatRead = async (fromMessage, count) => {92await setQuery([93{94tag: 'read',95attrs: {96jid: fromMessage.remoteJid,97count: count.toString(),98index: fromMessage.id,99owner: fromMessage.fromMe ? 'true' : 'false'100}101}102], [Types_1.WAMetric.read, Types_1.WAFlag.ignore]);103if (config.emitOwnEvents) {104ev.emit('chats.update', [{ id: fromMessage.remoteJid, unreadCount: count < 0 ? -1 : 0 }]);105}106};107ev.on('connection.update', async ({ connection }) => {108if (connection !== 'open') {109return;110}111try {112await Promise.all([113sendNode({114json: { tag: 'query', attrs: { type: 'contacts', epoch: '1' } },115binaryTag: [Types_1.WAMetric.queryContact, Types_1.WAFlag.ignore]116}),117sendNode({118json: { tag: 'query', attrs: { type: 'status', epoch: '1' } },119binaryTag: [Types_1.WAMetric.queryStatus, Types_1.WAFlag.ignore]120}),121sendNode({122json: { tag: 'query', attrs: { type: 'quick_reply', epoch: '1' } },123binaryTag: [Types_1.WAMetric.queryQuickReply, Types_1.WAFlag.ignore]124}),125sendNode({126json: { tag: 'query', attrs: { type: 'label', epoch: '1' } },127binaryTag: [Types_1.WAMetric.queryLabel, Types_1.WAFlag.ignore]128}),129sendNode({130json: { tag: 'query', attrs: { type: 'emoji', epoch: '1' } },131binaryTag: [Types_1.WAMetric.queryEmoji, Types_1.WAFlag.ignore]132}),133sendNode({134json: {135tag: 'action',136attrs: { type: 'set', epoch: '1' },137content: [138{ tag: 'presence', attrs: { type: 'available' } }139]140},141binaryTag: [Types_1.WAMetric.presence, Types_1.WAFlag.available]142})143]);144chatsDebounceTimeout.start();145logger.debug('sent init queries');146}147catch (error) {148logger.error(`error in sending init queries: ${error}`);149}150});151socketEvents.on('CB:response,type:chat', async ({ content: data }) => {152chatsDebounceTimeout.cancel();153if (Array.isArray(data)) {154const contacts = [];155const chats = data.map(({ attrs }) => {156const id = WABinary_1.jidNormalizedUser(attrs.jid);157if (attrs.name) {158contacts.push({ id, name: attrs.name });159}160return {161id: WABinary_1.jidNormalizedUser(attrs.jid),162conversationTimestamp: attrs.t ? +attrs.t : undefined,163unreadCount: +attrs.count,164archive: attrs.archive === 'true' ? true : undefined,165pin: attrs.pin ? +attrs.pin : undefined,166mute: attrs.mute ? +attrs.mute : undefined,167notSpam: !(attrs.spam === 'true'),168name: attrs.name,169ephemeralExpiration: attrs.ephemeral ? +attrs.ephemeral : undefined,170ephemeralSettingTimestamp: attrs.eph_setting_ts ? +attrs.eph_setting_ts : undefined,171readOnly: attrs.read_only === 'true' ? true : undefined,172};173});174logger.info(`got ${chats.length} chats, extracted ${contacts.length} contacts with name`);175ev.emit('chats.set', { chats, isLatest: true });176}177});178// got all contacts from phone179socketEvents.on('CB:response,type:contacts', async ({ content: data }) => {180if (Array.isArray(data)) {181const contacts = data.map(({ attrs }) => {182return {183id: WABinary_1.jidNormalizedUser(attrs.jid),184name: attrs.name,185notify: attrs.notify,186verifiedName: attrs.verify === '2' ? attrs.vname : undefined187};188});189logger.info(`got ${contacts.length} contacts`);190ev.emit('contacts.set', { contacts });191}192});193// status updates194socketEvents.on('CB:Status,status', json => {195const id = WABinary_1.jidNormalizedUser(json[1].id);196ev.emit('contacts.update', [{ id, status: json[1].status }]);197});198// User Profile Name Updates199socketEvents.on('CB:Conn,pushname', json => {200const { legacy: { user }, connection } = state;201if (connection === 'open' && json[1].pushname !== user.name) {202user.name = json[1].pushname;203ev.emit('connection.update', { legacy: { ...state.legacy, user } });204}205});206// read updates207socketEvents.on('CB:action,,read', async ({ content }) => {208if (Array.isArray(content)) {209const { attrs } = content[0];210const update = {211id: WABinary_1.jidNormalizedUser(attrs.jid)212};213if (attrs.type === 'false') {214update.unreadCount = -1;215}216else {217update.unreadCount = 0;218}219ev.emit('chats.update', [update]);220}221});222socketEvents.on('CB:Cmd,type:picture', async (json) => {223json = json[1];224const id = WABinary_1.jidNormalizedUser(json.jid);225const imgUrl = await profilePictureUrl(id).catch(() => '');226ev.emit('contacts.update', [{ id, imgUrl }]);227});228// chat archive, pin etc.229socketEvents.on('CB:action,,chat', ({ content }) => {230if (Array.isArray(content)) {231const [node] = content;232executeChatModification(node);233}234});235socketEvents.on('CB:action,,user', (json) => {236if (Array.isArray(json.content)) {237const user = json.content[0].attrs;238if (user.id) {239user.id = WABinary_1.jidNormalizedUser(user.id);240//ev.emit('contacts.upsert', [user])241}242else {243logger.warn({ json }, 'recv unknown action');244}245}246});247// presence updates248socketEvents.on('CB:Presence', json => {249const update = applyingPresenceUpdate(json[1]);250ev.emit('presence.update', update);251});252// blocklist updates253socketEvents.on('CB:Blocklist', json => {254json = json[1];255const blocklist = json.blocklist;256ev.emit('blocklist.set', { blocklist });257});258socketEvents.on('ws-close', () => {259chatsDebounceTimeout.cancel();260});261return {262...sock,263sendChatsQuery,264profilePictureUrl,265chatRead,266/**267* Modify a given chat (archive, pin etc.)268* @param jid the ID of the person/group you are modifiying269*/270chatModify: async (modification, jid, chatInfo, timestampNow) => {271const chatAttrs = { jid: jid };272let data = undefined;273timestampNow = timestampNow || generics_1.unixTimestampSeconds();274if ('archive' in modification) {275chatAttrs.type = modification.archive ? 'archive' : 'unarchive';276}277else if ('pin' in modification) {278chatAttrs.type = 'pin';279if (modification.pin) {280chatAttrs.pin = timestampNow.toString();281}282else {283chatAttrs.previous = chatInfo.pin.toString();284}285}286else if ('mute' in modification) {287chatAttrs.type = 'mute';288if (modification.mute) {289chatAttrs.mute = (timestampNow + modification.mute).toString();290}291else {292chatAttrs.previous = chatInfo.mute.toString();293}294}295else if ('clear' in modification) {296chatAttrs.type = 'clear';297chatAttrs.modify_tag = Math.round(Math.random() * 1000000).toString();298if (modification.clear !== 'all') {299data = modification.clear.messages.map(({ id, fromMe }) => ({300tag: 'item',301attrs: { owner: (!!fromMe).toString(), index: id }302}));303}304}305else if ('star' in modification) {306chatAttrs.type = modification.star.star ? 'star' : 'unstar';307data = modification.star.messages.map(({ id, fromMe }) => ({308tag: 'item',309attrs: { owner: (!!fromMe).toString(), index: id }310}));311}312else if ('markRead' in modification) {313const indexKey = modification.lastMessages[modification.lastMessages.length - 1].key;314return chatRead(indexKey, modification.markRead ? 0 : -1);315}316else if ('delete' in modification) {317chatAttrs.type = 'delete';318}319if ('lastMessages' in modification) {320const indexKey = modification.lastMessages[modification.lastMessages.length - 1].key;321if (indexKey) {322chatAttrs.index = indexKey.id;323chatAttrs.owner = indexKey.fromMe ? 'true' : 'false';324}325}326const node = { tag: 'chat', attrs: chatAttrs, content: data };327const response = await setQuery([node], [Types_1.WAMetric.chat, Types_1.WAFlag.ignore]);328if (config.emitOwnEvents) {329// apply it and emit events330executeChatModification(node);331}332return response;333},334/**335* Query whether a given number is registered on WhatsApp336* @param str phone number/jid you want to check for337* @returns undefined if the number doesn't exists, otherwise the correctly formatted jid338*/339onWhatsApp: async (str) => {340const { status, jid, biz } = await query({341json: ['query', 'exist', str],342requiresPhoneConnection: false343});344if (status === 200) {345return {346exists: true,347jid: WABinary_1.jidNormalizedUser(jid),348isBusiness: biz349};350}351},352/**353* Tell someone about your presence -- online, typing, offline etc.354* @param jid the ID of the person/group who you are updating355* @param type your presence356*/357sendPresenceUpdate: (type, jid) => (sendNode({358binaryTag: [Types_1.WAMetric.presence, Types_1.WAFlag[type]],359json: {360tag: 'action',361attrs: { epoch: currentEpoch().toString(), type: 'set' },362content: [363{364tag: 'presence',365attrs: { type: type, to: jid }366}367]368}369})),370/**371* Request updates on the presence of a user372* this returns nothing, you'll receive updates in chats.update event373* */374presenceSubscribe: async (jid) => (sendNode({ json: ['action', 'presence', 'subscribe', jid] })),375/** Query the status of the person (see groupMetadata() for groups) */376getStatus: async (jid) => {377const status = await query({ json: ['query', 'Status', jid], requiresPhoneConnection: false });378return status;379},380setStatus: async (status) => {381const response = await setQuery([382{383tag: 'status',384attrs: {},385content: Buffer.from(status, 'utf-8')386}387]);388ev.emit('contacts.update', [{ id: state.legacy.user.id, status }]);389return response;390},391/** Updates business profile. */392updateBusinessProfile: async (profile) => {393var _a;394if ((_a = profile.business_hours) === null || _a === void 0 ? void 0 : _a.config) {395profile.business_hours.business_config = profile.business_hours.config;396delete profile.business_hours.config;397}398const json = ['action', 'editBusinessProfile', { ...profile, v: 2 }];399await query({ json, expect200: true, requiresPhoneConnection: true });400},401updateProfileName: async (name) => {402const response = (await setQuery([403{404tag: 'profile',405attrs: { name }406}407]));408if (config.emitOwnEvents) {409const user = { ...state.legacy.user, name };410ev.emit('connection.update', { legacy: {411...state.legacy, user412} });413ev.emit('contacts.update', [{ id: user.id, name }]);414}415return response;416},417/**418* Update the profile picture419* @param jid420* @param img421*/422async updateProfilePicture(jid, img) {423var _a;424jid = WABinary_1.jidNormalizedUser(jid);425const data = { img: Buffer.from([]), preview: Buffer.from([]) }; //await generateProfilePicture(img) TODO426const tag = this.generateMessageTag();427const query = {428tag: 'picture',429attrs: { jid: jid, id: tag, type: 'set' },430content: [431{ tag: 'image', attrs: {}, content: data.img },432{ tag: 'preview', attrs: {}, content: data.preview }433]434};435const user = (_a = state.legacy) === null || _a === void 0 ? void 0 : _a.user;436const { eurl } = await this.setQuery([query], [Types_1.WAMetric.picture, 136], tag);437if (config.emitOwnEvents) {438if (jid === user.id) {439user.imgUrl = eurl;440ev.emit('connection.update', {441legacy: {442...state.legacy,443user444}445});446}447ev.emit('contacts.update', [{ id: jid, imgUrl: eurl }]);448}449},450/**451* Add or remove user from blocklist452* @param jid the ID of the person who you are blocking/unblocking453* @param type type of operation454*/455blockUser: async (jid, type = 'add') => {456const json = {457tag: 'block',458attrs: { type },459content: [{ tag: 'user', attrs: { jid } }]460};461await setQuery([json], [Types_1.WAMetric.block, Types_1.WAFlag.ignore]);462if (config.emitOwnEvents) {463ev.emit('blocklist.update', { blocklist: [jid], type });464}465},466/**467* Query Business Profile (Useful for VCards)468* @param jid Business Jid469* @returns profile object or undefined if not business account470*/471getBusinessProfile: async (jid) => {472jid = WABinary_1.jidNormalizedUser(jid);473const { profiles: [{ profile, wid }] } = await query({474json: [475'query', 'businessProfile',476[{ 'wid': jid.replace('@s.whatsapp.net', '@c.us') }],47784478],479expect200: true,480requiresPhoneConnection: false,481});482return {483...profile,484wid: WABinary_1.jidNormalizedUser(wid)485};486}487};488};489exports.default = makeChatsSocket;490491492