diff --git a/lib/session.js b/lib/session.js index a739544..1ae34b8 100644 --- a/lib/session.js +++ b/lib/session.js @@ -363,22 +363,31 @@ function sendLongSms(smsOptions, callback) { // Store long smses in the temporary storage function longSms(pduObj) { - var smsGroupId = pduObj.params.short_message[3], - smsParts = pduObj.params.short_message[4], - longSmsId = pduObj.params.source_addr + '_' + pduObj.params.destination_addr + '_' + smsGroupId; + // Fix: UDH values are stored in HEX and decoding them make it garbage. First OCTET contains + // the size of UDH data header. If UDH data header size is 0x05 then field 4 i.e. CSMS + // reference number is of one octet otherwise it consists of 2 octets. Other fields can + // be found from below reference. + // reference: https://en.wikipedia.org/wiki/Concatenated_SMS + var udhSize = pduObj.params['udhHeader'].size, + smsGroupId = pduObj.params['udhHeader'].reference, + smsParts = pduObj.params['udhHeader'].totalParts, + partNr = pduObj.params['udhHeader'].partNr; + + var longSmsId = pduObj.params.source_addr + '_' + pduObj.params.destination_addr + '_' + smsGroupId; if (this.longSmses[longSmsId] === undefined) { this.longSmses[longSmsId] = { 'created': new Date(), 'partsCount': parseInt(smsParts), + 'udhSize': udhSize, // Saving udh size to remove garbage from message 'pduObjs': [{ - 'partNr': pduObj.params.short_message[5], // We save this here to easier sort the array later on + 'partNr': partNr, // We save this here to easier sort the array later on 'pduObj': pduObj }] }; } else { this.longSmses[longSmsId].pduObjs.push({ - 'partNr': pduObj.params.short_message[5], // We save this here to easier sort the array later on + 'partNr': partNr, // We save this here to easier sort the array later on 'pduObj': pduObj }); } @@ -406,6 +415,7 @@ function checkLongSmses() { var that = this, smsGroupId, smsGroup, + udhSize, // UDH Size from longSms() function smsObj, i, curPduObj; @@ -422,7 +432,7 @@ function checkLongSmses() { for (smsGroupId in this.longSmses) { smsGroup = this.longSmses[smsGroupId]; - + udhSize = smsGroup.udhSize; // All parts are accounted for! Emit sms event and clear from tmp storage if (smsGroup.partsCount === smsGroup.pduObjs.length) { log.debug('larvitsmpp: lib/session.js: checkLongSmses() - All parts accounted for in smsGroupId "' + smsGroupId + '", emitting sms event.'); @@ -451,7 +461,9 @@ function checkLongSmses() { curPduObj = smsObj.pduObjs[i].pduObj; curPduObj.session = this; - smsObj.message += utils.decodeMsg(curPduObj.params.short_message, curPduObj.params.data_coding, curPduObj.params.short_message[0] + 1); + // Fix: message in pduObj is already decoded we dont need to do it again. Also removing garbade from original message. + //smsObj.message += utils.decodeMsg(curPduObj.params.short_message, curPduObj.params.data_coding, curPduObj.params.short_message[0] + 1); + smsObj.message += curPduObj.params.short_message.substring(udhSize + 1); i ++; } @@ -557,7 +569,9 @@ function session(sock) { var smsObj = {}; // If esm_class is 0x40 it means this is just a part of a larger message - if (pduObj.params.esm_class === 0x40) { + //if (pduObj.params.esm_class === 0x40) { + // Fix: esm_class can be combination of bits. We need to extract 0x40 and then compare + if ((pduObj.params.esm_class & 0x40) === 0x40) { log.debug('larvitsmpp: lib/session.js: session() - returnObj.handleCmd.submit_sm() - long sms detected, esm_class 0x40.'); returnObj.longSms(pduObj); return; // Long messages should not get handled here at all, so cancel execution here @@ -709,4 +723,4 @@ function session(sock) { } // Expose some functions -exports = module.exports = session; \ No newline at end of file +exports = module.exports = session; diff --git a/lib/utils.js b/lib/utils.js index f806205..3beadb7 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -271,8 +271,28 @@ function pduToObj(pdu, stupidNullByte, callback) { paramSize = command.params[param].type.size(retObj.params[param]); log.silly('larvitsmpp: lib/utils.js: pduToObj() - Reading param "' + param + '" at offset ' + offset + ' with calculated size: ' + paramSize + ' content in hex: ' + pdu.slice(offset, offset + paramSize).toString('hex')); - if (param === 'short_message') { + if((retObj.params['esm_class'] & 0x40) === 0x40) { + //This is a part of long sms. We should save UDH header information in params. + var hsize = parseInt("0x" + pdu.slice(offset, offset + paramSize).toString('hex').slice(0, 2)); + //If hsize is >5 then CSMS Reference consist of two parts + if(hsize == 5) { + var reference = parseInt("0x" + pdu.slice(offset, offset + paramSize).toString('hex').slice(6, 8)), + totalParts = parseInt("0x" + pdu.slice(offset, offset + paramSize).toString('hex').slice(8, 10)), + partNr = parseInt("0x" + pdu.slice(offset, offset + paramSize).toString('hex').slice(10, 12)); + } else { + var reference = (parseInt("0x" + pdu.slice(offset, offset + paramSize).toString('hex').slice(6, 8)) * 256) + parseInt("0x" + pdu.slice(offset, offset + paramSize).toString('hex').slice(8, 10)), + totalParts = parseInt("0x" + pdu.slice(offset, offset + paramSize).toString('hex').slice(10, 12)), + partNr = parseInt("0x" + pdu.slice(offset, offset + paramSize).toString('hex').slice(12, 14)); + } + var udhHeader = { + 'size': hsize, + 'reference': reference, + 'totalParts': totalParts, + 'partNr': partNr + } + retObj.params['udhHeader'] = udhHeader; + } // Check if we have a trailing NULL octet after the short_message. Some idiot thought that would be a good idea // in some implementations, so we need to account for that. if (stupidNullByte === true) { @@ -782,4 +802,4 @@ exports.pduReturn = pduReturn; exports.smppDate = smppDate; exports.bitCount = bitCount; exports.splitMsg = splitMsg; -exports.smsDlr = smsDlr; \ No newline at end of file +exports.smsDlr = smsDlr;