diff --git a/acs.coffee b/acs.coffee index c8ee439..16ee813 100644 --- a/acs.coffee +++ b/acs.coffee @@ -74,6 +74,10 @@ updateDevice = (currentRequest, actions, callback) -> else deletes["#{path}_type"] = 1 + if actions.deletedObjects? + for p in actions.deletedObjects + deletes[p] = 1 + if actions.parameterNames? for p in actions.parameterNames path = if common.endsWith(p[0], '.') then p[0] else "#{p[0]}." @@ -82,7 +86,7 @@ updateDevice = (currentRequest, actions, callback) -> updates["#{path}_writable"] = p[1] updates["#{path}_timestamp"] = now - if Object.keys(updates).length > 0 + if Object.keys(updates).length > 0 or Object.keys(deletes).length > 0 db.devicesCollection.update({'_id' : currentRequest.deviceId}, {'$set' : updates, '$unset' : deletes}, {safe: true}, (err, count) -> if (err) callback(err) if callback? diff --git a/tasks.coffee b/tasks.coffee index a5afa9c..6d44388 100644 --- a/tasks.coffee +++ b/tasks.coffee @@ -116,6 +116,84 @@ this.setParameterValues = (task, methodResponse, callback) -> callback(null, STATUS_STARTED, {methodRequest : {type : 'SetParameterValues', parameterList : values}}, deviceUpdates) +this.addObject = (task, methodResponse, callback) -> + if methodResponse.faultcode? + task.fault = methodResponse + callback(null, STATUS_FAULT) + return + + if not task.instanceNumber? + if methodResponse.type is 'AddObjectResponse' + task.instanceNumber = methodResponse.instanceNumber + task.subtask = {name : 'getParameterNames', parameterPath : "#{task.objectName}#{task.instanceNumber}.", nextLevel : false} + task.appliedParameterValues = [] + task.parameterNames = [] + else + callback(null, STATUS_STARTED, {methodRequest : {type : 'AddObject', objectName : task.objectName}}) + return + + allDeviceUpdates = {} + + if task.subtask.name is 'getParameterNames' + this.getParameterNames(task.subtask, methodResponse, (err, status, cwmpResponse, deviceUpdates) => + common.extend(allDeviceUpdates, deviceUpdates) + if deviceUpdates and deviceUpdates.parameterNames + for p in deviceUpdates.parameterNames + task.parameterNames.push(p[0]) if not common.endsWith(p[0], '.') + + if status is STATUS_FINISHED + task.subtask = {name : 'getParameterValues', parameterNames : task.parameterNames} + else if status is STATUS_STARTED + callback(err, STATUS_STARTED, cwmpResponse, allDeviceUpdates) + else + throw Error('Unexpected subtask status') + ) + + if task.subtask.name is 'getParameterValues' + this.getParameterValues(task.subtask, methodResponse, (err, status, cwmpResponse, deviceUpdates) => + common.extend(allDeviceUpdates, deviceUpdates) + if deviceUpdates and deviceUpdates.parameterValues + for p1 in deviceUpdates.parameterValues + for p2 in task.parameterValues + if common.endsWith(p1[0], ".#{p2[0]}") + t = if p2[2] then p2[2] else p1[2] + v = common.matchType(p1[1], p2[1]) + # TODO only include if writable + task.appliedParameterValues.push([p1[0], v, t]) + + if methodResponse.faultcode? + # Ignore GetParameterValues errors. A workaround for the crappy Seewon devices. + methodResponse = {parameterList : {}} + if status is STATUS_FINISHED and task.appliedParameterValues.length > 0 + task.subtask = {name : 'setParameterValues', parameterValues : task.appliedParameterValues} + else + callback(err, status, cwmpResponse, allDeviceUpdates) + ) + + if task.subtask.name is 'setParameterValues' + this.setParameterValues(task.subtask, methodResponse, (err, status, cwmpResponse, deviceUpdates) => + common.extend(allDeviceUpdates, deviceUpdates) + callback(err, status, cwmpResponse, allDeviceUpdates) + ) + + +this.deleteObject = (task, methodResponse, callback) -> + if methodResponse.faultcode? + task.fault = methodResponse + callback(null, STATUS_FAULT) + return + + if methodResponse.type is 'DeleteObjectResponse' + # trim the last dot (.) + callback(null, STATUS_FINISHED, null, {deletedObjects : [task.objectName.slice(0, -1)]}) + else + methodRequest = { + type : 'DeleteObject', + objectName : task.objectName + } + callback(null, STATUS_STARTED, {methodRequest : methodRequest}) + + this.reboot = (task, methodResponse, callback) -> if methodResponse.faultcode? task.fault = methodResponse diff --git a/tr-069.coffee b/tr-069.coffee index 7dae2ab..ed7f460 100644 --- a/tr-069.coffee +++ b/tr-069.coffee @@ -97,6 +97,29 @@ cpeSetParameterValuesResponse = (xml) -> {status : JSON.parse(xml.get('Status').text())} +cpeAddObject = (xml, methodRequest) -> + el = xml.node('cwmp:AddObject') + el.node('ObjectName').text(methodRequest.objectName) + el.node('ParameterKey').text(if methodRequest.parameterKey? then methodRequest.parameterKey else '') + + +cpeAddObjectResponse = (xml) -> + { + instanceNumber : parseInt(xml.get('InstanceNumber').text()), + status : parseInt(xml.get('Status').text()) + } + + +cpeDeleteObject = (xml, methodRequest) -> + el = xml.node('cwmp:DeleteObject') + el.node('ObjectName').text(methodRequest.objectName) + el.node('ParameterKey').text(if methodRequest.parameterKey? then methodRequest.parameterKey else '') + + +cpeDeleteObjectResponse = (xml) -> + {status : parseInt(xml.get('Status').text())} + + traverseXml = (xml) -> obj = {} for n in xml.childNodes() @@ -208,6 +231,12 @@ exports.request = (httpRequest) -> when 'SetParameterValuesResponse' cwmpRequest.methodResponse = cpeSetParameterValuesResponse(methodElement) cwmpRequest.methodResponse.type = 'SetParameterValuesResponse' + when 'AddObjectResponse' + cwmpRequest.methodResponse = cpeAddObjectResponse(methodElement) + cwmpRequest.methodResponse.type = 'AddObjectResponse' + when 'DeleteObjectResponse' + cwmpRequest.methodResponse = cpeDeleteObjectResponse(methodElement) + cwmpRequest.methodResponse.type = 'DeleteObjectResponse' when 'RebootResponse' cwmpRequest.methodResponse = cpeRebootResponse(methodElement) cwmpRequest.methodResponse.type = 'RebootResponse' @@ -267,6 +296,10 @@ exports.response = (id, cwmpResponse, cookies = null) -> cpeGetParameterValues(body, cwmpResponse.methodRequest) when 'SetParameterValues' cpeSetParameterValues(body, cwmpResponse.methodRequest) + when 'AddObject' + cpeAddObject(body, cwmpResponse.methodRequest) + when 'DeleteObject' + cpeDeleteObject(body, cwmpResponse.methodRequest) when 'Reboot' cpeReboot(body, cwmpResponse.methodRequest) when 'FactoryReset'