diff options
Diffstat (limited to 'lib/libUPnP/Platinum/Source/Core/PltAction.cpp')
-rw-r--r-- | lib/libUPnP/Platinum/Source/Core/PltAction.cpp | 505 |
1 files changed, 505 insertions, 0 deletions
diff --git a/lib/libUPnP/Platinum/Source/Core/PltAction.cpp b/lib/libUPnP/Platinum/Source/Core/PltAction.cpp new file mode 100644 index 0000000..78ff4b2 --- /dev/null +++ b/lib/libUPnP/Platinum/Source/Core/PltAction.cpp @@ -0,0 +1,505 @@ +/***************************************************************** +| +| Platinum - Service Action +| +| Copyright (c) 2004-2010, Plutinosoft, LLC. +| All rights reserved. +| http://www.plutinosoft.com +| +| This program is free software; you can redistribute it and/or +| modify it under the terms of the GNU General Public License +| as published by the Free Software Foundation; either version 2 +| of the License, or (at your option) any later version. +| +| OEMs, ISVs, VARs and other distributors that combine and +| distribute commercially licensed software with Platinum software +| and do not wish to distribute the source code for the commercially +| licensed software under version 2, or (at your option) any later +| version, of the GNU General Public License (the "GPL") must enter +| into a commercial license agreement with Plutinosoft, LLC. +| licensing@plutinosoft.com +| +| This program is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| You should have received a copy of the GNU General Public License +| along with this program; see the file LICENSE.txt. If not, write to +| the Free Software Foundation, Inc., +| 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +| http://www.gnu.org/licenses/gpl-2.0.html +| +****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "PltAction.h" +#include "PltService.h" +#include "PltUtilities.h" + +#define REMOVE_WMP_DATATYPE_EXTENSION + +NPT_SET_LOCAL_LOGGER("platinum.core.action") + +/*---------------------------------------------------------------------- +| PLT_ActionDesc::PLT_ActionDesc ++---------------------------------------------------------------------*/ +PLT_ActionDesc::PLT_ActionDesc(const char* name, PLT_Service* service) : + m_Name(name), + m_Service(service) +{ +} + +/*---------------------------------------------------------------------- +| PLT_ActionDesc::~PLT_ActionDesc ++---------------------------------------------------------------------*/ +PLT_ActionDesc::~PLT_ActionDesc() +{ + m_ArgumentDescs.Apply(NPT_ObjectDeleter<PLT_ArgumentDesc>()); +} + +/*---------------------------------------------------------------------- +| PLT_ActionDesc::GetSCPDXML ++---------------------------------------------------------------------*/ +NPT_Result +PLT_ActionDesc::GetSCPDXML(NPT_XmlElementNode* node) +{ + NPT_XmlElementNode* action = new NPT_XmlElementNode("action"); + NPT_CHECK_SEVERE(node->AddChild(action)); + NPT_CHECK_SEVERE(PLT_XmlHelper::AddChildText(action, "name", m_Name)); + + NPT_XmlElementNode* argumentList = new NPT_XmlElementNode("argumentList"); + NPT_CHECK_SEVERE(action->AddChild(argumentList)); + + // no arguments is ok + if (!m_ArgumentDescs.GetItemCount()) return NPT_SUCCESS; + + return m_ArgumentDescs.ApplyUntil( + PLT_GetSCPDXMLIterator<PLT_ArgumentDesc>(argumentList), + NPT_UntilResultNotEquals(NPT_SUCCESS)); +} + +/*---------------------------------------------------------------------- +| PLT_ActionDesc::GetService ++---------------------------------------------------------------------*/ +PLT_Service* +PLT_ActionDesc::GetService() +{ + return m_Service; +} + +/*---------------------------------------------------------------------- +| PLT_ActionDesc::GetArgumentDesc ++---------------------------------------------------------------------*/ +PLT_ArgumentDesc* +PLT_ActionDesc::GetArgumentDesc(const char* name) +{ + PLT_ArgumentDesc* arg_desc = NULL; + NPT_ContainerFind(m_ArgumentDescs, PLT_ArgumentDescNameFinder(name), arg_desc); + return arg_desc; +} + +/*---------------------------------------------------------------------- +| PLT_Action::PLT_Action ++---------------------------------------------------------------------*/ +PLT_Action::PLT_Action(PLT_ActionDesc& action_desc) : + m_ActionDesc(action_desc), + m_ErrorCode(0) +{ +} + +/*---------------------------------------------------------------------- +| PLT_Action::PLT_Action ++---------------------------------------------------------------------*/ +PLT_Action::PLT_Action(PLT_ActionDesc& action_desc, + PLT_DeviceDataReference& root_device) : + m_ActionDesc(action_desc), + m_ErrorCode(0), + m_RootDevice(root_device) +{ +} + +/*---------------------------------------------------------------------- +| PLT_Action::~PLT_Action ++---------------------------------------------------------------------*/ +PLT_Action::~PLT_Action() +{ + m_Arguments.Apply(NPT_ObjectDeleter<PLT_Argument>()); +} + +/*---------------------------------------------------------------------- +| PLT_Action::GetArgumentValue ++---------------------------------------------------------------------*/ +NPT_Result +PLT_Action::GetArgumentValue(const char* name, NPT_String& value) +{ + PLT_Argument* arg = GetArgument(name); + if (arg == NULL) { + return NPT_FAILURE; + } + value = arg->GetValue(); + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| PLT_Action::GetArgumentValue ++---------------------------------------------------------------------*/ +NPT_Result +PLT_Action::GetArgumentValue(const char* name, NPT_UInt32& value) +{ + NPT_String tmp_value; + NPT_CHECK_WARNING(GetArgumentValue(name, tmp_value)); + return tmp_value.ToInteger(value); +} + +/*---------------------------------------------------------------------- +| PLT_Action::GetArgumentValue ++---------------------------------------------------------------------*/ +NPT_Result +PLT_Action::GetArgumentValue(const char* name, NPT_Int32& value) +{ + NPT_String tmp_value; + NPT_CHECK_WARNING(GetArgumentValue(name, tmp_value)); + return tmp_value.ToInteger(value); +} + +/*---------------------------------------------------------------------- +| PLT_Action::GetArgumentValue ++---------------------------------------------------------------------*/ +NPT_Result +PLT_Action::GetArgumentValue(const char* name, bool& value) +{ + NPT_String tmp_value; + NPT_CHECK_WARNING(GetArgumentValue(name, tmp_value)); + if (tmp_value == "1" || + !tmp_value.Compare("TRUE", true) || + !tmp_value.Compare("YES", true)) { + value = true; + } else if (tmp_value == "0" || + !tmp_value.Compare("FALSE", true) || + !tmp_value.Compare("NO", true)) { + value = false; + } else { + return NPT_FAILURE; + } + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| PLT_Action::GetArgument ++---------------------------------------------------------------------*/ +PLT_Argument* +PLT_Action::GetArgument(const char* name) +{ + PLT_Argument* argument = NULL; + NPT_ContainerFind(m_Arguments, PLT_ArgumentNameFinder(name), argument); + return argument; +} + +/*---------------------------------------------------------------------- +| PLT_Action::SetArgumentValue ++---------------------------------------------------------------------*/ +NPT_Result +PLT_Action::SetArgumentValue(const char* name, + const char* value) +{ + // look for this argument in our argument list + // and replace the value if we found it + PLT_Arguments::Iterator iter = NULL; + if (NPT_SUCCEEDED(NPT_ContainerFind(m_Arguments, PLT_ArgumentNameFinder(name), iter))) { + NPT_Result res = (*iter)->SetValue(value); + + // remove argument from list if failed + // so that when we verify arguments later, + // we don't use a previously set value + if (NPT_FAILED(res)) m_Arguments.Erase(iter); + return res; + } + + // since we didn't find it, create a clone + PLT_Argument* arg; + NPT_CHECK_SEVERE(PLT_Argument::CreateArgument(m_ActionDesc, name, value, arg)); + + // insert it at the right position + for (NPT_Cardinal i=0; + i<m_Arguments.GetItemCount(); + i++) { + iter = m_Arguments.GetItem(i); + if ((*iter)->GetPosition() > arg->GetPosition()) { + return m_Arguments.Insert(iter, arg); + } + } + + return m_Arguments.Add(arg); +} + +/*---------------------------------------------------------------------- +| PLT_Action::VerifyArgumentValue ++---------------------------------------------------------------------*/ +NPT_Result +PLT_Action::VerifyArgumentValue(const char* name, const char* value) +{ + NPT_String str; + NPT_CHECK_SEVERE(GetArgumentValue(name, str)); + + return str.Compare(value, true)?NPT_FAILURE:NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| PLT_Action::VerifyArguments ++---------------------------------------------------------------------*/ +NPT_Result +PLT_Action::VerifyArguments(bool input) +{ + NPT_Cardinal count = 0; + + // Check we have all the required parameters (in or out) + for(unsigned int i=0; i<m_ActionDesc.GetArgumentDescs().GetItemCount(); i++) { + PLT_ArgumentDesc* arg_desc = m_ActionDesc.GetArgumentDescs()[i]; + + // only input arguments are needed + if (arg_desc->GetDirection().Compare(input?"in":"out", true)) + continue; + + // look for this argument in the list we received + PLT_Argument* arg = NULL; + if (NPT_FAILED(NPT_ContainerFind(m_Arguments, PLT_ArgumentNameFinder(arg_desc->GetName()), arg))) { + NPT_LOG_WARNING_2("Argument %s for action %s not found", + (const char*) arg_desc->GetName(), + (const char*) m_ActionDesc.GetName()); + return NPT_FAILURE; + } + ++count; + } + + SetError(0, ""); + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| PLT_Action::SetArgumentOutFromStateVariable ++---------------------------------------------------------------------*/ +NPT_Result +PLT_Action::SetArgumentOutFromStateVariable(PLT_ArgumentDesc* arg_desc) +{ + // only output arguments can use a state variable + if (arg_desc->GetDirection().Compare("out", true)) { + return NPT_FAILURE; + } + + PLT_StateVariable* variable = arg_desc->GetRelatedStateVariable(); + if (!variable) return NPT_FAILURE; + + // assign the value to an argument + NPT_CHECK_SEVERE(SetArgumentValue(arg_desc->GetName(), variable->GetValue())); + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| PLT_Action::SetArgumentOutFromStateVariable ++---------------------------------------------------------------------*/ +NPT_Result +PLT_Action::SetArgumentOutFromStateVariable(const char* name) +{ + // look for this argument in the action list of arguments + PLT_ArgumentDesc* arg_desc = NULL; + NPT_CHECK_SEVERE(NPT_ContainerFind(m_ActionDesc.GetArgumentDescs(), + PLT_ArgumentDescNameFinder(name), arg_desc)); + + return SetArgumentOutFromStateVariable(arg_desc); +} + +/*---------------------------------------------------------------------- +| PLT_Action::SetArgumentsOutFromStateVariable ++---------------------------------------------------------------------*/ +NPT_Result +PLT_Action::SetArgumentsOutFromStateVariable() +{ + // go through the list of the action output arguments + for(unsigned int i=0; i<m_ActionDesc.GetArgumentDescs().GetItemCount(); i++) { + PLT_ArgumentDesc* arg_desc = m_ActionDesc.GetArgumentDescs()[i]; + + // only output arguments are needed + if (arg_desc->GetDirection().Compare("out", true)) + continue; + + NPT_CHECK_SEVERE(SetArgumentOutFromStateVariable(arg_desc)); + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| PLT_Action::SetError ++---------------------------------------------------------------------*/ +NPT_Result +PLT_Action::SetError(unsigned int code, const char* description) +{ + m_ErrorCode = code; + m_ErrorDescription = description; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| PLT_Action::GetError ++---------------------------------------------------------------------*/ +const char* +PLT_Action::GetError(unsigned int* code /* = NULL */) +{ + if (code) *code = m_ErrorCode; + return m_ErrorDescription; +} + +/*---------------------------------------------------------------------- +| PLT_Action::GetErrorCode ++---------------------------------------------------------------------*/ +unsigned int +PLT_Action::GetErrorCode() +{ + return m_ErrorCode; +} + +/*---------------------------------------------------------------------- +| PLT_Action::FormatSoapRequest ++---------------------------------------------------------------------*/ +NPT_Result +PLT_Action::FormatSoapRequest(NPT_OutputStream& stream) +{ + NPT_String str; + NPT_Result res; + NPT_XmlElementNode* body = NULL; + NPT_XmlElementNode* request = NULL; + NPT_XmlElementNode* envelope = new NPT_XmlElementNode("s", "Envelope"); + + NPT_CHECK_LABEL_SEVERE(res = envelope->SetNamespaceUri("s", "http://schemas.xmlsoap.org/soap/envelope/"), cleanup); + NPT_CHECK_LABEL_SEVERE(res = envelope->SetAttribute("s", "encodingStyle", "http://schemas.xmlsoap.org/soap/encoding/"), cleanup); + + body = new NPT_XmlElementNode("s", "Body"); + NPT_CHECK_LABEL_SEVERE(res = envelope->AddChild(body), cleanup); + + request = new NPT_XmlElementNode("u", m_ActionDesc.GetName()); + NPT_CHECK_LABEL_SEVERE(res = request->SetNamespaceUri("u", m_ActionDesc.GetService()->GetServiceType()), cleanup); + NPT_CHECK_LABEL_SEVERE(res = body->AddChild(request), cleanup); + + for(unsigned int i=0; i<m_Arguments.GetItemCount(); i++) { + PLT_Argument* argument = m_Arguments[i]; + if (argument->GetDesc().GetDirection().Compare("in", true) == 0) { + NPT_CHECK_LABEL_SEVERE(res = PLT_XmlHelper::AddChildText( + request, + argument->GetDesc().GetName(), + argument->GetValue()), cleanup); + } + } + + NPT_CHECK_LABEL_SEVERE(res = PLT_XmlHelper::Serialize(*envelope, str), cleanup); + delete envelope; + + return stream.Write((const char*)str, str.GetLength()); + +cleanup: + delete envelope; + return res; +} + +/*---------------------------------------------------------------------- +| PLT_Action::FormatSoapResponse ++---------------------------------------------------------------------*/ +NPT_Result +PLT_Action::FormatSoapResponse(NPT_OutputStream& stream) +{ + if (m_ErrorCode) { + return FormatSoapError(m_ErrorCode, m_ErrorDescription, stream); + } + + NPT_String str; + NPT_Result res; + NPT_XmlElementNode* body = NULL; + NPT_XmlElementNode* response = NULL; + NPT_XmlElementNode* node = NULL; + NPT_XmlElementNode* envelope = new NPT_XmlElementNode("s", "Envelope"); + + NPT_CHECK_LABEL_SEVERE(res = envelope->SetNamespaceUri("s", "http://schemas.xmlsoap.org/soap/envelope/"), cleanup); + NPT_CHECK_LABEL_SEVERE(res = envelope->SetAttribute("s", "encodingStyle", "http://schemas.xmlsoap.org/soap/encoding/"), cleanup); + + body = new NPT_XmlElementNode("s", "Body"); + NPT_CHECK_LABEL_SEVERE(res = envelope->AddChild(body), cleanup); + + response = new NPT_XmlElementNode("u", m_ActionDesc.GetName() + "Response"); + NPT_CHECK_LABEL_SEVERE(response->SetNamespaceUri("u", m_ActionDesc.GetService()->GetServiceType()), cleanup); + NPT_CHECK_LABEL_SEVERE(res = body->AddChild(response), cleanup); + + for(unsigned int i=0; i<m_Arguments.GetItemCount(); i++) { + PLT_Argument* argument = m_Arguments[i]; + if (argument->GetDesc().GetDirection().Compare("out", true) == 0) { + node = new NPT_XmlElementNode(argument->GetDesc().GetName()); + NPT_CHECK_LABEL_SEVERE(res = node->AddText(argument->GetValue()), cleanup); + NPT_CHECK_LABEL_SEVERE(res = response->AddChild(node), cleanup); + +#ifndef REMOVE_WMP_DATATYPE_EXTENSION + PLT_StateVariable* var = argument->GetDesc().GetRelatedStateVariable(); + if (var) { + node->SetNamespaceUri("dt", "urn:schemas-microsoft-com:datatypes"); + node->SetAttribute("dt", "dt", var->GetDataType()); + } +#endif + } + } + + // this will xmlescape any values that contain xml characters + NPT_CHECK_LABEL_SEVERE(PLT_XmlHelper::Serialize(*envelope, str), cleanup); + delete envelope; + + return stream.Write((const char*)str, str.GetLength()); + +cleanup: + delete envelope; + return res; +} + +/*---------------------------------------------------------------------- +| PLT_Action::FormatSoapError ++---------------------------------------------------------------------*/ +NPT_Result +PLT_Action::FormatSoapError(unsigned int code, NPT_String desc, NPT_OutputStream& stream) +{ + NPT_String str; + NPT_Result res; + NPT_XmlElementNode* body = NULL; + NPT_XmlElementNode* fault = NULL; + NPT_XmlElementNode* detail = NULL; + NPT_XmlElementNode* UPnPError = NULL; + NPT_XmlElementNode* envelope = new NPT_XmlElementNode("s", "Envelope"); + + NPT_CHECK_LABEL_SEVERE(res = envelope->SetNamespaceUri("s", "http://schemas.xmlsoap.org/soap/envelope/"), cleanup); + NPT_CHECK_LABEL_SEVERE(res = envelope->SetAttribute("s", "encodingStyle", "http://schemas.xmlsoap.org/soap/encoding/"), cleanup); + + body = new NPT_XmlElementNode("s", "Body"); + NPT_CHECK_LABEL_SEVERE(res = envelope->AddChild(body), cleanup); + + fault = new NPT_XmlElementNode("s", "Fault"); + NPT_CHECK_LABEL_SEVERE(res = body->AddChild(fault), cleanup); + + NPT_CHECK_LABEL_SEVERE(res = PLT_XmlHelper::AddChildText(fault, "faultcode", "s:Client"), cleanup); + NPT_CHECK_LABEL_SEVERE(res = PLT_XmlHelper::AddChildText(fault, "faultstring", "UPnPError"), cleanup); + + detail = new NPT_XmlElementNode("detail"); + NPT_CHECK_LABEL_SEVERE(res = fault->AddChild(detail), cleanup); + + UPnPError = new NPT_XmlElementNode("UPnPError"); + NPT_CHECK_LABEL_SEVERE(res = UPnPError->SetNamespaceUri("", "urn:schemas-upnp-org:control-1-0"), cleanup); + NPT_CHECK_LABEL_SEVERE(res = detail->AddChild(UPnPError), cleanup); + + NPT_CHECK_LABEL_SEVERE(res = PLT_XmlHelper::AddChildText(UPnPError, "errorCode", NPT_String::FromInteger(code)), cleanup); + NPT_CHECK_LABEL_SEVERE(res = PLT_XmlHelper::AddChildText(UPnPError, "errorDescription", desc), cleanup); + + NPT_CHECK_LABEL_SEVERE(res = PLT_XmlHelper::Serialize(*envelope, str), cleanup); + delete envelope; + + return stream.Write((const char*)str, str.GetLength()); + +cleanup: + delete envelope; + return res; +} |