Monstrous amount of changes. Bad commit disciplin.
This commit is contained in:
+272
-96
@@ -2,8 +2,167 @@
|
||||
|
||||
var log = require('winston'),
|
||||
events = require('events'),
|
||||
moment = require('moment'),
|
||||
utils = require('./utils'),
|
||||
defs = require('./defs');
|
||||
defs = require('./defs'),
|
||||
async = require('async');
|
||||
|
||||
/*
|
||||
* Send a response to an sms
|
||||
* This must be called from an sms object context
|
||||
*
|
||||
* @param str status - see list at defs.errors - defaults to 'ESME_ROK' - no error (OPTIONAL)
|
||||
* @param func callback(err, [retPdu, ...])
|
||||
*/
|
||||
function smsResp(status, callback) {
|
||||
var sms = this,
|
||||
err,
|
||||
i,
|
||||
tasks = [];
|
||||
|
||||
if (typeof status === 'function') {
|
||||
callback = status;
|
||||
status = true;
|
||||
}
|
||||
|
||||
if (typeof callback !== 'function') {
|
||||
callback = function() {};
|
||||
}
|
||||
|
||||
if (sms.smsId === undefined) {
|
||||
sms.smsId = '';
|
||||
}
|
||||
|
||||
// Accept a generic positive status
|
||||
if (status === 'true' || status === true || status === 0) {
|
||||
status = 'ESME_ROK';
|
||||
}
|
||||
|
||||
// Accept a generic negative status
|
||||
if (status === 'false' || status === false || status === 1) {
|
||||
status = 'ESME_RUNKNOWNERR'; // Set to unknown error in this case
|
||||
}
|
||||
|
||||
if (sms.pduObjs === undefined && sms.pduObj === undefined) {
|
||||
err = new Error('No pdu objects found to base return PDU upon');
|
||||
log.warn('larvitsmpp: lib/session.js: smsResp() - ' + err.message);
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sms.pduObjs === undefined) {
|
||||
sms.pduObjs = [sms.pduObjs];
|
||||
}
|
||||
|
||||
// Build async tasks to run the responses in parallel
|
||||
i = 0;
|
||||
while (sms.pduObjs[i] !== undefined) {
|
||||
|
||||
|
||||
tasks.push(function(callback) {
|
||||
sms.session.sendReturn(
|
||||
sms.pduObj,
|
||||
status,
|
||||
{'message_id': sms.smsId},
|
||||
false,
|
||||
callback
|
||||
);
|
||||
});
|
||||
|
||||
i ++;
|
||||
}
|
||||
|
||||
|
||||
sms.session.sendReturn(
|
||||
sms.pduObj,
|
||||
status,
|
||||
{'message_id': sms.smsId},
|
||||
false,
|
||||
callback
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a dlr to an sms
|
||||
* This must be called from an sms object context
|
||||
*
|
||||
* @param str status - see list at defs.consts.MESSAGE_STATE - defaults to 'DELIVERED'
|
||||
* @param func callback(err, retPdu)
|
||||
*/
|
||||
function smsDlr(status, callback) {
|
||||
var shortMessage,
|
||||
dlrPduObj,
|
||||
err,
|
||||
sms = this;
|
||||
|
||||
if (typeof status === 'function') {
|
||||
callback = status;
|
||||
status = undefined;
|
||||
}
|
||||
|
||||
if (status === undefined || status === true || status === 2 || status === 'true') {
|
||||
status = 2;
|
||||
} else if (defs.consts.MESSAGE_STATE[status] !== undefined) {
|
||||
status = defs.consts.MESSAGE_STATE[status];
|
||||
} else if (defs.constsById.MESSAGE_STATE[status]) {
|
||||
status = parseInt(status);
|
||||
} else {
|
||||
status = 5; // UNDELIVERABLE
|
||||
}
|
||||
|
||||
if (typeof callback !== 'function') {
|
||||
callback = function() {};
|
||||
}
|
||||
|
||||
if (sms.smsId === undefined) {
|
||||
err = new Error('Trying to send DLR with no smsId.');
|
||||
log.warn('larvitsmpp: lib/session.js: smsDlr() - ' + err.message);
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
shortMessage = 'id:' + sms.smsId + ' sub:001 ';
|
||||
|
||||
if (status === 2) {
|
||||
shortMessage += 'dlvrd:1 ';
|
||||
} else {
|
||||
shortMessage += 'dlvrd:0 ';
|
||||
}
|
||||
|
||||
shortMessage += 'submit date:' + utils.smppDate(sms.submitTime);
|
||||
shortMessage += ' done date:' + utils.smppDate(new Date());
|
||||
|
||||
if (status === 2) {
|
||||
shortMessage += ' stat:DELIVRD err:0 text:xxx';
|
||||
} else {
|
||||
shortMessage += ' stat:UNDELIVERABLE err:1 text:xxx';
|
||||
}
|
||||
|
||||
dlrPduObj = {
|
||||
'cmdName': 'deliver_sm',
|
||||
'params': {
|
||||
'source_addr': sms.from,
|
||||
'destination_addr': sms.to,
|
||||
'esm_class': 4,
|
||||
'short_message': shortMessage
|
||||
},
|
||||
'tlvs': {
|
||||
'receipted_message_id': {
|
||||
'tagId': 0x001E,
|
||||
'tagName': 'receipted_message_id',
|
||||
'tagValue': sms.smsId
|
||||
},
|
||||
'message_state': {
|
||||
'tagId': 0x0427,
|
||||
'tagName': 'message_state',
|
||||
'tagValue': status
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
sms.session.send(dlrPduObj, false, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic session function
|
||||
@@ -136,14 +295,14 @@ function session(sock) {
|
||||
log.debug('larvitsmpp: lib/session.js: session() - returnObj.send() - returnObj.on(incomingPduObj) - cmdName: ' + incPduObj.cmdName + ' seqNr: ' + incPduObj.seqNr + ' cmdStatus: ' + incPduObj.cmdStatus);
|
||||
|
||||
// Make sure this is the actual response to the sent PDU
|
||||
if (incPduObj.isResponse() && incPduObj.seqNr === pduObj.seqNr) {
|
||||
if (incPduObj.isResp() && incPduObj.seqNr === pduObj.seqNr) {
|
||||
callback(null, incPduObj);
|
||||
|
||||
if (closeAfterSend) {
|
||||
returnObj.closeSocket();
|
||||
}
|
||||
} else {
|
||||
err = new Error('larvitsmpp: lib/session.js: session() - returnObj.send() - returnObj.on(incomingPduObj) - Event triggered but incoming PDU is not a response or seqNr does not match. isResponse: ' + incPduObj.isResponse().toString() + ' incSeqNr: ' + incPduObj.seqNr + ' expected seqNr: ' + pduObj.seqNr);
|
||||
err = new Error('larvitsmpp: lib/session.js: session() - returnObj.send() - returnObj.on(incomingPduObj) - Event triggered but incoming PDU is not a response or seqNr does not match. isResp: ' + incPduObj.isResp().toString() + ' incSeqNr: ' + incPduObj.seqNr + ' expected seqNr: ' + pduObj.seqNr);
|
||||
log.warn(err.message);
|
||||
callback(err);
|
||||
}
|
||||
@@ -189,6 +348,8 @@ function session(sock) {
|
||||
return;
|
||||
}
|
||||
|
||||
log.silly('larvitsmpp: lib/session.js: session() - returnObj.sendReturn() - Sending return PDU: ' + retPdu.toString('hex'));
|
||||
|
||||
returnObj.sockWrite(retPdu, closeAfterSend);
|
||||
|
||||
if (typeof callback === 'function') {
|
||||
@@ -208,7 +369,8 @@ function session(sock) {
|
||||
* @param func callback(err, smsId, retPduObj)
|
||||
*/
|
||||
returnObj.sendLongSms = function(smsOptions, callback) {
|
||||
var msgs = utils.splitMsg(smsOptions.message),
|
||||
var smsIds = [],
|
||||
msgs = utils.splitMsg(smsOptions.message),
|
||||
encoding = defs.encodings.detect(smsOptions.message); // Set encoding once for all message parts
|
||||
|
||||
function sendPart(i) {
|
||||
@@ -233,8 +395,10 @@ function session(sock) {
|
||||
log.debug('larvitsmpp: lib/session.js: returnObj.sendLongSms() - pduObj: ' + JSON.stringify(pduObj));
|
||||
|
||||
returnObj.send(pduObj, function(err, retPduObj) {
|
||||
smsIds.push(retPduObj.params.message_id);
|
||||
|
||||
if (typeof callback === 'function' && msgs[i + 1] === undefined) {
|
||||
callback(err, retPduObj.params.message_id, retPduObj);
|
||||
callback(err, smsIds, retPduObj);
|
||||
} else if (msgs[i + 1] !== undefined) {
|
||||
sendPart(i + 1);
|
||||
}
|
||||
@@ -281,97 +445,106 @@ function session(sock) {
|
||||
|
||||
returnObj.send(pduObj, function(err, retPduObj) {
|
||||
if (typeof callback === 'function') {
|
||||
callback(err, retPduObj.params.message_id, retPduObj);
|
||||
callback(err, [retPduObj.params.message_id], retPduObj);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Send a DLR
|
||||
*
|
||||
* @param obj sms - sms object
|
||||
* @param bol status - defaults to true
|
||||
* @param func callback(err)
|
||||
*/
|
||||
returnObj.sendDlr = function(sms, status, callback) {
|
||||
var shortMessage = 'id:' + sms.smsId + ' sub:001 ',
|
||||
dlrPduObj;
|
||||
// Temporary storage for long sms parts
|
||||
// These should be cleared if they lingre to long to avoid memory leaks
|
||||
returnObj.longSmses = {};
|
||||
|
||||
if (typeof status === 'function') {
|
||||
callback = status;
|
||||
status = true;
|
||||
}
|
||||
// Store long smses in the temporary storage
|
||||
returnObj.longSms = function(pduObj) {
|
||||
var smsGroupId = pduObj.params.short_message[3],
|
||||
smsParts = pduObj.params.short_message[4],
|
||||
longSmsId = pduObj.params.source_addr + '_' + pduObj.params.destination_addr + '_' + smsGroupId;
|
||||
|
||||
if (status === undefined) {
|
||||
status = true;
|
||||
}
|
||||
|
||||
if (status) {
|
||||
shortMessage += 'dlvrd:1 ';
|
||||
if (returnObj.longSmses[longSmsId] === undefined) {
|
||||
returnObj.longSmses[longSmsId] = {
|
||||
'created': new Date(),
|
||||
'partsCount': parseInt(smsParts),
|
||||
'pduObjs': [{
|
||||
'partNr': pduObj.params.short_message[5], // We save this here to easier sort the array later on
|
||||
'pduObj': pduObj
|
||||
}]
|
||||
};
|
||||
} else {
|
||||
shortMessage += 'dlvrd:0 ';
|
||||
returnObj.longSmses[longSmsId].pduObjs.push(pduObj);
|
||||
}
|
||||
};
|
||||
|
||||
shortMessage += 'submit date:' + utils.smppDate(sms.submitTime);
|
||||
shortMessage += ' done date:' + utils.smppDate(new Date());
|
||||
// Walk through the long sms storage to investigate if we can send complete messages along
|
||||
// or should remove old ones
|
||||
returnObj.checkLongSmses = function() {
|
||||
var smsGroupId,
|
||||
smsGroup,
|
||||
smsObj,
|
||||
i,
|
||||
curPduObj;
|
||||
|
||||
if (status) {
|
||||
shortMessage += ' stat:DELIVRD err:0 text:xxx';
|
||||
} else {
|
||||
shortMessage += ' stat:UNDELIVERABLE err:1 text:xxx';
|
||||
}
|
||||
|
||||
dlrPduObj = {
|
||||
'cmdName': 'deliver_sm',
|
||||
'params': {
|
||||
'source_addr': sms.from,
|
||||
'destination_addr': sms.to,
|
||||
'esm_class': 4,
|
||||
'short_message': shortMessage
|
||||
},
|
||||
'tlvs': {
|
||||
'receipted_message_id': {
|
||||
'tagId': 0x001E,
|
||||
'tagName': 'receipted_message_id',
|
||||
'tagValue': sms.smsId
|
||||
},
|
||||
'message_state': {
|
||||
'tagId': 0x0427,
|
||||
'tagName': 'message_state',
|
||||
'tagValue': 2
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if ( ! status) {
|
||||
dlrPduObj.tlvs.message_state.tagValue = 5;
|
||||
}
|
||||
|
||||
dlrPduObj.seqNr = 323;
|
||||
|
||||
utils.objToPdu(dlrPduObj, function(err, pdu) {
|
||||
if (err) {
|
||||
throw err;
|
||||
// Sort function to sort group parts
|
||||
function sortLongSmsPdus(a, b) {
|
||||
if (a.partNr < b.partNr) {
|
||||
return - 1;
|
||||
}
|
||||
|
||||
utils.pduToObj(pdu, function(err, newObj) {
|
||||
if (err) {
|
||||
throw err;
|
||||
if (a.partNr > b.partNr) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Callback function for emitted sms event
|
||||
function smsReceived(smsData) {
|
||||
delete returnObj.longSmses[smsGroupId];
|
||||
}
|
||||
|
||||
for (smsGroupId in returnObj.longSmses) {
|
||||
smsGroup = returnObj.longSmses[smsGroupId];
|
||||
|
||||
// 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: session() - returnObj.checkLongSmses() - All parts accounted for in smsGroupId "' + smsGroupId + '", emitting sms event.');
|
||||
|
||||
smsObj = {
|
||||
|
||||
// These are needed for references here and there in functions
|
||||
'session': returnObj,
|
||||
'pduObjs': smsGroup.pduObjs,
|
||||
|
||||
'from': smsGroup.pduObjs[0].params.source_addr,
|
||||
'to': smsGroup.pduObjs[0].params.destination_addr,
|
||||
'submitTime': new Date(),
|
||||
'message': '',
|
||||
'dlr': Boolean(smsGroup.pduObjs[0].params.registered_delivery),
|
||||
'sendResp': smsResp,
|
||||
'sendDlr': smsDlr
|
||||
};
|
||||
|
||||
// Concatenate all the parts messages to one and set references to the session
|
||||
|
||||
// First we need to sort the parts, since they can come in random order
|
||||
smsObj.pduObjs.sort(sortLongSmsPdus);
|
||||
|
||||
i = 0;
|
||||
while (smsObj.pduObjs[i] !== undefined) {
|
||||
curPduObj = smsObj.pduObjs[i];
|
||||
curPduObj.session = returnObj;
|
||||
|
||||
smsObj.message += utils.decode(curPduObj.params.short_message, curPduObj.params.data_coding, curPduObj.params.short_message[0]);
|
||||
|
||||
i ++;
|
||||
}
|
||||
|
||||
console.log('newObj:');
|
||||
console.log(newObj);
|
||||
});
|
||||
});
|
||||
returnObj.emit('sms', smsObj);
|
||||
} else if (moment(new Date()).diff(smsGroup.created, 'hours') > 24) {
|
||||
log.info('larvitsmpp: lib/session.js: session() - returnObj.checkLongSmses() - smsGroupId "' + smsGroupId + '" is removed from returnObj.longSmses due to being older than 24 hours.');
|
||||
|
||||
returnObj.send(dlrPduObj, function(err, retPduObj) {
|
||||
console.log('WHATTA WHATTA');
|
||||
console.log(retPduObj);
|
||||
|
||||
if (typeof callback === 'function') {
|
||||
callback(err, retPduObj.params.message_id, retPduObj);
|
||||
delete returnObj.longSmses[smsGroupId];
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Handle incomming commands.
|
||||
@@ -384,7 +557,7 @@ function session(sock) {
|
||||
|
||||
// TLV message_state must exists
|
||||
if (pduObj.tlvs.message_state === undefined) {
|
||||
log.info('larvitsmpp: lib/session.js: session() - returnObj.deliverSm() - TLV message_state is missing. SeqNr: ' + pduObj.seqNr);
|
||||
log.info('larvitsmpp: lib/session.js: session() - returnObj.handleCmd.deliver_sm() - TLV message_state is missing. SeqNr: ' + pduObj.seqNr);
|
||||
returnObj.sendReturn(pduObj, 'ESME_RINVTLVSTREAM');
|
||||
|
||||
return;
|
||||
@@ -392,7 +565,7 @@ function session(sock) {
|
||||
|
||||
// TLV message_state needs to be valid
|
||||
if (defs.constsById.MESSAGE_STATE[pduObj.tlvs.message_state.tagValue] === undefined) {
|
||||
log.info('larvitsmpp: lib/session.js: session() - returnObj.deliverSm() - Invalid TLV message_state: "' + pduObj.tlvs.message_state.tagValue + '". SeqNr: ' + pduObj.seqNr);
|
||||
log.info('larvitsmpp: lib/session.js: session() - returnObj.handleCmd.deliver_sm() - Invalid TLV message_state: "' + pduObj.tlvs.message_state.tagValue + '". SeqNr: ' + pduObj.seqNr);
|
||||
returnObj.sendReturn(pduObj, 'ESME_RINVTLVSTREAM');
|
||||
|
||||
return;
|
||||
@@ -400,7 +573,7 @@ function session(sock) {
|
||||
|
||||
// TLV receipted_message_id must exist
|
||||
if (pduObj.tlvs.receipted_message_id === undefined) {
|
||||
log.info('larvitsmpp: lib/session.js: session() - returnObj.deliverSm() - TLV receipted_message_id is missing. SeqNr: ' + pduObj.seqNr);
|
||||
log.info('larvitsmpp: lib/session.js: session() - returnObj.handleCmd.deliver_sm() - TLV receipted_message_id is missing. SeqNr: ' + pduObj.seqNr);
|
||||
returnObj.sendReturn(pduObj, 'ESME_RINVTLVSTREAM');
|
||||
|
||||
return;
|
||||
@@ -427,25 +600,28 @@ function session(sock) {
|
||||
returnObj.handleCmd.submit_sm = function(pduObj) {
|
||||
var smsObj = {};
|
||||
|
||||
// If esm_class is 0x40 it means this is just a part of a larger message
|
||||
if (pduObj.params.esm_class === 0x40) {
|
||||
returnObj.longSms(pduObj);
|
||||
return; // Long messages should not get handled here at all, so cancel execution here
|
||||
}
|
||||
|
||||
smsObj = {
|
||||
|
||||
// These are needed for references here and there in functions
|
||||
'session': returnObj,
|
||||
'pduObj': pduObj,
|
||||
|
||||
'from': pduObj.params.source_addr,
|
||||
'to': pduObj.params.destination_addr,
|
||||
'submitTime': new Date(),
|
||||
'message': pduObj.params.short_message,
|
||||
'dlr': Boolean(pduObj.params.registered_delivery)
|
||||
'dlr': Boolean(pduObj.params.registered_delivery),
|
||||
'sendResp': smsResp,
|
||||
'sendDlr': smsDlr
|
||||
};
|
||||
|
||||
function smsReceived(smsData) {
|
||||
if (smsData === undefined) {
|
||||
smsData = {};
|
||||
}
|
||||
|
||||
smsObj.smsId = smsData.smsId;
|
||||
|
||||
returnObj.sendReturn(pduObj, 'ESME_ROK', {'message_id': smsObj.smsId});
|
||||
}
|
||||
|
||||
returnObj.emit('sms', smsObj, smsReceived);
|
||||
returnObj.emit('sms', smsObj);
|
||||
};
|
||||
|
||||
// Handle incoming unbind
|
||||
@@ -534,7 +710,7 @@ function session(sock) {
|
||||
} else {
|
||||
log.verbose('larvitsmpp: lib/session.js: session() - returnObj.on(incomingPdu) - Incoming PDU parsed. Seqnr: ' + pduObj.seqNr + ' cmd: ' + pduObj.cmdName + ' cmdStatus: ' + pduObj.cmdStatus + ' hex: ' + pdu.toString('hex'));
|
||||
|
||||
if (pduObj.isResponse()) {
|
||||
if (pduObj.isResp()) {
|
||||
// We do this so we can remove the dynamic event listeners to not have a memory leak
|
||||
returnObj.emit('incomingPduObj' + pduObj.seqNr, pduObj);
|
||||
|
||||
|
||||
+8
-3
@@ -159,11 +159,16 @@ function writeBuffer(obj, cmdLength, callback) {
|
||||
*
|
||||
* @param buf buffer
|
||||
* @param str encoding 'ASCII', 'LATIN1' or 'UCS2' or hex values
|
||||
* @param int offset - defaults to 0
|
||||
* @return str in utf8 format
|
||||
*/
|
||||
function decodeMsg(buffer, encoding) {
|
||||
function decodeMsg(buffer, encoding, offset) {
|
||||
var checkEnc;
|
||||
|
||||
if (offset === undefined) {
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
for (checkEnc in defs.consts.ENCODING) {
|
||||
if (parseInt(encoding) === defs.consts.ENCODING[checkEnc] || encoding === checkEnc) {
|
||||
encoding = checkEnc;
|
||||
@@ -175,7 +180,7 @@ function decodeMsg(buffer, encoding) {
|
||||
encoding = 'ASCII';
|
||||
}
|
||||
|
||||
return defs.encodings[encoding].decode(buffer);
|
||||
return defs.encodings[encoding].decode(buffer.slice(offset, buffer.length));
|
||||
}
|
||||
|
||||
function encodeMsg(str) {
|
||||
@@ -208,7 +213,7 @@ function pduToObj(pdu, stupidNullByte, callback) {
|
||||
}
|
||||
|
||||
// Returns true if this PDU is a response to another PDU
|
||||
retObj.isResponse = function() {
|
||||
retObj.isResp = function() {
|
||||
return ! ! (this.cmdId & 0x80000000);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user