diff --git a/README.md b/README.md index ead2ea0..d0e1511 100644 --- a/README.md +++ b/README.md @@ -117,27 +117,11 @@ Example code below: }); // Oh, the sms sender wants a dlr (delivery report), send it! - if (sms.dlr === true) { - serverSession.sendDlr({ - 'smsId': 450, - 'status': 2 + if (sms.dlrRequested === true) { + serverSession.sendDlr(sms); - /* - * All available dlr status codes: - * - * 0 SCHEDULED The message is scheduled for later sending. - * 1 ENROUTE The message is enroute. - * 2 DELIVERED The message was successfully delivered. - * 3 EXPIRED The SMSC was unable to deliver the message in a specified amount of time.For instance when the phone was turned off. - * 4 DELETED The message was deleted. - * 5 UNDELIVERABLE The SMS was unable to deliver the message.For instance, when the number does not exist. - * 6 ACCEPTED The SMS was accepted and will be send. - * 7 UNKNOWN Unknown error occured. - * 8 REJECTED The message was rejected.The provider could have blocked phonenumbers in this range. - * 9 SKIPPED The message was skipped. - */ - - }); + // To send a negative delivery report do: + //serverSession.sendDlr(sms, false); } }); }); diff --git a/lib/session.js b/lib/session.js index 74071c7..7a100f2 100644 --- a/lib/session.js +++ b/lib/session.js @@ -94,11 +94,6 @@ function session(sock) { var pduObj = pdu, err = null; - // Make sure the sequence number is set and is correct - if ( ! Buffer.isBuffer(pdu)) { - pdu.seqNr = returnObj.ourSeqNr; - } - // Make sure the pdu is an object if (Buffer.isBuffer(pdu)) { smppUtils.pduToObj(pdu, function(err, pduObj) { @@ -112,7 +107,10 @@ function session(sock) { return; } - log.debug('larvitsmpp: lib/session.js: session() - returnObj.send() - Sending PDU to remote. cmdName: ' + pdu.cmdName + ' seqNr: ' + pdu.seqNr); + // Make sure the sequence number is set and is correct + pduObj.seqNr = returnObj.ourSeqNr; + + log.debug('larvitsmpp: lib/session.js: session() - returnObj.send() - Sending PDU to remote. cmdName: ' + pduObj.cmdName + ' seqNr: ' + pduObj.seqNr); // If closeAndSend is omitted, put callback in its place if (typeof closeAfterSend === 'function') { @@ -209,7 +207,7 @@ function session(sock) { * from - alphanum or international format * to - international format * message - string - * dlr - boolean defaults to false + * dlrRequested - boolean defaults to false * @param func callback(err, smsId, retPduObj) */ returnObj.sendSms = function(smsOptions, callback) { @@ -223,7 +221,7 @@ function session(sock) { }; // Request DLRs! - if (smsOptions.dlr) { + if (smsOptions.dlrRequested) { pduObj.params.registered_delivery = 0x01; } @@ -234,6 +232,99 @@ function session(sock) { }); }; + /** + * 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 ', + err, + dlrPduObj; + + if (typeof status === 'function') { + callback = status; + status = true; + } + + if (status === undefined) { + status = true; + } + + if (status) { + shortMessage += 'dlvrd:1 '; + } else { + shortMessage += 'dlvrd:0 '; + } + + shortMessage += 'submit date:' + smppUtils.smppDate(sms.submitTime); + shortMessage += ' done date:' + smppUtils.smppDate(new Date()); + + 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; + + console.log('before:'); + console.log(dlrPduObj); + + smppUtils.objToPdu(dlrPduObj, function(err, pdu) { + if (err) { + throw err; + } + + smppUtils.pduToObj(pdu, function(err, newObj) { + if (err) { + throw err; + } + + console.log('newObj:'); + console.log(newObj); + }); + }); + + return; + returnObj.send(dlrPduObj, function(err, retPduObj) { + console.log('WHATTA WHATTA'); + console.log(retPduObj); + + /*if (typeof callback === 'function') { + callback(err, retPduObj.params.message_id, retPduObj); + }*/ + }); + }; + // Handle incoming deliver_sm returnObj.deliverSm = function(pduObj) { var dlrObj; @@ -279,6 +370,7 @@ function session(sock) { smsObj = { 'from': pduObj.params.source_addr, 'to': pduObj.params.destination_addr, + 'submitTime': new Date(), 'message': pduObj.params.short_message, 'dlrRequested': Boolean(pduObj.params.registered_delivery) }; diff --git a/lib/utils.js b/lib/utils.js index f1cf7b2..47ce58e 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -48,7 +48,14 @@ function calcCmdLength(obj, callback) { tlvDef = defs.tlvs.default; } - cmdLength += tlvDef.type.size(tlvValue) + 4; + try { + cmdLength += tlvDef.type.size(tlvValue) + 4; + } catch(e) { + err = new Error('Could not get size of TLV parameter "' + tlvName + '" with value "' + tlvValue + '"'); + log.error('larvitsmpp: lib/utils.js: calcCmdLength() - ' + err.message); + callback(err); + return; + } } callback(null, cmdLength); @@ -192,8 +199,8 @@ function pduToObj(pdu, callback) { log.silly('larvitsmpp: lib/utils.js: pduToObj() - Decoding PDU to Obj. PDU buff in hex: ' + pdu.toString('hex')); if (pdu.length < 16) { - err = new Error('larvitsmpp: lib/utils.js: pduToObj() - PDU is to small, minimum size is 16, given size is ' + pdu.length); - log.warn(err.message); + err = new Error('PDU is to small, minimum size is 16, given size is ' + pdu.length); + log.warn('larvitsmpp: lib/utils.js: pduToObj() - ' + err.message); callback(err); return; @@ -207,18 +214,18 @@ function pduToObj(pdu, callback) { // Lookup the command id in the definitions if (defs.cmdsById[retObj.cmdId] === undefined) { - err = new Error('larvitsmpp: lib/utils.js: pduToObj() - Unknown PDU command id: ' + retObj.cmdId); + err = new Error('Unknown PDU command id: ' + retObj.cmdId); } if (isNaN(retObj.seqNr)) { - err = new Error('larvitsmpp: lib/utils.js: pduToObj() - Invalid seqNr, is not an interger: "' + retObj.seqNr + '"'); + err = new Error('Invalid seqNr, is not an interger: "' + retObj.seqNr + '"'); } else if (retObj.seqNr > 2147483646) { - err = new Error('larvitsmpp: lib/utils.js: pduToObj() - Invalid seqNr, maximum size of 2147483646 (0x7fffffff) exceeded.'); + err = new Error('Invalid seqNr, maximum size of 2147483646 (0x7fffffff) exceeded.'); } // If error is found, do not proceed with execution if (err !== null) { - log.warn(err.message); + log.warn('larvitsmpp: lib/utils.js: pduToObj() - ' + err.message); callback(err); return; } @@ -251,7 +258,8 @@ function pduToObj(pdu, callback) { // Increase the offset by the current params length offset += paramSize; } catch (e) { - err = new Error('larvitsmpp: lib/utils.js: pduToObj() - Failed to read param "' + param + '": ' + e.message); + err = new Error('Failed to read param "' + param + '": ' + e.message); + log.error('larvitsmpp: lib/utils.js: pduToObj() - ' + err.message); callback(err); return; @@ -260,8 +268,14 @@ function pduToObj(pdu, callback) { // If the length is greater than the current offset, there must be TLVs - resolve them! while (offset < retObj.cmdLength) { - tlvCmdId = pdu.readInt16BE(offset); - tlvLength = pdu.readInt16BE(offset + 2); + try { + tlvCmdId = pdu.readInt16BE(offset); + tlvLength = pdu.readInt16BE(offset + 2); + } catch (e) { + err = new Error('Unable to read TLV at offset "' + offset + '", given cmdLength: "' + retObj.cmdLength + '" pdu: ' + pdu.toString('hex')); + log.error('larvitsmpp: lib/utils.js: pduToObj() - ' + err.message); + callback(err); + } if (defs.tlvsById[tlvCmdId] === undefined) { tlvValue = pdu.slice(offset + 4, offset + 4 + tlvLength).toString('hex'); @@ -475,9 +489,48 @@ function pduReturn(pdu, status, params, tlvs, callback) { }); } +/** + * Format a js date object as ugly SMPP date format + * + * @param obj jsDateObj + * @return str + */ +function smppDate(jsDateObj) { + var uglyStr = ''; + + uglyStr += jsDateObj.getFullYear().toString().substring(2); + + if (jsDateObj.getMonth() < 10) { + uglyStr += '0'; + } + + uglyStr += jsDateObj.getMonth(); + + if (jsDateObj.getDate() < 10) { + uglyStr += '0'; + } + + uglyStr += jsDateObj.getDate(); + + if (jsDateObj.getHours() < 10) { + uglyStr += '0'; + } + + uglyStr += jsDateObj.getHours(); + + if (jsDateObj.getMinutes() < 10) { + uglyStr += '0'; + } + + uglyStr += jsDateObj.getMinutes(); + + return uglyStr; +} + // Expose some functions exports.decodeMsg = decodeMsg; exports.encodeMsg = encodeMsg; exports.pduToObj = pduToObj; exports.objToPdu = objToPdu; -exports.pduReturn = pduReturn; \ No newline at end of file +exports.pduReturn = pduReturn; +exports.smppDate = smppDate; \ No newline at end of file