"use strict";
import {XMPPService} from "../XMPPService";
import {XMPPUTils, xu} from "../../common/XMPPUtils";
export {};
const moment = require("moment");
const prettydata = require("../pretty-data").pd;
// @ts-ignore
global.window = {};
const momentDurationFormatSetup = require("moment-duration-format");
momentDurationFormatSetup(moment);
// @ts-ignore
global.window = undefined;
const xml = require("@xmpp/xml");
import {Message} from "../../common/models/Message";
import {
findAllPropInJSONByPropertyName,
findAllPropInJSONByPropertyNameByXmlNS,
getObjectFromVariable,
getTextFromJSONProperty,
getAttrFromJSONObj,
isDefined,
isString,
logEntryExit,
msToTime,
getAlternateMessageFromJSONObj
} from "../../common/Utils";
import {ConversationsService} from "../../services/ConversationsService";
import {ContactsService} from "../../services/ContactsService";
import {stringify} from "querystring";
import {GenericHandler} from "./GenericHandler";
import {Conversation} from "../../common/models/Conversation.js";
//import {isObject} from "node:util";
const LOG_ID = "XMPP/HNDL/HIST/CONV - ";
const TYPE_CHAT = "chat";
const TYPE_GROUPCHAT = "groupchat";
@logEntryExit(LOG_ID)
class ConversationHistoryHandler extends GenericHandler {
public MESSAGE: string;
public IQ_GET: any;
public IQ_SET: any;
public IQ_RESULT: any;
public IQ_ERROR: any;
/* public MESSAGE_MAM: any;
public FIN_MAM: any;
public MESSAGE_MAM_BULK: any;
public FIN_MAM_BULK: any; // */
public _conversationService: ConversationsService;
private _contactsService : ContactsService;
public forceHistoryGetContactFromServer : boolean;
private _options: any;
static getClassName(){ return 'ConversationHistoryHandler'; }
getClassName(){ return ConversationHistoryHandler.getClassName(); }
static getAccessorName(){ return 'conversationhistory'; }
getAccessorName(){ return ConversationHistoryHandler.getAccessorName(); }
public historyDelay: number;
constructor(xmppService : XMPPService, conversationService : ConversationsService, contactsService : ContactsService, options : any) {
super( xmppService);
this.MESSAGE = "jabber:client.message";
/* this.MESSAGE_MAM = "urn:xmpp:mam:1.result";
this.FIN_MAM = "urn:xmpp:mam:1.fin";
this.MESSAGE_MAM_BULK = "urn:xmpp:mam:1:bulk.results";
this.FIN_MAM_BULK = "urn:xmpp:mam:1:bulk.fin"; // */
this.IQ_GET = "jabber:client.iq.get";
this.IQ_SET = "jabber:client.iq.set";
this.IQ_RESULT = "jabber:client.iq.result";
this.IQ_ERROR = "jabber:client.iq.error";
this._conversationService = conversationService;
this._contactsService = contactsService;
let that = this;
that._options = options;
that.forceHistoryGetContactFromServer = that._options.imOptions.forceHistoryGetContactFromServer;
that.historyDelay = 0;
}
async onMamMessageReceived(msg, stanzaTab) {
let that = this;
let stanza: any = stanzaTab[0];
let prettyStanza: any = stanzaTab[1];
let jsonStanza: any = stanzaTab[2];
// let startDate = undefined// new Date();
//let stopDate = undefined;
//let startDuration = 0;
try {
that._logger.log(that.INTERNAL, LOG_ID + "(onMamMessageReceived) _entering_");
//that._logger.log(that.INTERNAL, LOG_ID + "(onMamMessageReceived) _entering_ : ", msg, "\n", prettyStanza, "\n jsonStanza : \n", jsonStanza);
if (jsonStanza?.iq?.fin) {
//if ( stanza?.getChild("fin")) {
that._logger.log(that.INTERNAL, LOG_ID + "(onMamMessageReceived) \"fin\" found.");
// let queryId = null;
// that._logger.log(that.INTERNAL, LOG_ID + "(onMamMessageReceived) queryid found on result \"fin\" tag : ", queryId);
// */
// jidTel are used for callLog
if (/*queryId?.indexOf("tel_")!==0 && // */that.onHistoryMessageReceived) {
let startDate : any = new Date();
let treatmentHistoryMesageResult = await that.onHistoryMessageReceived(msg, stanzaTab, null);
let stopDate : any = new Date();
let startDuration = Math.round(stopDate - startDate);
that.historyDelay += startDuration;
if (treatmentHistoryMesageResult==="completed") {
that._logger.log(that.INFO, LOG_ID + "(onMamMessageReceived) is retrieve completed duration : " + that.historyDelay + " ms => ", msToTime(that.historyDelay));
}
}
} else if (jsonStanza?.message?.result) {
// Get queryId and deleteId
// let queryId2 = stanza.getChild("result") ? stanza.getChild("result")?.getAttr("queryid") : null;
let queryId = jsonStanza?.message?.result['$attrs']?.queryid;
if (!queryId) {
if (jsonStanza?.iq?.fin) {
//if ( stanza?.getChild("fin")) {
that._logger.log(that.INTERNAL, LOG_ID + "(onMamMessageReceived) no queryid found on result, and a \"fin\" found.");
/*
let queryId2 = stanza?.getAttr("id");
queryId = jsonStanza?.iq['$attrs']?.id;
that._logger.log(that.INTERNAL, LOG_ID + "(onMamMessageReceived) no queryid found on result, and a \"fin\" found.");
// */
} else {
queryId = null;
}
} else if (queryId.indexOf("id:") === 0 && queryId.length > 13) {
queryId = queryId.substring(13);
}
// */
// jidTel are used for callLog
if (queryId?.indexOf("tel_")!==0 && that.onHistoryMessageReceived) {
let startDate :any = new Date();
// Get associated conversation
let conversation = this._conversationService.getConversationById(queryId);
// For test let bubble = {"id":"room_53851c7c4a554cb79815209cc1dda5db@muc.openrainbow.net", "jid":"room_53851c7c4a554cb79815209cc1dda5db@muc.openrainbow.net"};
// For Test conversation = Conversation.createBubbleConversation(bubble, that._logger, that._options._imOptions);
that.onHistoryMessageReceived(msg, stanzaTab, conversation);
let stopDate :any = new Date();
let startDuration = Math.round(stopDate - startDate);
that.historyDelay += startDuration;
}
// jidIm are used for history
//else if (that.callLogHandler) {
// that.callLogHandler(stanza);
//}
return true;
} else if (jsonStanza?.message?.results) {
that._logger.log(that.DEBUG, LOG_ID + "(onMamMessageReceived) results found, so it is bulk answer ");
// jidTel are used for callLog
// for (let i = 0; i < jsonStanza?.message?.results?.result.length; i++) {
let i = 0;
jsonStanza?.message?.results?.result.forEach((result) => {
//let result = jsonStanza?.message?.results?.result[i];
//that._logger.log(that.INTERNAL, LOG_ID + "(onMamMessageReceived) results [", i, "] : ", result);
// that._logger.log(that.INTERNAL, LOG_ID + "(onMamMessageReceived) a result of results.");
let queryId = result['$attrs']?.queryid;
/*
if (!queryId) {
if (jsonStanza?.iq?.fin) {
//if ( stanza?.getChild("fin")) {
that._logger.log(that.INTERNAL, LOG_ID + "(onMamMessageReceived) no queryid found on result, and a \"fin\" found.");
queryId = jsonStanza?.iq?.id;
} else {
queryId = null;
}
} // */
if (queryId.indexOf("id:") === 0 && queryId.length > 13) {
queryId = queryId.substring(13);
}
if (queryId?.indexOf("tel_")!==0 && that.onHistoryMessageReceived) {
let stanzaTabIter = [];
let startDate :any = new Date();
stanzaTabIter.push({}); // let stanza = stanzaTab[0];
stanzaTabIter.push({}); // let prettyStanza = stanzaTab[1];
stanzaTabIter.push({message: {result}}); // let jsonStanza = stanzaTab[2];
// Get associated conversation
let conversation = this._conversationService.getConversationById(queryId);
that.onHistoryMessageReceived("", stanzaTabIter, conversation);
let stopDate :any = new Date();
let startDuration :any = Math.round(stopDate - startDate);
that.historyDelay += startDuration;
}
i++ ;
});
}
} catch (error) {
return true;
}
}
async onMessageReceived(msg, stanzaTab) {
let that = this;
let stanza = stanzaTab[0];
let prettyStanza = stanzaTab[1];
let jsonStanza = stanzaTab[2];
that._logger.log(that.INTERNAL, LOG_ID + "(onMessageReceived) _entering_ : ", msg, prettyStanza);
try {
let stanzaElem = stanza;
that._logger.log(that.DEBUG, LOG_ID + "(onMessageReceived) jsonStanza : ", jsonStanza);
let jsonStanzaMessage=getObjectFromVariable(jsonStanza?.message);
//for (let key in jsonStanzaMessage) {
Object.entries(jsonStanzaMessage).forEach(([key, value] : any) => // : [key, value]
{
//if (jsonStanza.hasOwnProperty(key)) {
if (key==="results" && value?.$attrs?.xmlns==="urn:xmpp:mam:1:bulk") {
that._logger.log(that.DEBUG, LOG_ID + "(onMessageReceived) found a property 'results' in jsonStanza. (So it is bulk)");
that.onMamMessageReceived(msg, stanzaTab);
return;
}
if (key==="result" && value?.$attrs?.xmlns==="urn:xmpp:mam:1") {
that._logger.log(that.DEBUG, LOG_ID + "(onMessageReceived) found a property 'result' in jsonStanza. (So it is a single message)");
that.onMamMessageReceived(msg, stanzaTab);
return;
}
//}
});
/*
if (findAllPropInJSONByPropertyNameByXmlNS(jsonStanza,"results", "urn:xmpp:mam:1:bulk",1) || findAllPropInJSONByPropertyNameByXmlNS(jsonStanza,"result", "urn:xmpp:mam:1",1)) {
that._logger.log(that.DEBUG, LOG_ID + "(onMessageReceived) found a property in jsonStanza : ", jsonStanza);
that.onMamMessageReceived(msg, stanzaTab);
}
// */
} catch (error) {
// that._logger.log(that.ERROR, LOG_ID + "(onMessageReceived) CATCH Error !!! -- failure -- ");
that._logger.log(that.ERROR, LOG_ID + "(onMessageReceived) CATCH Error !!! -- failure -- : ", error);
//return true;
}
that._logger.log(that.DEBUG, LOG_ID + "(onMessageReceived) _exiting_");
return true;
}
onIqResultReceived (msg, stanzaTab) {
let that = this;
let stanza = stanzaTab[0];
let prettyStanza = stanzaTab[1];
let jsonStanza = stanzaTab[2];
try {
that._logger.log(that.INTERNAL, LOG_ID + "(onIqResultReceived) _entering_", msg, "\n", prettyStanza);
let jsonStanzaIq=getObjectFromVariable(jsonStanza?.iq);
//for (let key in jsonStanzaMessage) {
Object.entries(jsonStanzaIq).forEach(([key, value] : any) => // : [key, value]
{
if (key==="fin" && ( value?.$attrs?.xmlns==="urn:xmpp:mam:1:bulk" || value?.$attrs?.xmlns==="urn:xmpp:mam:1")) {
that._logger.log(that.DEBUG, LOG_ID + "(onIqResultReceived) found a property 'result' in jsonStanza.");
that.onMamMessageReceived(msg, stanzaTab);
return;
}
});
} catch (err) {
// that._logger.log(that.ERROR, LOG_ID + "(onIqResultReceived) CATCH ErrorManager !!! ");
that._logger.log(that.ERROR, LOG_ID + "(onIqResultReceived) CATCH ErrorManager !!! : ", err);
}
};
async onHistoryMessageReceived (msg, stanzaTab, conversation) {
let that = this;
// Handle response
try {
//let conversation: Conversation = null;
let stanza = stanzaTab[0];
let prettyStanza = stanzaTab[1];
let jsonStanza = stanzaTab[2];
that._logger.log(that.INTERNAL, LOG_ID + "(onHistoryMessageReceived) _entering_");
//that._logger.log(that.INTERNAL, LOG_ID + "(onHistoryMessageReceived) _entering_ : ", msg, "\n", prettyStanza);
//that._logger.log(that.INTERNAL, LOG_ID + "(onHistoryMessageReceived) _entering_ : ", msg, "\n", stanza.root ? stanza.root().toString() : stanza);
// that._logger.log(that.INTERNAL, LOG_ID + "(onHistoryMessageReceived) _entering_ : ", msg, "\n", stanza.root ? prettydata.xml(stanza.root().toString()) : stanza);
//let queryId = stanza.getChild("result") ? stanza?.getChild("result")?.getAttr("queryid") : null;
//if (queryId) {
if (conversation) {
// Extract info
// let stanzaForwarded = stanza.getChild("result")?.getChild("forwarded");
let jsonForwarded = jsonStanza?.message?.result?.forwarded;
// let stanzaMessage = stanzaForwarded.getChild("message");
let jsonMessage = jsonForwarded?.message;
if (jsonMessage?.call_log) {
return this.onWebrtcHistoryMessageReceived(stanza, conversation);
}
//let brutJid = stanzaMessage?.getAttr("from");
let brutJid = jsonMessage["$attrs"]?.from;
// Extract fromJid
let fromJid;
let roomEvent = null;
let bodyEvent = undefined;//
Vincent04 Berder04 a rejoint la bulle
let subjectEvent = undefined;// room event
if (brutJid.indexOf("room_")===0) {
fromJid = brutJid.split("/")[1];
} else {
fromJid = XMPPUTils.getXMPPUtils().getBareJIDFromFullJID(brutJid);
}
//const eventElmt = stanzaMessage.find("event"); //findAllPropInJSONByPropertyName
const eventElmt = findAllPropInJSONByPropertyName(jsonMessage, "event"); //findAllPropInJSONByPropertyName
if (Array.isArray(eventElmt)) {
eventElmt.forEach((content) => {
if (!fromJid) {
//roomEvent = content?.attr("name") + "";
roomEvent = content?.$attrs?.name + "";
//fromJid = content?.attr("jid");
fromJid = content?.$attrs?.jid;
if (roomEvent==="welcome" && conversation.bubble && conversation.bubble.creator) {
let ownerContact = conversation.bubble.users.find((user) => conversation.bubble.creator===user.userId)
fromJid = ownerContact ? ownerContact.jid_im:"";
}
}
// that._logger.log(that.DEBUG, LOG_ID + "(onHistoryMessageReceived) message - event, roomEvent : ", roomEvent, ", fromJid : ", fromJid );
});
} else {
// mention['jid'] = eventElmt.text();
if (!fromJid) {
//roomEvent = eventElmt?.attr("name") + "";
roomEvent = eventElmt?.$attrs.name + "";
//fromJid = eventElmt?.attr("jid");
fromJid = eventElmt?.$attrs?.jid;
if (roomEvent==="welcome" && conversation.bubble && conversation.bubble.creator) {
let ownerContact = conversation.bubble.users.find((user) => conversation.bubble.creator===user.userId)
fromJid = ownerContact ? ownerContact.jid_im:"";
}
}
// that._logger.log(that.DEBUG, LOG_ID + "(onHistoryMessageReceived) message - event, roomEvent : ", roomEvent, ", fromJid : ", fromJid );
}
/*
if (!fromJid && stanzaMessage.getChild("event")) {
roomEvent = stanzaMessage.getChild("event")?.attr("name") + "";
fromJid = stanzaMessage.getChild("event")?.attr("jid");
if (roomEvent === "welcome" && conversation.bubble && conversation.bubble.creator) {
let ownerContact = conversation.bubble.users.find( (user) => conversation.bubble.creator === user.userId )
fromJid = ownerContact ? ownerContact.jid_im : "";
}
}
// */
if (!fromJid) {
that._logger.log(that.WARN, LOG_ID + "(onHistoryMessageReceived) - Receive message without valid fromJid information");
return true;
}
if (!conversation.pendingPromise) {
conversation.pendingPromise = [];
}
let promiseContact = new Promise((resolve) => {
// that._logger.log(that.DEBUG, LOG_ID + "(onHistoryMessageReceived) - will getContactByJid - fromJid :", fromJid);
that._contactsService.getContactByJid(fromJid, that.forceHistoryGetContactFromServer)
.then((from) => {
resolve(from);
}).catch((err) => {
that._logger.log(that.ERROR, LOG_ID + "(onHistoryMessageReceived) getContactByJid failed : ", err);
resolve(null);
}); // */
//resolve(null);
}).then(async (from: any) => {
//let type = stanzaMessage?.getAttr("type");
let type = jsonMessage?.$attrs?.type;
//let messageId = stanzaMessage?.getAttr("id");
let messageId = jsonMessage?.$attrs?.id;
//let date = new Date(stanzaForwarded?.getChild("delay")?.getAttr("stamp"));
let date = new Date(jsonForwarded?.delay?.$attrs?.stamp);
let body = getTextFromJSONProperty(jsonMessage?.body);
//let body = stanzaMessage?.getChild("body")?.text();
//let ack = stanzaMessage?.getChild("ack");
let ack = jsonMessage?.ack;
let oobElmt = findAllPropInJSONByPropertyNameByXmlNS(jsonMessage, "x", "jabber:x:oob"); //? jsonMessage?.x //: undefined; // stanzaMessage?.getChild("x", "jabber:x:oob");
//let oobElmt = stanzaMessage?.getChild("x", "jabber:x:oob");
let conference = findAllPropInJSONByPropertyNameByXmlNS(jsonMessage, "x", "jabber:x:audioconference");//stanzaMessage?.getChild("x", "jabber:x:audioconference");
//let content = stanzaMessage?.getChild("content", "urn:xmpp:content");
let content = findAllPropInJSONByPropertyNameByXmlNS(jsonMessage, "content", "urn:xmpp:content"); // stanzaMessage?.getChild("content", "urn:xmpp:content");
let contentObj = content?getAlternateMessageFromJSONObj(content):undefined;
let answeredMsg: Message;
let answeredMsgId: string;
let answeredMsgDate: string;
let answeredMsgStamp: string;
let subject: string;
let attention: boolean;
let urgency: string = "std";
let urgencyAck: boolean = false;
let urgencyHandler: any = undefined;
let attachedMsgId: string;
let attachIndex: number;
let attachNumber: number;
let resource: string;
let toJid: string = "";
let lang: string = "";
let event: string = "";
let eventJid: string = "";
let isEvent: boolean = false;
let oob: any;
let isFileAttachment = false;
let originalMessageReplaced: any = null;
let isForwarded: boolean = false;
let forwardedMsg: any;
let deletedMsg: boolean;
let modifiedMsg: boolean = false;
let mentions: Array