diff --git a/lib/utils.js b/lib/utils.js index 47ce58e..4da737e 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -527,10 +527,99 @@ function smppDate(jsDateObj) { return uglyStr; } +/** + * Calculate bitCount of short_message + * + * @param str msg + * @param str encoding - Force encoding ASCII or UCS2 (OPTIONAL) + * @return integer + */ +function bitCount(msg, encoding) { + if (encoding === 'ASCII' || defs.encodings.ASCII.match(msg)) { + return defs.encodings.ASCII.encode(msg).length * 7; // * 7 since each character takes up 7 bits + } else { + return defs.encodings.UCS2.encode(msg).length * 8; // * 8 since its encoded as 16-bits. + } +} + +/** + * Split a message into multiple messages + * + * @param str msg + * @return array of buffers + */ +function splitMsg(msg) { + var msgPart = '', + msgs = [], + msgId = Math.floor(Math.random() * (255 - 0)), // This will identify this message "bundle" + encoding, + udh, + 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 + // Return directly if the message fits into that + if (bitCount(msg) < 1121) { + return [defs.encodings[encoding].encode(msg)]; + } + + i = 0; + while (msg[i] !== undefined) { + msgPart += msg[i]; + + if (bitCount(msgPart, encoding) > 1072) { + // We've reached the message limit + + // Add this msgPart minus the last character to the msgs array as an encoded buffer + msgs.push(defs.encodings[encoding].encode(msgPart.slice(0, - 1))); + + // Reset msgPart + msgPart = ''; + + // Put i back one to account for the last character we removed from the msgPart + i --; + } + + i ++; + } + + // Add the last msgPart to the msgs array + msgs.push(defs.encodings[encoding].encode(msgPart)); + + // Add the UDH (http://en.wikipedia.org/wiki/Concatenated_SMS) + i = 0; + while (msgs[i] !== undefined) { + + // Create the UDH buffer + udh = new Buffer([ + 0x05, // Length of User Data Header, in this case 05. + 0x00, // Information Element Identifier, equal to 00 (Concatenated short messages, 8-bit reference number) + 0x03, // Length of the header, excluding the first two fields; equal to 03 + msgId, // CSMS reference number, must be same for all the SMS parts in the CSMS + msgs.length, // Total number of parts. The value shall remain constant for every short message which makes up the concatenated short message. If the value is zero then the receiving entity shall ignore the whole information element + i + 1 // This part's number in the sequence. The value shall start at 1 and increment for every short message which makes up the concatenated short message. + ]); + + msgs[i] = Buffer.concat([udh, msgs[i]]); + + i ++; + } + + return msgs; +} + // Expose some functions exports.decodeMsg = decodeMsg; exports.encodeMsg = encodeMsg; exports.pduToObj = pduToObj; exports.objToPdu = objToPdu; exports.pduReturn = pduReturn; -exports.smppDate = smppDate; \ No newline at end of file +exports.smppDate = smppDate; +exports.bitCount = bitCount; +exports.splitMsg = splitMsg; \ No newline at end of file diff --git a/test/03_pdu.js b/test/03_pdu.js index 3e737a2..b74ac6d 100644 --- a/test/03_pdu.js +++ b/test/03_pdu.js @@ -204,7 +204,6 @@ describe('PDU convertion', function() { }); describe('Return PDUs', function() { - it('should create a basic and valid return PDU', function(done) { var pduObj = { 'cmdName': 'deliver_sm', @@ -286,7 +285,44 @@ describe('PDU convertion', function() { }); }); }); + }); + describe('Message size and split', function() { + it('should calculate sizes of msgs', function(done) { + var a = 'abcd', + b = 'abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcd', + c = 'Ledds med « df BLAH och därför är alla hjul runda fast bara några hihi', + d = 'abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdHIHIHIHI foobar', + e = 'Ledds med « df BLAH och därför är alla hjul runda fast bara några hihi Ledds med « df BLAH och därför är alla hjul runda fast bara några hihi Ledds med « df BLAH och därför är alla hjul runda fast bara några hihi Ledds med « df BLAH och därför är alla hjul runda fast bara några hihi', + f = 'abcd€abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcd', + g = 'Ledds med « df BLAH och därför är alla hjul runda fast bara några hihi bara lite längre'; + + assert(larvitsmpp.utils.bitCount(a) === 28, 'ASCII'); + assert(larvitsmpp.utils.bitCount(b) === 1120, 'ASCII'); + assert(larvitsmpp.utils.bitCount(c) === 1120, 'UCS2'); + assert(larvitsmpp.utils.bitCount(d) === 1225, 'ASCII'); + assert(larvitsmpp.utils.bitCount(e) === 4528, 'UCS2'); + assert(larvitsmpp.utils.bitCount(f) === 1120, 'ASCII with special char'); + assert(larvitsmpp.utils.bitCount(g) === 1392, 'UCS2'); + + assert(larvitsmpp.utils.splitMsg(a).length === 1); + assert(larvitsmpp.utils.splitMsg(b).length === 1); + assert(larvitsmpp.utils.splitMsg(c).length === 1); + assert(larvitsmpp.utils.splitMsg(d).length === 2); + assert(larvitsmpp.utils.splitMsg(e).length === 5); + assert(larvitsmpp.utils.splitMsg(f).length === 1); + assert(larvitsmpp.utils.splitMsg(g).length === 2); + + done(); + }); + + it('should return an array with a buffer equalling the input msg', function(done) { + var msg = 'hello world', + msgs = larvitsmpp.utils.splitMsg(msg); + + assert(msgs[0].toString() === msg, 'Messages should equal'); + done(); + }); }); }); \ No newline at end of file