Added support for sending long messages via splitted short_message parameter
This commit is contained in:
@@ -3,3 +3,4 @@
|
|||||||
exports.server = require('./lib/server');
|
exports.server = require('./lib/server');
|
||||||
exports.client = require('./lib/client');
|
exports.client = require('./lib/client');
|
||||||
exports.utils = require('./lib/utils');
|
exports.utils = require('./lib/utils');
|
||||||
|
exports.defs = require('./lib/defs');
|
||||||
+69
-19
@@ -1,9 +1,9 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var log = require('winston'),
|
var log = require('winston'),
|
||||||
events = require('events'),
|
events = require('events'),
|
||||||
smppUtils = require('./utils'),
|
utils = require('./utils'),
|
||||||
defs = require('./defs');
|
defs = require('./defs');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generic session function
|
* Generic session function
|
||||||
@@ -57,7 +57,7 @@ function session(sock) {
|
|||||||
*/
|
*/
|
||||||
returnObj.sockWrite = function(pdu, closeAfterSend) {
|
returnObj.sockWrite = function(pdu, closeAfterSend) {
|
||||||
if ( ! Buffer.isBuffer(pdu)) {
|
if ( ! Buffer.isBuffer(pdu)) {
|
||||||
smppUtils.objToPdu(pdu, function(err, buffer) {
|
utils.objToPdu(pdu, function(err, buffer) {
|
||||||
if (err) {
|
if (err) {
|
||||||
log.warn('larvitsmpp: lib/session.js: session() - sockWrite() - Could not convert PDU to buffer');
|
log.warn('larvitsmpp: lib/session.js: session() - sockWrite() - Could not convert PDU to buffer');
|
||||||
returnObj.closeSocket();
|
returnObj.closeSocket();
|
||||||
@@ -96,7 +96,7 @@ function session(sock) {
|
|||||||
|
|
||||||
// Make sure the pdu is an object
|
// Make sure the pdu is an object
|
||||||
if (Buffer.isBuffer(pdu)) {
|
if (Buffer.isBuffer(pdu)) {
|
||||||
smppUtils.pduToObj(pdu, function(err, pduObj) {
|
utils.pduToObj(pdu, function(err, pduObj) {
|
||||||
if (err) {
|
if (err) {
|
||||||
callback(err);
|
callback(err);
|
||||||
return;
|
return;
|
||||||
@@ -180,7 +180,7 @@ function session(sock) {
|
|||||||
closeAfterSend = undefined;
|
closeAfterSend = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
smppUtils.pduReturn(pdu, status, params, function(err, retPdu) {
|
utils.pduReturn(pdu, status, params, function(err, retPdu) {
|
||||||
if (err) {
|
if (err) {
|
||||||
log.error('larvitsmpp: lib/session.js: session() - returnObj.sendReturn() - Could not create return PDU: ' + err.message);
|
log.error('larvitsmpp: lib/session.js: session() - returnObj.sendReturn() - Could not create return PDU: ' + err.message);
|
||||||
returnObj.closeSocket();
|
returnObj.closeSocket();
|
||||||
@@ -200,6 +200,53 @@ function session(sock) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a longer SMS than 1120 bits
|
||||||
|
*
|
||||||
|
* @param obj smsOptions
|
||||||
|
* from - alphanum or international format
|
||||||
|
* to - international format
|
||||||
|
* message - string
|
||||||
|
* dlr - boolean defaults to false
|
||||||
|
* @param func callback(err, smsId, retPduObj)
|
||||||
|
*/
|
||||||
|
returnObj.sendLongSms = function(smsOptions, callback) {
|
||||||
|
var msgs = utils.splitMsg(smsOptions.message),
|
||||||
|
encoding = defs.encodings.detect(smsOptions.message); // Set encoding once for all message parts
|
||||||
|
|
||||||
|
function sendPart(i) {
|
||||||
|
var pduObj = {
|
||||||
|
'cmdName': 'submit_sm',
|
||||||
|
'params': {
|
||||||
|
'source_addr_ton': 1, // Default to international format
|
||||||
|
'esm_class': 0x40, // This indicates that there is a UDH in the short_message
|
||||||
|
'source_addr': smsOptions.from,
|
||||||
|
'destination_addr': smsOptions.to,
|
||||||
|
'data_coding': defs.consts.ENCODING[encoding],
|
||||||
|
'short_message': msgs[i],
|
||||||
|
'sm_length': msgs[i].length
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Request DLRs!
|
||||||
|
if (smsOptions.dlr) {
|
||||||
|
pduObj.params.registered_delivery = 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug('larvitsmpp: lib/session.js: returnObj.sendLongSms() - pduObj: ' + JSON.stringify(pduObj));
|
||||||
|
|
||||||
|
returnObj.send(pduObj, function(err, retPduObj) {
|
||||||
|
if (typeof callback === 'function' && msgs[i + 1] === undefined) {
|
||||||
|
callback(err, retPduObj.params.message_id, retPduObj);
|
||||||
|
} else if (msgs[i + 1] !== undefined) {
|
||||||
|
sendPart(i + 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
sendPart(0);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send an SMS
|
* Send an SMS
|
||||||
*
|
*
|
||||||
@@ -215,6 +262,7 @@ function session(sock) {
|
|||||||
|
|
||||||
pduObj.cmdName = 'submit_sm';
|
pduObj.cmdName = 'submit_sm';
|
||||||
pduObj.params = {
|
pduObj.params = {
|
||||||
|
'source_addr_ton': 1, // Default to international format
|
||||||
'source_addr': smsOptions.from,
|
'source_addr': smsOptions.from,
|
||||||
'destination_addr': smsOptions.to,
|
'destination_addr': smsOptions.to,
|
||||||
'short_message': smsOptions.message
|
'short_message': smsOptions.message
|
||||||
@@ -225,6 +273,13 @@ function session(sock) {
|
|||||||
pduObj.params.registered_delivery = 0x01;
|
pduObj.params.registered_delivery = 0x01;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if we must split this message into multiple
|
||||||
|
if (utils.bitCount(smsOptions.message) > 1120) {
|
||||||
|
returnObj.sendLongSms(smsOptions, callback);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
log.debug('larvitsmpp: lib/session.js: returnObj.sendSms() - pduObj: ' + JSON.stringify(pduObj));
|
log.debug('larvitsmpp: lib/session.js: returnObj.sendSms() - pduObj: ' + JSON.stringify(pduObj));
|
||||||
|
|
||||||
returnObj.send(pduObj, function(err, retPduObj) {
|
returnObj.send(pduObj, function(err, retPduObj) {
|
||||||
@@ -243,7 +298,6 @@ function session(sock) {
|
|||||||
*/
|
*/
|
||||||
returnObj.sendDlr = function(sms, status, callback) {
|
returnObj.sendDlr = function(sms, status, callback) {
|
||||||
var shortMessage = 'id:' + sms.smsId + ' sub:001 ',
|
var shortMessage = 'id:' + sms.smsId + ' sub:001 ',
|
||||||
err,
|
|
||||||
dlrPduObj;
|
dlrPduObj;
|
||||||
|
|
||||||
if (typeof status === 'function') {
|
if (typeof status === 'function') {
|
||||||
@@ -261,8 +315,8 @@ function session(sock) {
|
|||||||
shortMessage += 'dlvrd:0 ';
|
shortMessage += 'dlvrd:0 ';
|
||||||
}
|
}
|
||||||
|
|
||||||
shortMessage += 'submit date:' + smppUtils.smppDate(sms.submitTime);
|
shortMessage += 'submit date:' + utils.smppDate(sms.submitTime);
|
||||||
shortMessage += ' done date:' + smppUtils.smppDate(new Date());
|
shortMessage += ' done date:' + utils.smppDate(new Date());
|
||||||
|
|
||||||
if (status) {
|
if (status) {
|
||||||
shortMessage += ' stat:DELIVRD err:0 text:xxx';
|
shortMessage += ' stat:DELIVRD err:0 text:xxx';
|
||||||
@@ -298,15 +352,12 @@ function session(sock) {
|
|||||||
|
|
||||||
dlrPduObj.seqNr = 323;
|
dlrPduObj.seqNr = 323;
|
||||||
|
|
||||||
console.log('before:');
|
utils.objToPdu(dlrPduObj, function(err, pdu) {
|
||||||
console.log(dlrPduObj);
|
|
||||||
|
|
||||||
smppUtils.objToPdu(dlrPduObj, function(err, pdu) {
|
|
||||||
if (err) {
|
if (err) {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
||||||
smppUtils.pduToObj(pdu, function(err, newObj) {
|
utils.pduToObj(pdu, function(err, newObj) {
|
||||||
if (err) {
|
if (err) {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
@@ -316,14 +367,13 @@ function session(sock) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return;
|
|
||||||
returnObj.send(dlrPduObj, function(err, retPduObj) {
|
returnObj.send(dlrPduObj, function(err, retPduObj) {
|
||||||
console.log('WHATTA WHATTA');
|
console.log('WHATTA WHATTA');
|
||||||
console.log(retPduObj);
|
console.log(retPduObj);
|
||||||
|
|
||||||
/*if (typeof callback === 'function') {
|
if (typeof callback === 'function') {
|
||||||
callback(err, retPduObj.params.message_id, retPduObj);
|
callback(err, retPduObj.params.message_id, retPduObj);
|
||||||
}*/
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -423,7 +473,7 @@ function session(sock) {
|
|||||||
|
|
||||||
log.silly('larvitsmpp: lib/session.js: session() - sock.on(data) - Incoming PDU: ' + pduBuf.toString('hex'));
|
log.silly('larvitsmpp: lib/session.js: session() - sock.on(data) - Incoming PDU: ' + pduBuf.toString('hex'));
|
||||||
|
|
||||||
smppUtils.pduToObj(pduBuf, function(err, pduObj) {
|
utils.pduToObj(pduBuf, function(err, pduObj) {
|
||||||
if (err) {
|
if (err) {
|
||||||
log.warn('larvitsmpp: lib/session.js: session() - Invalid PDU. ' + err.message);
|
log.warn('larvitsmpp: lib/session.js: session() - Invalid PDU. ' + err.message);
|
||||||
|
|
||||||
|
|||||||
+19
-16
@@ -73,6 +73,7 @@ function writeBuffer(obj, cmdLength, callback) {
|
|||||||
buff,
|
buff,
|
||||||
param,
|
param,
|
||||||
paramType,
|
paramType,
|
||||||
|
paramSize,
|
||||||
tlvId,
|
tlvId,
|
||||||
tlvName,
|
tlvName,
|
||||||
tlvValue,
|
tlvValue,
|
||||||
@@ -112,14 +113,19 @@ function writeBuffer(obj, cmdLength, callback) {
|
|||||||
// Cycle through the defs list to make sure the params are in the right order
|
// Cycle through the defs list to make sure the params are in the right order
|
||||||
for (param in defs.cmds[obj.cmdName].params) {
|
for (param in defs.cmds[obj.cmdName].params) {
|
||||||
paramType = defs.cmds[obj.cmdName].params[param].type;
|
paramType = defs.cmds[obj.cmdName].params[param].type;
|
||||||
|
paramSize = paramType.size(obj.params[param]);
|
||||||
|
|
||||||
// Write parameter value to buffer using the types method write()
|
// Write parameter value to buffer using the types method write()
|
||||||
paramType.write(obj.params[param], buff, offset);
|
paramType.write(obj.params[param], buff, offset);
|
||||||
|
|
||||||
log.silly('larvitsmpp: lib/utils.js: writeBuffer() - Writing param "' + param + '" with content "' + obj.params[param] + '"');
|
if (Buffer.isBuffer(obj.params[param])) {
|
||||||
|
log.silly('larvitsmpp: lib/utils.js: writeBuffer() - Writing param "' + param + '" with content "' + obj.params[param].toString('hex') + '" and size "' + paramSize + '"');
|
||||||
|
} else {
|
||||||
|
log.silly('larvitsmpp: lib/utils.js: writeBuffer() - Writing param "' + param + '" with content "' + obj.params[param] + '"');
|
||||||
|
}
|
||||||
|
|
||||||
// Increase the offset for the next param
|
// Increase the offset for the next param
|
||||||
offset += paramType.size(obj.params[param]);
|
offset += paramSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cycle through the tlvs
|
// Cycle through the tlvs
|
||||||
@@ -143,6 +149,8 @@ function writeBuffer(obj, cmdLength, callback) {
|
|||||||
offset += tlvDef.type.size(tlvValue) + 4;
|
offset += tlvDef.type.size(tlvValue) + 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.silly('larvitsmpp: lib/utils.js: writeBuffer() - Complete PDU: "' + buff.toString('hex') + '"');
|
||||||
|
|
||||||
callback(null, buff);
|
callback(null, buff);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,7 +263,6 @@ function pduToObj(pdu, stupidNullByte, callback) {
|
|||||||
if (param === 'short_message') {
|
if (param === 'short_message') {
|
||||||
// Check if we have a trailing NULL octet after the short_message. Some idiot thought that would be a good idea
|
// 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.
|
// in some implementations, so we need to account for that.
|
||||||
|
|
||||||
if (stupidNullByte === true) {
|
if (stupidNullByte === true) {
|
||||||
log.silly('larvitsmpp: lib/utils.js: pduToObj() - stupidNullByte is set, so short_message is followed by a NULL octet, increase paramSize one extra to account for that');
|
log.silly('larvitsmpp: lib/utils.js: pduToObj() - stupidNullByte is set, so short_message is followed by a NULL octet, increase paramSize one extra to account for that');
|
||||||
paramSize ++;
|
paramSize ++;
|
||||||
@@ -326,8 +333,10 @@ function pduToObj(pdu, stupidNullByte, callback) {
|
|||||||
log.warn('larvitsmpp: lib/utils.js: pduToObj() - Offset (' + offset + ') !== cmdLength (' + retObj.cmdLength + ') for seqNr: ' + retObj.seqNr);
|
log.warn('larvitsmpp: lib/utils.js: pduToObj() - Offset (' + offset + ') !== cmdLength (' + retObj.cmdLength + ') for seqNr: ' + retObj.seqNr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode the short message if it is set
|
// Decode the short message if it is set and esm_class is 0
|
||||||
if (retObj.params.short_message !== undefined) {
|
// The esm_class 0x40 (64 int) means the short_message have a UDH
|
||||||
|
// Thats why we return the short_message as a buffer
|
||||||
|
if (retObj.params.short_message !== undefined && retObj.params.esm_class !== 0x40) {
|
||||||
retObj.params.short_message = decodeMsg(retObj.params.short_message, retObj.params.data_coding);
|
retObj.params.short_message = decodeMsg(retObj.params.short_message, retObj.params.data_coding);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -395,6 +404,7 @@ function objToPdu(obj, callback) {
|
|||||||
// Acutally encode the string
|
// Acutally encode the string
|
||||||
shortMsg = obj.params.short_message;
|
shortMsg = obj.params.short_message;
|
||||||
obj.params.short_message = encodeMsg(obj.params.short_message);
|
obj.params.short_message = encodeMsg(obj.params.short_message);
|
||||||
|
|
||||||
obj.params.sm_length = obj.params.short_message.length;
|
obj.params.sm_length = obj.params.short_message.length;
|
||||||
log.silly('larvitsmpp: lib/utils.js: objToPdu() - encoding message "' + shortMsg + '" to "' + obj.params.short_message.toString('hex') + '"');
|
log.silly('larvitsmpp: lib/utils.js: objToPdu() - encoding message "' + shortMsg + '" to "' + obj.params.short_message.toString('hex') + '"');
|
||||||
}
|
}
|
||||||
@@ -571,20 +581,13 @@ function bitCount(msg, encoding) {
|
|||||||
* @return array of buffers
|
* @return array of buffers
|
||||||
*/
|
*/
|
||||||
function splitMsg(msg) {
|
function splitMsg(msg) {
|
||||||
var msgPart = '',
|
var msgPart = '',
|
||||||
msgs = [],
|
msgs = [],
|
||||||
msgId = Math.floor(Math.random() * (255 - 0)), // This will identify this message "bundle"
|
msgId = Math.floor(Math.random() * (255 - 0)), // This will identify this message "bundle"
|
||||||
encoding,
|
encoding = defs.encodings.detect(msg),
|
||||||
udh,
|
udh,
|
||||||
i;
|
i;
|
||||||
|
|
||||||
// Build a buffer from the correct encoding
|
|
||||||
if (defs.encodings.ASCII.match(msg)) {
|
|
||||||
encoding = 'ASCII';
|
|
||||||
} else {
|
|
||||||
encoding = 'UCS2';
|
|
||||||
}
|
|
||||||
|
|
||||||
// A single message could contain up to 1120 bits
|
// A single message could contain up to 1120 bits
|
||||||
// Return directly if the message fits into that
|
// Return directly if the message fits into that
|
||||||
if (bitCount(msg) < 1121) {
|
if (bitCount(msg) < 1121) {
|
||||||
|
|||||||
@@ -142,6 +142,38 @@ describe('PDU convertion', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should create a submit_sm PDU with esm_class 0x40 and a short_message with UDH in it', function(done) {
|
||||||
|
var msg = 'hej världen',
|
||||||
|
msgBuf = Buffer.concat([new Buffer('050003010101', 'hex'), new Buffer(msg)]),
|
||||||
|
encoding = larvitsmpp.defs.encodings.detect(msg);
|
||||||
|
|
||||||
|
larvitsmpp.utils.objToPdu({
|
||||||
|
'cmdName': 'submit_sm',
|
||||||
|
'cmdStatus': 'ESME_ROK',
|
||||||
|
'seqNr': 12,
|
||||||
|
'params': {
|
||||||
|
'esm_class': 0x40,
|
||||||
|
'source_addr': '46701113311',
|
||||||
|
'destination_addr': '46709771337',
|
||||||
|
'sm_length': msgBuf.length,
|
||||||
|
'data_coding': larvitsmpp.defs.consts.ENCODING[encoding],
|
||||||
|
'short_message': msgBuf
|
||||||
|
}
|
||||||
|
}, function(err, pdu) {
|
||||||
|
assert( ! err, 'Error should be negative');
|
||||||
|
|
||||||
|
larvitsmpp.utils.pduToObj(pdu, function(err, retObj) {
|
||||||
|
assert( ! err, 'Error should be negative');
|
||||||
|
|
||||||
|
assert(retObj.params.short_message.toString('hex') === '05000301010168656a2076c3a4726c64656e', 'short_message should be correct');
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should encode and decode integer cstring params correctly', function(done) {
|
it('should encode and decode integer cstring params correctly', function(done) {
|
||||||
var pduObj = {
|
var pduObj = {
|
||||||
'cmdName': 'submit_sm_resp',
|
'cmdName': 'submit_sm_resp',
|
||||||
|
|||||||
Reference in New Issue
Block a user