1 /*****************************************************************
3 | Platinum - Service Action
5 | Copyright (c) 2004-2010, Plutinosoft, LLC.
7 | http://www.plutinosoft.com
9 | This program is free software; you can redistribute it and/or
10 | modify it under the terms of the GNU General Public License
11 | as published by the Free Software Foundation; either version 2
12 | of the License, or (at your option) any later version.
14 | OEMs, ISVs, VARs and other distributors that combine and
15 | distribute commercially licensed software with Platinum software
16 | and do not wish to distribute the source code for the commercially
17 | licensed software under version 2, or (at your option) any later
18 | version, of the GNU General Public License (the "GPL") must enter
19 | into a commercial license agreement with Plutinosoft, LLC.
20 | licensing@plutinosoft.com
22 | This program is distributed in the hope that it will be useful,
23 | but WITHOUT ANY WARRANTY; without even the implied warranty of
24 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 | GNU General Public License for more details.
27 | You should have received a copy of the GNU General Public License
28 | along with this program; see the file LICENSE.txt. If not, write to
29 | the Free Software Foundation, Inc.,
30 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
31 | http://www.gnu.org/licenses/gpl-2.0.html
33 ****************************************************************/
35 /*----------------------------------------------------------------------
37 +---------------------------------------------------------------------*/
38 #include "PltAction.h"
39 #include "PltService.h"
40 #include "PltUtilities.h"
42 #define REMOVE_WMP_DATATYPE_EXTENSION
44 NPT_SET_LOCAL_LOGGER("platinum.core.action")
46 /*----------------------------------------------------------------------
47 | PLT_ActionDesc::PLT_ActionDesc
48 +---------------------------------------------------------------------*/
49 PLT_ActionDesc::PLT_ActionDesc(const char* name
, PLT_Service
* service
) :
55 /*----------------------------------------------------------------------
56 | PLT_ActionDesc::~PLT_ActionDesc
57 +---------------------------------------------------------------------*/
58 PLT_ActionDesc::~PLT_ActionDesc()
60 m_ArgumentDescs
.Apply(NPT_ObjectDeleter
<PLT_ArgumentDesc
>());
63 /*----------------------------------------------------------------------
64 | PLT_ActionDesc::GetSCPDXML
65 +---------------------------------------------------------------------*/
67 PLT_ActionDesc::GetSCPDXML(NPT_XmlElementNode
* node
)
69 NPT_XmlElementNode
* action
= new NPT_XmlElementNode("action");
70 NPT_CHECK_SEVERE(node
->AddChild(action
));
71 NPT_CHECK_SEVERE(PLT_XmlHelper::AddChildText(action
, "name", m_Name
));
73 NPT_XmlElementNode
* argumentList
= new NPT_XmlElementNode("argumentList");
74 NPT_CHECK_SEVERE(action
->AddChild(argumentList
));
77 if (!m_ArgumentDescs
.GetItemCount()) return NPT_SUCCESS
;
79 return m_ArgumentDescs
.ApplyUntil(
80 PLT_GetSCPDXMLIterator
<PLT_ArgumentDesc
>(argumentList
),
81 NPT_UntilResultNotEquals(NPT_SUCCESS
));
84 /*----------------------------------------------------------------------
85 | PLT_ActionDesc::GetService
86 +---------------------------------------------------------------------*/
88 PLT_ActionDesc::GetService()
93 /*----------------------------------------------------------------------
94 | PLT_ActionDesc::GetArgumentDesc
95 +---------------------------------------------------------------------*/
97 PLT_ActionDesc::GetArgumentDesc(const char* name
)
99 PLT_ArgumentDesc
* arg_desc
= NULL
;
100 NPT_ContainerFind(m_ArgumentDescs
, PLT_ArgumentDescNameFinder(name
), arg_desc
);
104 /*----------------------------------------------------------------------
105 | PLT_Action::PLT_Action
106 +---------------------------------------------------------------------*/
107 PLT_Action::PLT_Action(PLT_ActionDesc
& action_desc
) :
108 m_ActionDesc(action_desc
),
113 /*----------------------------------------------------------------------
114 | PLT_Action::PLT_Action
115 +---------------------------------------------------------------------*/
116 PLT_Action::PLT_Action(PLT_ActionDesc
& action_desc
,
117 PLT_DeviceDataReference
& root_device
) :
118 m_ActionDesc(action_desc
),
120 m_RootDevice(root_device
)
124 /*----------------------------------------------------------------------
125 | PLT_Action::~PLT_Action
126 +---------------------------------------------------------------------*/
127 PLT_Action::~PLT_Action()
129 m_Arguments
.Apply(NPT_ObjectDeleter
<PLT_Argument
>());
132 /*----------------------------------------------------------------------
133 | PLT_Action::GetArgumentValue
134 +---------------------------------------------------------------------*/
136 PLT_Action::GetArgumentValue(const char* name
, NPT_String
& value
)
138 PLT_Argument
* arg
= GetArgument(name
);
142 value
= arg
->GetValue();
146 /*----------------------------------------------------------------------
147 | PLT_Action::GetArgumentValue
148 +---------------------------------------------------------------------*/
150 PLT_Action::GetArgumentValue(const char* name
, NPT_UInt32
& value
)
152 NPT_String tmp_value
;
153 NPT_CHECK_WARNING(GetArgumentValue(name
, tmp_value
));
154 return tmp_value
.ToInteger(value
);
157 /*----------------------------------------------------------------------
158 | PLT_Action::GetArgumentValue
159 +---------------------------------------------------------------------*/
161 PLT_Action::GetArgumentValue(const char* name
, NPT_Int32
& value
)
163 NPT_String tmp_value
;
164 NPT_CHECK_WARNING(GetArgumentValue(name
, tmp_value
));
165 return tmp_value
.ToInteger(value
);
168 /*----------------------------------------------------------------------
169 | PLT_Action::GetArgumentValue
170 +---------------------------------------------------------------------*/
172 PLT_Action::GetArgumentValue(const char* name
, bool& value
)
174 NPT_String tmp_value
;
175 NPT_CHECK_WARNING(GetArgumentValue(name
, tmp_value
));
176 if (tmp_value
== "1" ||
177 !tmp_value
.Compare("TRUE", true) ||
178 !tmp_value
.Compare("YES", true)) {
180 } else if (tmp_value
== "0" ||
181 !tmp_value
.Compare("FALSE", true) ||
182 !tmp_value
.Compare("NO", true)) {
190 /*----------------------------------------------------------------------
191 | PLT_Action::GetArgument
192 +---------------------------------------------------------------------*/
194 PLT_Action::GetArgument(const char* name
)
196 PLT_Argument
* argument
= NULL
;
197 NPT_ContainerFind(m_Arguments
, PLT_ArgumentNameFinder(name
), argument
);
201 /*----------------------------------------------------------------------
202 | PLT_Action::SetArgumentValue
203 +---------------------------------------------------------------------*/
205 PLT_Action::SetArgumentValue(const char* name
,
208 // look for this argument in our argument list
209 // and replace the value if we found it
210 PLT_Arguments::Iterator iter
= NULL
;
211 if (NPT_SUCCEEDED(NPT_ContainerFind(m_Arguments
, PLT_ArgumentNameFinder(name
), iter
))) {
212 NPT_Result res
= (*iter
)->SetValue(value
);
214 // remove argument from list if failed
215 // so that when we verify arguments later,
216 // we don't use a previously set value
217 if (NPT_FAILED(res
)) m_Arguments
.Erase(iter
);
221 // since we didn't find it, create a clone
223 NPT_CHECK_SEVERE(PLT_Argument::CreateArgument(m_ActionDesc
, name
, value
, arg
));
225 // insert it at the right position
226 for (NPT_Cardinal i
=0;
227 i
<m_Arguments
.GetItemCount();
229 iter
= m_Arguments
.GetItem(i
);
230 if ((*iter
)->GetPosition() > arg
->GetPosition()) {
231 return m_Arguments
.Insert(iter
, arg
);
235 return m_Arguments
.Add(arg
);
238 /*----------------------------------------------------------------------
239 | PLT_Action::VerifyArgumentValue
240 +---------------------------------------------------------------------*/
242 PLT_Action::VerifyArgumentValue(const char* name
, const char* value
)
245 NPT_CHECK_SEVERE(GetArgumentValue(name
, str
));
247 return str
.Compare(value
, true)?NPT_FAILURE
:NPT_SUCCESS
;
250 /*----------------------------------------------------------------------
251 | PLT_Action::VerifyArguments
252 +---------------------------------------------------------------------*/
254 PLT_Action::VerifyArguments(bool input
)
256 NPT_Cardinal count
= 0;
258 // Check we have all the required parameters (in or out)
259 for(unsigned int i
=0; i
<m_ActionDesc
.GetArgumentDescs().GetItemCount(); i
++) {
260 PLT_ArgumentDesc
* arg_desc
= m_ActionDesc
.GetArgumentDescs()[i
];
262 // only input arguments are needed
263 if (arg_desc
->GetDirection().Compare(input
?"in":"out", true))
266 // look for this argument in the list we received
267 PLT_Argument
* arg
= NULL
;
268 if (NPT_FAILED(NPT_ContainerFind(m_Arguments
, PLT_ArgumentNameFinder(arg_desc
->GetName()), arg
))) {
269 NPT_LOG_WARNING_2("Argument %s for action %s not found",
270 (const char*) arg_desc
->GetName(),
271 (const char*) m_ActionDesc
.GetName());
281 /*----------------------------------------------------------------------
282 | PLT_Action::SetArgumentOutFromStateVariable
283 +---------------------------------------------------------------------*/
285 PLT_Action::SetArgumentOutFromStateVariable(PLT_ArgumentDesc
* arg_desc
)
287 // only output arguments can use a state variable
288 if (arg_desc
->GetDirection().Compare("out", true)) {
292 PLT_StateVariable
* variable
= arg_desc
->GetRelatedStateVariable();
293 if (!variable
) return NPT_FAILURE
;
295 // assign the value to an argument
296 NPT_CHECK_SEVERE(SetArgumentValue(arg_desc
->GetName(), variable
->GetValue()));
300 /*----------------------------------------------------------------------
301 | PLT_Action::SetArgumentOutFromStateVariable
302 +---------------------------------------------------------------------*/
304 PLT_Action::SetArgumentOutFromStateVariable(const char* name
)
306 // look for this argument in the action list of arguments
307 PLT_ArgumentDesc
* arg_desc
= NULL
;
308 NPT_CHECK_SEVERE(NPT_ContainerFind(m_ActionDesc
.GetArgumentDescs(),
309 PLT_ArgumentDescNameFinder(name
), arg_desc
));
311 return SetArgumentOutFromStateVariable(arg_desc
);
314 /*----------------------------------------------------------------------
315 | PLT_Action::SetArgumentsOutFromStateVariable
316 +---------------------------------------------------------------------*/
318 PLT_Action::SetArgumentsOutFromStateVariable()
320 // go through the list of the action output arguments
321 for(unsigned int i
=0; i
<m_ActionDesc
.GetArgumentDescs().GetItemCount(); i
++) {
322 PLT_ArgumentDesc
* arg_desc
= m_ActionDesc
.GetArgumentDescs()[i
];
324 // only output arguments are needed
325 if (arg_desc
->GetDirection().Compare("out", true))
328 NPT_CHECK_SEVERE(SetArgumentOutFromStateVariable(arg_desc
));
334 /*----------------------------------------------------------------------
335 | PLT_Action::SetError
336 +---------------------------------------------------------------------*/
338 PLT_Action::SetError(unsigned int code
, const char* description
)
341 m_ErrorDescription
= description
;
345 /*----------------------------------------------------------------------
346 | PLT_Action::GetError
347 +---------------------------------------------------------------------*/
349 PLT_Action::GetError(unsigned int* code
/* = NULL */)
351 if (code
) *code
= m_ErrorCode
;
352 return m_ErrorDescription
;
355 /*----------------------------------------------------------------------
356 | PLT_Action::GetErrorCode
357 +---------------------------------------------------------------------*/
359 PLT_Action::GetErrorCode()
364 /*----------------------------------------------------------------------
365 | PLT_Action::FormatSoapRequest
366 +---------------------------------------------------------------------*/
368 PLT_Action::FormatSoapRequest(NPT_OutputStream
& stream
)
372 NPT_XmlElementNode
* body
= NULL
;
373 NPT_XmlElementNode
* request
= NULL
;
374 NPT_XmlElementNode
* envelope
= new NPT_XmlElementNode("s", "Envelope");
376 NPT_CHECK_LABEL_SEVERE(res
= envelope
->SetNamespaceUri("s", "http://schemas.xmlsoap.org/soap/envelope/"), cleanup
);
377 NPT_CHECK_LABEL_SEVERE(res
= envelope
->SetAttribute("s", "encodingStyle", "http://schemas.xmlsoap.org/soap/encoding/"), cleanup
);
379 body
= new NPT_XmlElementNode("s", "Body");
380 NPT_CHECK_LABEL_SEVERE(res
= envelope
->AddChild(body
), cleanup
);
382 request
= new NPT_XmlElementNode("u", m_ActionDesc
.GetName());
383 NPT_CHECK_LABEL_SEVERE(res
= request
->SetNamespaceUri("u", m_ActionDesc
.GetService()->GetServiceType()), cleanup
);
384 NPT_CHECK_LABEL_SEVERE(res
= body
->AddChild(request
), cleanup
);
386 for(unsigned int i
=0; i
<m_Arguments
.GetItemCount(); i
++) {
387 PLT_Argument
* argument
= m_Arguments
[i
];
388 if (argument
->GetDesc().GetDirection().Compare("in", true) == 0) {
389 NPT_CHECK_LABEL_SEVERE(res
= PLT_XmlHelper::AddChildText(
391 argument
->GetDesc().GetName(),
392 argument
->GetValue()), cleanup
);
396 NPT_CHECK_LABEL_SEVERE(res
= PLT_XmlHelper::Serialize(*envelope
, str
), cleanup
);
399 return stream
.Write((const char*)str
, str
.GetLength());
406 /*----------------------------------------------------------------------
407 | PLT_Action::FormatSoapResponse
408 +---------------------------------------------------------------------*/
410 PLT_Action::FormatSoapResponse(NPT_OutputStream
& stream
)
413 return FormatSoapError(m_ErrorCode
, m_ErrorDescription
, stream
);
418 NPT_XmlElementNode
* body
= NULL
;
419 NPT_XmlElementNode
* response
= NULL
;
420 NPT_XmlElementNode
* node
= NULL
;
421 NPT_XmlElementNode
* envelope
= new NPT_XmlElementNode("s", "Envelope");
423 NPT_CHECK_LABEL_SEVERE(res
= envelope
->SetNamespaceUri("s", "http://schemas.xmlsoap.org/soap/envelope/"), cleanup
);
424 NPT_CHECK_LABEL_SEVERE(res
= envelope
->SetAttribute("s", "encodingStyle", "http://schemas.xmlsoap.org/soap/encoding/"), cleanup
);
426 body
= new NPT_XmlElementNode("s", "Body");
427 NPT_CHECK_LABEL_SEVERE(res
= envelope
->AddChild(body
), cleanup
);
429 response
= new NPT_XmlElementNode("u", m_ActionDesc
.GetName() + "Response");
430 NPT_CHECK_LABEL_SEVERE(response
->SetNamespaceUri("u", m_ActionDesc
.GetService()->GetServiceType()), cleanup
);
431 NPT_CHECK_LABEL_SEVERE(res
= body
->AddChild(response
), cleanup
);
433 for(unsigned int i
=0; i
<m_Arguments
.GetItemCount(); i
++) {
434 PLT_Argument
* argument
= m_Arguments
[i
];
435 if (argument
->GetDesc().GetDirection().Compare("out", true) == 0) {
436 node
= new NPT_XmlElementNode(argument
->GetDesc().GetName());
437 NPT_CHECK_LABEL_SEVERE(res
= node
->AddText(argument
->GetValue()), cleanup
);
438 NPT_CHECK_LABEL_SEVERE(res
= response
->AddChild(node
), cleanup
);
440 #ifndef REMOVE_WMP_DATATYPE_EXTENSION
441 PLT_StateVariable
* var
= argument
->GetDesc().GetRelatedStateVariable();
443 node
->SetNamespaceUri("dt", "urn:schemas-microsoft-com:datatypes");
444 node
->SetAttribute("dt", "dt", var
->GetDataType());
450 // this will xmlescape any values that contain xml characters
451 NPT_CHECK_LABEL_SEVERE(PLT_XmlHelper::Serialize(*envelope
, str
), cleanup
);
454 return stream
.Write((const char*)str
, str
.GetLength());
461 /*----------------------------------------------------------------------
462 | PLT_Action::FormatSoapError
463 +---------------------------------------------------------------------*/
465 PLT_Action::FormatSoapError(unsigned int code
, NPT_String desc
, NPT_OutputStream
& stream
)
469 NPT_XmlElementNode
* body
= NULL
;
470 NPT_XmlElementNode
* fault
= NULL
;
471 NPT_XmlElementNode
* detail
= NULL
;
472 NPT_XmlElementNode
* UPnPError
= NULL
;
473 NPT_XmlElementNode
* envelope
= new NPT_XmlElementNode("s", "Envelope");
475 NPT_CHECK_LABEL_SEVERE(res
= envelope
->SetNamespaceUri("s", "http://schemas.xmlsoap.org/soap/envelope/"), cleanup
);
476 NPT_CHECK_LABEL_SEVERE(res
= envelope
->SetAttribute("s", "encodingStyle", "http://schemas.xmlsoap.org/soap/encoding/"), cleanup
);
478 body
= new NPT_XmlElementNode("s", "Body");
479 NPT_CHECK_LABEL_SEVERE(res
= envelope
->AddChild(body
), cleanup
);
481 fault
= new NPT_XmlElementNode("s", "Fault");
482 NPT_CHECK_LABEL_SEVERE(res
= body
->AddChild(fault
), cleanup
);
484 NPT_CHECK_LABEL_SEVERE(res
= PLT_XmlHelper::AddChildText(fault
, "faultcode", "s:Client"), cleanup
);
485 NPT_CHECK_LABEL_SEVERE(res
= PLT_XmlHelper::AddChildText(fault
, "faultstring", "UPnPError"), cleanup
);
487 detail
= new NPT_XmlElementNode("detail");
488 NPT_CHECK_LABEL_SEVERE(res
= fault
->AddChild(detail
), cleanup
);
490 UPnPError
= new NPT_XmlElementNode("UPnPError");
491 NPT_CHECK_LABEL_SEVERE(res
= UPnPError
->SetNamespaceUri("", "urn:schemas-upnp-org:control-1-0"), cleanup
);
492 NPT_CHECK_LABEL_SEVERE(res
= detail
->AddChild(UPnPError
), cleanup
);
494 NPT_CHECK_LABEL_SEVERE(res
= PLT_XmlHelper::AddChildText(UPnPError
, "errorCode", NPT_String::FromInteger(code
)), cleanup
);
495 NPT_CHECK_LABEL_SEVERE(res
= PLT_XmlHelper::AddChildText(UPnPError
, "errorDescription", desc
), cleanup
);
497 NPT_CHECK_LABEL_SEVERE(res
= PLT_XmlHelper::Serialize(*envelope
, str
), cleanup
);
500 return stream
.Write((const char*)str
, str
.GetLength());