2 * Web Services on Devices
4 * Copyright 2017-2018 Owen Rudge for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "wsdapi_internal.h"
27 #include "wine/debug.h"
28 #include "wine/heap.h"
29 #include "webservices.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(wsdapi
);
33 #define APP_MAX_DELAY 500
35 static const WCHAR discoveryTo
[] = {
37 's','c','h','e','m','a','s','-','x','m','l','s','o','a','p','-','o','r','g',':',
38 'w','s',':','2','0','0','5',':','0','4',':',
39 'd','i','s','c','o','v','e','r','y', 0 };
41 static const WCHAR anonymousTo
[] = {
42 'h','t','t','p',':','/','/',
43 's','c','h','e','m','a','s','.','x','m','l','s','o','a','p','.','o','r','g','/',
44 'w','s','/','2','0','0','4','/','0','8','/',
45 'a','d','d','r','e','s','s','i','n','g','/',
47 'a','n','o','n','y','m','o','u','s', 0 };
49 static const WCHAR actionHello
[] = {
50 'h','t','t','p',':','/','/',
51 's','c','h','e','m','a','s','.','x','m','l','s','o','a','p','.','o','r','g','/',
52 'w','s','/','2','0','0','5','/','0','4','/',
53 'd','i','s','c','o','v','e','r','y','/',
54 'H','e','l','l','o', 0 };
56 static const WCHAR actionProbe
[] = {
57 'h','t','t','p',':','/','/',
58 's','c','h','e','m','a','s','.','x','m','l','s','o','a','p','.','o','r','g','/',
59 'w','s','/','2','0','0','5','/','0','4','/',
60 'd','i','s','c','o','v','e','r','y','/',
61 'P','r','o','b','e', 0 };
63 static const WCHAR actionProbeMatches
[] = {
64 'h','t','t','p',':','/','/',
65 's','c','h','e','m','a','s','.','x','m','l','s','o','a','p','.','o','r','g','/',
66 'w','s','/','2','0','0','5','/','0','4','/',
67 'd','i','s','c','o','v','e','r','y','/',
68 'P','r','o','b','e','M','a','t','c','h','e','s', 0 };
70 static const WCHAR actionBye
[] = {
71 'h','t','t','p',':','/','/',
72 's','c','h','e','m','a','s','.','x','m','l','s','o','a','p','.','o','r','g','/',
73 'w','s','/','2','0','0','5','/','0','4','/',
74 'd','i','s','c','o','v','e','r','y','/',
77 static const WCHAR addressingNsUri
[] = {
78 'h','t','t','p',':','/','/',
79 's','c','h','e','m','a','s','.','x','m','l','s','o','a','p','.','o','r','g','/',
80 'w','s','/','2','0','0','4','/','0','8','/','a','d','d','r','e','s','s','i','n','g', 0 };
82 static const WCHAR discoveryNsUri
[] = {
83 'h','t','t','p',':','/','/',
84 's','c','h','e','m','a','s','.','x','m','l','s','o','a','p','.','o','r','g','/',
85 'w','s','/','2','0','0','5','/','0','4','/','d','i','s','c','o','v','e','r','y', 0 };
87 static const WCHAR envelopeNsUri
[] = {
88 'h','t','t','p',':','/','/',
89 'w','w','w','.','w','3','.','o','r','g','/',
90 '2','0','0','3','/','0','5','/','s','o','a','p','-','e','n','v','e','l','o','p','e', 0 };
92 static const WCHAR addressingPrefix
[] = { 'w','s','a', 0 };
93 static const WCHAR discoveryPrefix
[] = { 'w','s','d', 0 };
94 static const WCHAR envelopePrefix
[] = { 's','o','a','p', 0 };
95 static const WCHAR headerString
[] = { 'H','e','a','d','e','r', 0 };
96 static const WCHAR actionString
[] = { 'A','c','t','i','o','n', 0 };
97 static const WCHAR messageIdString
[] = { 'M','e','s','s','a','g','e','I','D', 0 };
98 static const WCHAR toString
[] = { 'T','o', 0 };
99 static const WCHAR relatesToString
[] = { 'R','e','l','a','t','e','s','T','o', 0 };
100 static const WCHAR appSequenceString
[] = { 'A','p','p','S','e','q','u','e','n','c','e', 0 };
101 static const WCHAR instanceIdString
[] = { 'I','n','s','t','a','n','c','e','I','d', 0 };
102 static const WCHAR messageNumberString
[] = { 'M','e','s','s','a','g','e','N','u','m','b','e','r', 0 };
103 static const WCHAR sequenceIdString
[] = { 'S','e','q','u','e','n','c','e','I','d', 0 };
104 static const WCHAR emptyString
[] = { 0 };
105 static const WCHAR bodyString
[] = { 'B','o','d','y', 0 };
106 static const WCHAR helloString
[] = { 'H','e','l','l','o', 0 };
107 static const WCHAR probeString
[] = { 'P','r','o','b','e', 0 };
108 static const WCHAR probeMatchString
[] = { 'P','r','o','b','e','M','a','t','c','h', 0 };
109 static const WCHAR probeMatchesString
[] = { 'P','r','o','b','e','M','a','t','c','h','e','s', 0 };
110 static const WCHAR byeString
[] = { 'B','y','e', 0 };
111 static const WCHAR endpointReferenceString
[] = { 'E','n','d','p','o','i','n','t','R','e','f','e','r','e','n','c','e', 0 };
112 static const WCHAR addressString
[] = { 'A','d','d','r','e','s','s', 0 };
113 static const WCHAR referenceParametersString
[] = { 'R','e','f','e','r','e','n','c','e','P','a','r','a','m','e','t','e','r','s', 0 };
114 static const WCHAR typesString
[] = { 'T','y','p','e','s', 0 };
115 static const WCHAR scopesString
[] = { 'S','c','o','p','e','s', 0 };
116 static const WCHAR xAddrsString
[] = { 'X','A','d','d','r','s', 0 };
117 static const WCHAR metadataVersionString
[] = { 'M','e','t','a','d','a','t','a','V','e','r','s','i','o','n', 0 };
119 struct discovered_namespace
126 static LPWSTR
utf8_to_wide(void *parent
, const char *utf8_str
, int length
)
128 int utf8_str_len
= 0, chars_needed
= 0, bytes_needed
= 0;
129 LPWSTR new_str
= NULL
;
131 if (utf8_str
== NULL
) return NULL
;
133 utf8_str_len
= (length
< 0) ? lstrlenA(utf8_str
) : length
;
134 chars_needed
= MultiByteToWideChar(CP_UTF8
, 0, utf8_str
, utf8_str_len
, NULL
, 0);
136 if (chars_needed
<= 0) return NULL
;
138 bytes_needed
= sizeof(WCHAR
) * (chars_needed
+ 1);
139 new_str
= WSDAllocateLinkedMemory(parent
, bytes_needed
);
141 MultiByteToWideChar(CP_UTF8
, 0, utf8_str
, utf8_str_len
, new_str
, chars_needed
);
142 new_str
[chars_needed
] = 0;
147 static char *wide_to_utf8(LPCWSTR wide_string
, int *length
)
149 char *new_string
= NULL
;
151 if (wide_string
== NULL
)
154 *length
= WideCharToMultiByte(CP_UTF8
, 0, wide_string
, -1, NULL
, 0, NULL
, NULL
);
159 new_string
= heap_alloc(*length
);
160 WideCharToMultiByte(CP_UTF8
, 0, wide_string
, -1, new_string
, *length
, NULL
, NULL
);
165 static WS_XML_STRING
*populate_xml_string(LPCWSTR str
)
167 WS_XML_STRING
*xml
= heap_alloc_zero(sizeof(WS_XML_STRING
));
173 xml
->bytes
= (BYTE
*)wide_to_utf8(str
, &utf8Length
);
175 if (xml
->bytes
== NULL
)
181 xml
->dictionary
= NULL
;
183 xml
->length
= (xml
->bytes
== NULL
) ? 0 : (utf8Length
- 1);
188 static inline void free_xml_string(WS_XML_STRING
*value
)
193 heap_free(value
->bytes
);
198 static HRESULT
write_xml_attribute(WSDXML_ATTRIBUTE
*attribute
, WS_XML_WRITER
*writer
)
200 WS_XML_STRING
*local_name
= NULL
, *element_ns
= NULL
, *ns_prefix
= NULL
;
201 WS_XML_UTF16_TEXT utf16_text
;
202 HRESULT ret
= E_OUTOFMEMORY
;
205 if (attribute
== NULL
)
208 /* Start the attribute */
209 local_name
= populate_xml_string(attribute
->Name
->LocalName
);
210 if (local_name
== NULL
) goto cleanup
;
212 if (attribute
->Name
->Space
== NULL
)
214 element_ns
= populate_xml_string(emptyString
);
215 if (element_ns
== NULL
) goto cleanup
;
221 element_ns
= populate_xml_string(attribute
->Name
->Space
->Uri
);
222 if (element_ns
== NULL
) goto cleanup
;
224 ns_prefix
= populate_xml_string(attribute
->Name
->Space
->PreferredPrefix
);
225 if (ns_prefix
== NULL
) goto cleanup
;
228 ret
= WsWriteStartAttribute(writer
, ns_prefix
, local_name
, element_ns
, FALSE
, NULL
);
229 if (FAILED(ret
)) goto cleanup
;
231 text_len
= lstrlenW(attribute
->Value
);
233 utf16_text
.text
.textType
= WS_XML_TEXT_TYPE_UTF16
;
234 utf16_text
.bytes
= (BYTE
*)attribute
->Value
;
235 utf16_text
.byteCount
= min(WSD_MAX_TEXT_LENGTH
, text_len
) * sizeof(WCHAR
);
237 ret
= WsWriteText(writer
, (WS_XML_TEXT
*)&utf16_text
, NULL
);
238 if (FAILED(ret
)) goto cleanup
;
240 ret
= WsWriteEndAttribute(writer
, NULL
);
241 if (FAILED(ret
)) goto cleanup
;
244 free_xml_string(local_name
);
245 free_xml_string(element_ns
);
246 free_xml_string(ns_prefix
);
251 static HRESULT
write_xml_element(WSDXML_ELEMENT
*element
, WS_XML_WRITER
*writer
)
253 WS_XML_STRING
*local_name
= NULL
, *element_ns
= NULL
, *ns_prefix
= NULL
;
254 WSDXML_ATTRIBUTE
*current_attribute
;
255 WS_XML_UTF16_TEXT utf16_text
;
256 WSDXML_NODE
*current_child
;
257 WSDXML_TEXT
*node_as_text
;
259 HRESULT ret
= E_OUTOFMEMORY
;
264 /* Start the element */
265 local_name
= populate_xml_string(element
->Name
->LocalName
);
266 if (local_name
== NULL
) goto cleanup
;
268 element_ns
= populate_xml_string(element
->Name
->Space
->Uri
);
269 if (element_ns
== NULL
) goto cleanup
;
271 ns_prefix
= populate_xml_string(element
->Name
->Space
->PreferredPrefix
);
272 if (ns_prefix
== NULL
) goto cleanup
;
274 ret
= WsWriteStartElement(writer
, ns_prefix
, local_name
, element_ns
, NULL
);
275 if (FAILED(ret
)) goto cleanup
;
277 /* Write attributes */
278 current_attribute
= element
->FirstAttribute
;
280 while (current_attribute
!= NULL
)
282 ret
= write_xml_attribute(current_attribute
, writer
);
283 if (FAILED(ret
)) goto cleanup
;
284 current_attribute
= current_attribute
->Next
;
287 /* Write child elements */
288 current_child
= element
->FirstChild
;
290 while (current_child
!= NULL
)
292 if (current_child
->Type
== ElementType
)
294 ret
= write_xml_element((WSDXML_ELEMENT
*)current_child
, writer
);
295 if (FAILED(ret
)) goto cleanup
;
297 else if (current_child
->Type
== TextType
)
299 node_as_text
= (WSDXML_TEXT
*)current_child
;
300 text_len
= lstrlenW(node_as_text
->Text
);
302 utf16_text
.text
.textType
= WS_XML_TEXT_TYPE_UTF16
;
303 utf16_text
.byteCount
= min(WSD_MAX_TEXT_LENGTH
, text_len
) * sizeof(WCHAR
);
304 utf16_text
.bytes
= (BYTE
*)node_as_text
->Text
;
306 ret
= WsWriteText(writer
, (WS_XML_TEXT
*)&utf16_text
, NULL
);
307 if (FAILED(ret
)) goto cleanup
;
310 current_child
= current_child
->Next
;
313 /* End the element */
314 ret
= WsWriteEndElement(writer
, NULL
);
317 free_xml_string(local_name
);
318 free_xml_string(element_ns
);
319 free_xml_string(ns_prefix
);
324 static HRESULT
add_child_element(IWSDXMLContext
*xml_context
, WSDXML_ELEMENT
*parent
, LPCWSTR ns_uri
,
325 LPCWSTR name
, LPCWSTR text
, WSDXML_ELEMENT
**out
)
327 WSDXML_ELEMENT
*element_obj
;
328 WSDXML_NAME
*name_obj
;
331 ret
= IWSDXMLContext_AddNameToNamespace(xml_context
, ns_uri
, name
, &name_obj
);
332 if (FAILED(ret
)) return ret
;
334 ret
= WSDXMLBuildAnyForSingleElement(name_obj
, text
, &element_obj
);
335 WSDFreeLinkedMemory(name_obj
);
337 if (FAILED(ret
)) return ret
;
339 /* Add the element as a child - this will link the element's memory allocation to the parent's */
340 ret
= WSDXMLAddChild(parent
, element_obj
);
344 WSDFreeLinkedMemory(element_obj
);
348 if (out
!= NULL
) *out
= element_obj
;
352 HRESULT
register_namespaces(IWSDXMLContext
*xml_context
)
356 ret
= IWSDXMLContext_AddNamespace(xml_context
, addressingNsUri
, addressingPrefix
, NULL
);
357 if (FAILED(ret
)) return ret
;
359 ret
= IWSDXMLContext_AddNamespace(xml_context
, discoveryNsUri
, discoveryPrefix
, NULL
);
360 if (FAILED(ret
)) return ret
;
362 return IWSDXMLContext_AddNamespace(xml_context
, envelopeNsUri
, envelopePrefix
, NULL
);
365 static BOOL
create_guid(LPWSTR buffer
)
367 const WCHAR formatString
[] = { 'u','r','n',':','u','u','i','d',':','%','s', 0 };
369 WCHAR
* uuidString
= NULL
;
372 if (UuidCreate(&uuid
) != RPC_S_OK
)
375 UuidToStringW(&uuid
, (RPC_WSTR
*)&uuidString
);
377 if (uuidString
== NULL
)
380 wsprintfW(buffer
, formatString
, uuidString
);
381 RpcStringFreeW((RPC_WSTR
*)&uuidString
);
386 static void populate_soap_header(WSD_SOAP_HEADER
*header
, LPCWSTR to
, LPCWSTR action
, LPCWSTR message_id
,
387 WSD_APP_SEQUENCE
*sequence
, const WSDXML_ELEMENT
*any_headers
)
389 ZeroMemory(header
, sizeof(WSD_SOAP_HEADER
));
392 header
->Action
= action
;
393 header
->MessageID
= message_id
;
394 header
->AppSequence
= sequence
;
395 header
->AnyHeaders
= (WSDXML_ELEMENT
*)any_headers
;
397 /* TODO: Implement RelatesTo, ReplyTo, From, FaultTo */
400 #define MAX_ULONGLONG_STRING_SIZE 25
402 static LPWSTR
ulonglong_to_string(void *parent
, ULONGLONG value
)
404 WCHAR formatString
[] = { '%','I','6','4','u', 0 };
407 ret
= WSDAllocateLinkedMemory(parent
, MAX_ULONGLONG_STRING_SIZE
* sizeof(WCHAR
));
412 wsprintfW(ret
, formatString
, value
);
416 static WSDXML_ATTRIBUTE
*add_attribute(IWSDXMLContext
*xml_context
, WSDXML_ELEMENT
*parent
, LPCWSTR ns_uri
, LPCWSTR name
)
418 WSDXML_ATTRIBUTE
*attribute
, *cur_attrib
;
419 WSDXML_NAME
*name_obj
= NULL
;
423 name_obj
= WSDAllocateLinkedMemory(NULL
, sizeof(WSDXML_NAME
));
424 name_obj
->LocalName
= duplicate_string(name_obj
, name
);
425 name_obj
->Space
= NULL
;
429 if (FAILED(IWSDXMLContext_AddNameToNamespace(xml_context
, ns_uri
, name
, &name_obj
)))
433 attribute
= WSDAllocateLinkedMemory(parent
, sizeof(WSDXML_ATTRIBUTE
));
435 if (attribute
== NULL
)
437 WSDFreeLinkedMemory(name_obj
);
441 attribute
->Element
= parent
;
442 attribute
->Name
= name_obj
;
443 attribute
->Next
= NULL
;
444 attribute
->Value
= NULL
;
446 if (name_obj
!= NULL
)
447 WSDAttachLinkedMemory(attribute
, name_obj
);
449 if (parent
->FirstAttribute
== NULL
)
451 /* Make this the first attribute of the parent */
452 parent
->FirstAttribute
= attribute
;
456 /* Find the last attribute and add this as the next one */
457 cur_attrib
= parent
->FirstAttribute
;
459 while (cur_attrib
->Next
!= NULL
)
461 cur_attrib
= cur_attrib
->Next
;
464 cur_attrib
->Next
= attribute
;
470 static void remove_attribute(WSDXML_ELEMENT
*parent
, WSDXML_ATTRIBUTE
*attribute
)
472 WSDXML_ATTRIBUTE
*cur_attrib
;
474 /* Find the last attribute and add this as the next one */
475 cur_attrib
= parent
->FirstAttribute
;
477 if (cur_attrib
== attribute
)
478 parent
->FirstAttribute
= cur_attrib
->Next
;
481 while (cur_attrib
!= NULL
)
483 /* Is our attribute the next attribute? */
484 if (cur_attrib
->Next
== attribute
)
486 /* Remove it from the list */
487 cur_attrib
->Next
= attribute
->Next
;
491 cur_attrib
= cur_attrib
->Next
;
495 WSDFreeLinkedMemory(attribute
);
498 static HRESULT
add_ulonglong_attribute(IWSDXMLContext
*xml_context
, WSDXML_ELEMENT
*parent
, LPCWSTR ns_uri
, LPCWSTR name
,
501 WSDXML_ATTRIBUTE
*attribute
= add_attribute(xml_context
, parent
, ns_uri
, name
);
503 if (attribute
== NULL
)
506 attribute
->Value
= ulonglong_to_string(attribute
, value
);
508 if (attribute
->Value
== NULL
)
510 remove_attribute(parent
, attribute
);
517 static HRESULT
add_string_attribute(IWSDXMLContext
*xml_context
, WSDXML_ELEMENT
*parent
, LPCWSTR ns_uri
, LPCWSTR name
,
520 WSDXML_ATTRIBUTE
*attribute
= add_attribute(xml_context
, parent
, ns_uri
, name
);
522 if (attribute
== NULL
)
525 attribute
->Value
= duplicate_string(attribute
, value
);
527 if (attribute
->Value
== NULL
)
529 remove_attribute(parent
, attribute
);
536 static BOOL
add_discovered_namespace(struct list
*namespaces
, WSDXML_NAMESPACE
*discovered_ns
)
538 struct discovered_namespace
*ns
;
540 LIST_FOR_EACH_ENTRY(ns
, namespaces
, struct discovered_namespace
, entry
)
542 if (lstrcmpW(ns
->uri
, discovered_ns
->Uri
) == 0)
543 return TRUE
; /* Already added */
546 ns
= WSDAllocateLinkedMemory(namespaces
, sizeof(struct discovered_namespace
));
551 ns
->prefix
= duplicate_string(ns
, discovered_ns
->PreferredPrefix
);
552 ns
->uri
= duplicate_string(ns
, discovered_ns
->Uri
);
554 if ((ns
->prefix
== NULL
) || (ns
->uri
== NULL
))
557 list_add_tail(namespaces
, &ns
->entry
);
561 static HRESULT
build_types_list(LPWSTR buffer
, size_t buffer_size
, const WSD_NAME_LIST
*list
, struct list
*namespaces
)
563 WCHAR format_string
[] = { '%', 's', ':', '%', 's', 0 };
564 LPWSTR current_buf_pos
= buffer
;
565 size_t memory_needed
= 0;
566 const WSD_NAME_LIST
*cur
= list
;
570 /* Calculate space needed, including NULL character, colon and potential trailing space */
571 memory_needed
= sizeof(WCHAR
) * (lstrlenW(cur
->Element
->LocalName
) +
572 lstrlenW(cur
->Element
->Space
->PreferredPrefix
) + 3);
574 if (current_buf_pos
+ memory_needed
> buffer
+ buffer_size
)
578 *current_buf_pos
++ = ' ';
580 current_buf_pos
+= wsprintfW(current_buf_pos
, format_string
, cur
->Element
->Space
->PreferredPrefix
,
581 cur
->Element
->LocalName
);
583 /* Record the namespace in the discovered namespaces list */
584 if (!add_discovered_namespace(namespaces
, cur
->Element
->Space
))
588 } while (cur
!= NULL
);
593 static HRESULT
build_uri_list(LPWSTR buffer
, size_t buffer_size
, const WSD_URI_LIST
*list
)
595 size_t memory_needed
= 0, string_len
= 0;
596 const WSD_URI_LIST
*cur
= list
;
597 LPWSTR cur_buf_pos
= buffer
;
601 /* Calculate space needed, including trailing space */
602 string_len
= lstrlenW(cur
->Element
);
603 memory_needed
= (string_len
+ 1) * sizeof(WCHAR
);
605 if (cur_buf_pos
+ memory_needed
> buffer
+ buffer_size
)
609 *cur_buf_pos
++ = ' ';
611 memcpy(cur_buf_pos
, cur
->Element
, memory_needed
);
612 cur_buf_pos
+= string_len
;
615 } while (cur
!= NULL
);
620 static HRESULT
duplicate_element(WSDXML_ELEMENT
*parent
, const WSDXML_ELEMENT
*node
, struct list
*namespaces
)
622 WSDXML_ATTRIBUTE
*cur_attribute
, *new_attribute
, *last_attribute
= NULL
;
623 WSDXML_ELEMENT
*new_element
;
624 WSDXML_TEXT
*text_node
;
625 WSDXML_NODE
*cur_node
;
628 /* First record the namespace in the discovered namespaces list */
629 if (!add_discovered_namespace(namespaces
, node
->Name
->Space
))
632 ret
= WSDXMLBuildAnyForSingleElement(node
->Name
, NULL
, &new_element
);
633 if (FAILED(ret
)) return ret
;
635 /* Duplicate the nodes */
636 cur_node
= node
->FirstChild
;
638 while (cur_node
!= NULL
)
640 if (cur_node
->Type
== ElementType
)
642 ret
= duplicate_element(new_element
, (WSDXML_ELEMENT
*)cur_node
, namespaces
);
643 if (FAILED(ret
)) goto cleanup
;
645 else if (cur_node
->Type
== TextType
)
647 text_node
= WSDAllocateLinkedMemory(new_element
, sizeof(WSDXML_TEXT
));
648 if (text_node
== NULL
) goto failed
;
650 text_node
->Node
.Parent
= NULL
;
651 text_node
->Node
.Next
= NULL
;
652 text_node
->Node
.Type
= TextType
;
653 text_node
->Text
= duplicate_string(text_node
, ((WSDXML_TEXT
*)cur_node
)->Text
);
655 if (text_node
->Text
== NULL
) goto failed
;
657 ret
= WSDXMLAddChild(new_element
, (WSDXML_ELEMENT
*)text_node
);
658 if (FAILED(ret
)) goto cleanup
;
661 cur_node
= cur_node
->Next
;
664 /* Duplicate the attributes */
665 cur_attribute
= node
->FirstAttribute
;
667 while (cur_attribute
!= NULL
)
669 if ((cur_attribute
->Name
->Space
!= NULL
) && (!add_discovered_namespace(namespaces
, cur_attribute
->Name
->Space
)))
672 new_attribute
= WSDAllocateLinkedMemory(new_element
, sizeof(WSDXML_ATTRIBUTE
));
673 if (new_attribute
== NULL
) goto failed
;
675 new_attribute
->Element
= new_element
;
676 new_attribute
->Name
= duplicate_name(new_attribute
, cur_attribute
->Name
);
677 new_attribute
->Value
= duplicate_string(new_attribute
, cur_attribute
->Value
);
678 new_attribute
->Next
= NULL
;
680 if ((new_attribute
->Name
== NULL
) || (new_attribute
->Value
== NULL
)) goto failed
;
682 if (last_attribute
== NULL
)
683 new_element
->FirstAttribute
= new_attribute
;
685 last_attribute
->Next
= new_attribute
;
687 last_attribute
= new_attribute
;
688 cur_attribute
= cur_attribute
->Next
;
691 ret
= WSDXMLAddChild(parent
, new_element
);
692 if (FAILED(ret
)) goto cleanup
;
700 WSDXMLCleanupElement(new_element
);
704 static HRESULT
create_soap_header_xml_elements(IWSDXMLContext
*xml_context
, WSD_SOAP_HEADER
*header
,
705 struct list
*discovered_namespaces
, WSDXML_ELEMENT
**out_element
)
707 WSDXML_ELEMENT
*header_element
= NULL
, *app_sequence_element
= NULL
, *temp_element
;
708 WSDXML_NAME
*header_name
= NULL
;
712 ret
= IWSDXMLContext_AddNameToNamespace(xml_context
, envelopeNsUri
, headerString
, &header_name
);
713 if (FAILED(ret
)) goto cleanup
;
715 ret
= WSDXMLBuildAnyForSingleElement(header_name
, NULL
, &header_element
);
716 if (FAILED(ret
)) goto cleanup
;
718 WSDFreeLinkedMemory(header_name
);
721 ret
= add_child_element(xml_context
, header_element
, addressingNsUri
, actionString
, header
->Action
, &temp_element
);
722 if (FAILED(ret
)) goto cleanup
;
725 ret
= add_child_element(xml_context
, header_element
, addressingNsUri
, messageIdString
, header
->MessageID
, &temp_element
);
726 if (FAILED(ret
)) goto cleanup
;
729 ret
= add_child_element(xml_context
, header_element
, addressingNsUri
, toString
, header
->To
, &temp_element
);
730 if (FAILED(ret
)) goto cleanup
;
733 if (header
->RelatesTo
.MessageID
!= NULL
)
735 ret
= add_child_element(xml_context
, header_element
, addressingNsUri
, relatesToString
,
736 header
->RelatesTo
.MessageID
, &temp_element
);
737 if (FAILED(ret
)) goto cleanup
;
740 /* <d:AppSequence> */
741 ret
= add_child_element(xml_context
, header_element
, discoveryNsUri
, appSequenceString
, emptyString
, &app_sequence_element
);
742 if (FAILED(ret
)) goto cleanup
;
744 /* InstanceId attribute */
745 ret
= add_ulonglong_attribute(xml_context
, app_sequence_element
, NULL
, instanceIdString
, min(UINT_MAX
,
746 header
->AppSequence
->InstanceId
));
747 if (FAILED(ret
)) goto cleanup
;
749 /* SequenceID attribute */
750 if (header
->AppSequence
->SequenceId
!= NULL
)
752 ret
= add_string_attribute(xml_context
, app_sequence_element
, NULL
, sequenceIdString
, header
->AppSequence
->SequenceId
);
753 if (FAILED(ret
)) goto cleanup
;
756 /* MessageNumber attribute */
757 ret
= add_ulonglong_attribute(xml_context
, app_sequence_element
, NULL
, messageNumberString
, min(UINT_MAX
,
758 header
->AppSequence
->MessageNumber
));
759 if (FAILED(ret
)) goto cleanup
;
761 /* </d:AppSequence> */
763 /* Write any headers */
764 if (header
->AnyHeaders
!= NULL
)
766 ret
= duplicate_element(header_element
, header
->AnyHeaders
, discovered_namespaces
);
767 if (FAILED(ret
)) goto cleanup
;
772 *out_element
= header_element
;
776 if (header_name
!= NULL
) WSDFreeLinkedMemory(header_name
);
777 WSDXMLCleanupElement(header_element
);
782 static HRESULT
create_soap_envelope(IWSDXMLContext
*xml_context
, WSD_SOAP_HEADER
*header
, WSDXML_ELEMENT
*body_element
,
783 WS_HEAP
**heap
, char **output_xml
, ULONG
*xml_length
, struct list
*discovered_namespaces
)
785 WS_XML_STRING
*actual_envelope_prefix
= NULL
, *envelope_uri_xmlstr
= NULL
, *tmp_prefix
= NULL
, *tmp_uri
= NULL
;
786 WSDXML_NAMESPACE
*addressing_ns
= NULL
, *discovery_ns
= NULL
, *envelope_ns
= NULL
;
787 WSDXML_ELEMENT
*header_element
= NULL
;
788 struct discovered_namespace
*ns
;
789 WS_XML_BUFFER
*buffer
= NULL
;
790 WS_XML_WRITER
*writer
= NULL
;
791 WS_XML_STRING envelope
;
792 HRESULT ret
= E_OUTOFMEMORY
;
793 static BYTE envelopeString
[] = "Envelope";
795 /* Create the necessary XML prefixes */
796 if (FAILED(IWSDXMLContext_AddNamespace(xml_context
, addressingNsUri
, addressingPrefix
, &addressing_ns
))) goto cleanup
;
797 if (!add_discovered_namespace(discovered_namespaces
, addressing_ns
)) goto cleanup
;
799 if (FAILED(IWSDXMLContext_AddNamespace(xml_context
, discoveryNsUri
, discoveryPrefix
, &discovery_ns
))) goto cleanup
;
800 if (!add_discovered_namespace(discovered_namespaces
, discovery_ns
)) goto cleanup
;
802 if (FAILED(IWSDXMLContext_AddNamespace(xml_context
, envelopeNsUri
, envelopePrefix
, &envelope_ns
))) goto cleanup
;
803 if (!add_discovered_namespace(discovered_namespaces
, envelope_ns
)) goto cleanup
;
805 envelope
.bytes
= envelopeString
;
806 envelope
.length
= sizeof(envelopeString
) - 1;
807 envelope
.dictionary
= NULL
;
810 actual_envelope_prefix
= populate_xml_string(envelope_ns
->PreferredPrefix
);
811 envelope_uri_xmlstr
= populate_xml_string(envelope_ns
->Uri
);
813 if ((actual_envelope_prefix
== NULL
) || (envelope_uri_xmlstr
== NULL
)) goto cleanup
;
815 /* Now try to create the appropriate WebServices buffers, etc */
816 ret
= WsCreateHeap(16384, 4096, NULL
, 0, heap
, NULL
);
817 if (FAILED(ret
)) goto cleanup
;
819 ret
= WsCreateXmlBuffer(*heap
, NULL
, 0, &buffer
, NULL
);
820 if (FAILED(ret
)) goto cleanup
;
822 ret
= WsCreateWriter(NULL
, 0, &writer
, NULL
);
823 if (FAILED(ret
)) goto cleanup
;
825 ret
= WsSetOutputToBuffer(writer
, buffer
, NULL
, 0, NULL
);
826 if (FAILED(ret
)) goto cleanup
;
828 /* Create the header XML elements */
829 ret
= create_soap_header_xml_elements(xml_context
, header
, discovered_namespaces
, &header_element
);
830 if (FAILED(ret
)) goto cleanup
;
833 ret
= WsWriteStartElement(writer
, actual_envelope_prefix
, &envelope
, envelope_uri_xmlstr
, NULL
);
834 if (FAILED(ret
)) goto cleanup
;
836 LIST_FOR_EACH_ENTRY(ns
, discovered_namespaces
, struct discovered_namespace
, entry
)
838 tmp_prefix
= populate_xml_string(ns
->prefix
);
839 tmp_uri
= populate_xml_string(ns
->uri
);
841 if ((tmp_prefix
== NULL
) || (tmp_uri
== NULL
)) goto cleanup
;
843 ret
= WsWriteXmlnsAttribute(writer
, tmp_prefix
, tmp_uri
, FALSE
, NULL
);
844 if (FAILED(ret
)) goto cleanup
;
846 free_xml_string(tmp_prefix
);
847 free_xml_string(tmp_uri
);
853 /* Write the header */
854 ret
= write_xml_element(header_element
, writer
);
855 if (FAILED(ret
)) goto cleanup
;
858 ret
= write_xml_element(body_element
, writer
);
859 if (FAILED(ret
)) goto cleanup
;
861 ret
= WsWriteEndElement(writer
, NULL
);
862 if (FAILED(ret
)) goto cleanup
;
866 /* Generate the bytes of the document */
867 ret
= WsWriteXmlBufferToBytes(writer
, buffer
, NULL
, NULL
, 0, *heap
, (void**)output_xml
, xml_length
, NULL
);
868 if (FAILED(ret
)) goto cleanup
;
871 WSDFreeLinkedMemory(addressing_ns
);
872 WSDFreeLinkedMemory(discovery_ns
);
873 WSDFreeLinkedMemory(envelope_ns
);
875 WSDXMLCleanupElement(header_element
);
877 free_xml_string(actual_envelope_prefix
);
878 free_xml_string(envelope_uri_xmlstr
);
881 WsFreeWriter(writer
);
883 /* Don't free the heap unless the operation has failed */
884 if ((FAILED(ret
)) && (*heap
!= NULL
))
893 static HRESULT
write_and_send_message(IWSDiscoveryPublisherImpl
*impl
, WSD_SOAP_HEADER
*header
, WSDXML_ELEMENT
*body_element
,
894 struct list
*discovered_namespaces
, IWSDUdpAddress
*remote_address
, int max_initial_delay
)
896 static const char xml_header
[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
897 ULONG xml_length
= 0, xml_header_len
= sizeof(xml_header
) - 1;
898 WS_HEAP
*heap
= NULL
;
903 ret
= create_soap_envelope(impl
->xmlContext
, header
, body_element
, &heap
, &xml
, &xml_length
, discovered_namespaces
);
904 if (ret
!= S_OK
) return ret
;
906 /* Prefix the XML header */
907 full_xml
= heap_alloc(xml_length
+ xml_header_len
+ 1);
909 if (full_xml
== NULL
)
912 return E_OUTOFMEMORY
;
915 memcpy(full_xml
, xml_header
, xml_header_len
);
916 memcpy(full_xml
+ xml_header_len
, xml
, xml_length
);
917 full_xml
[xml_length
+ xml_header_len
] = 0;
919 if (remote_address
== NULL
)
921 /* Send the message via UDP multicast */
922 ret
= send_udp_multicast(impl
, full_xml
, xml_length
+ xml_header_len
, max_initial_delay
) ? S_OK
: E_FAIL
;
926 /* Send the message via UDP unicast */
927 ret
= send_udp_unicast(full_xml
, xml_length
+ xml_header_len
, remote_address
, max_initial_delay
);
936 HRESULT
send_hello_message(IWSDiscoveryPublisherImpl
*impl
, LPCWSTR id
, ULONGLONG metadata_ver
, ULONGLONG instance_id
,
937 ULONGLONG msg_num
, LPCWSTR session_id
, const WSD_NAME_LIST
*types_list
, const WSD_URI_LIST
*scopes_list
,
938 const WSD_URI_LIST
*xaddrs_list
, const WSDXML_ELEMENT
*hdr_any
, const WSDXML_ELEMENT
*ref_param_any
,
939 const WSDXML_ELEMENT
*endpoint_ref_any
, const WSDXML_ELEMENT
*any
)
941 WSDXML_ELEMENT
*body_element
= NULL
, *hello_element
, *endpoint_reference_element
, *ref_params_element
;
942 struct list
*discoveredNamespaces
= NULL
;
943 WSDXML_NAME
*body_name
= NULL
;
944 WSD_SOAP_HEADER soapHeader
;
945 WSD_APP_SEQUENCE sequence
;
946 WCHAR message_id
[64];
947 HRESULT ret
= E_OUTOFMEMORY
;
950 sequence
.InstanceId
= instance_id
;
951 sequence
.MessageNumber
= msg_num
;
952 sequence
.SequenceId
= session_id
;
954 if (!create_guid(message_id
)) goto failed
;
956 discoveredNamespaces
= WSDAllocateLinkedMemory(NULL
, sizeof(struct list
));
957 if (!discoveredNamespaces
) goto failed
;
959 list_init(discoveredNamespaces
);
961 populate_soap_header(&soapHeader
, discoveryTo
, actionHello
, message_id
, &sequence
, hdr_any
);
963 ret
= IWSDXMLContext_AddNameToNamespace(impl
->xmlContext
, envelopeNsUri
, bodyString
, &body_name
);
964 if (FAILED(ret
)) goto cleanup
;
966 /* <soap:Body>, <wsd:Hello> */
967 ret
= WSDXMLBuildAnyForSingleElement(body_name
, NULL
, &body_element
);
968 if (FAILED(ret
)) goto cleanup
;
970 ret
= add_child_element(impl
->xmlContext
, body_element
, discoveryNsUri
, helloString
, NULL
, &hello_element
);
971 if (FAILED(ret
)) goto cleanup
;
973 /* <wsa:EndpointReference>, <wsa:Address> */
974 ret
= add_child_element(impl
->xmlContext
, hello_element
, addressingNsUri
, endpointReferenceString
, NULL
,
975 &endpoint_reference_element
);
976 if (FAILED(ret
)) goto cleanup
;
978 ret
= add_child_element(impl
->xmlContext
, endpoint_reference_element
, addressingNsUri
, addressString
, id
, NULL
);
979 if (FAILED(ret
)) goto cleanup
;
981 /* Write any reference parameters */
982 if (ref_param_any
!= NULL
)
984 ret
= add_child_element(impl
->xmlContext
, endpoint_reference_element
, addressingNsUri
, referenceParametersString
,
985 NULL
, &ref_params_element
);
986 if (FAILED(ret
)) goto cleanup
;
988 ret
= duplicate_element(ref_params_element
, ref_param_any
, discoveredNamespaces
);
989 if (FAILED(ret
)) goto cleanup
;
992 /* Write any endpoint reference headers */
993 if (endpoint_ref_any
!= NULL
)
995 ret
= duplicate_element(endpoint_reference_element
, endpoint_ref_any
, discoveredNamespaces
);
996 if (FAILED(ret
)) goto cleanup
;
1000 if (types_list
!= NULL
)
1002 buffer
= WSDAllocateLinkedMemory(hello_element
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
));
1003 if (buffer
== NULL
) goto failed
;
1005 ret
= build_types_list(buffer
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
), types_list
, discoveredNamespaces
);
1006 if (FAILED(ret
)) goto cleanup
;
1008 ret
= add_child_element(impl
->xmlContext
, hello_element
, discoveryNsUri
, typesString
, buffer
, NULL
);
1009 if (FAILED(ret
)) goto cleanup
;
1013 if (scopes_list
!= NULL
)
1015 buffer
= WSDAllocateLinkedMemory(hello_element
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
));
1016 if (buffer
== NULL
) goto failed
;
1018 ret
= build_uri_list(buffer
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
), scopes_list
);
1019 if (FAILED(ret
)) goto cleanup
;
1021 ret
= add_child_element(impl
->xmlContext
, hello_element
, discoveryNsUri
, scopesString
, buffer
, NULL
);
1022 if (FAILED(ret
)) goto cleanup
;
1026 if (xaddrs_list
!= NULL
)
1028 buffer
= WSDAllocateLinkedMemory(hello_element
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
));
1029 if (buffer
== NULL
) goto failed
;
1031 ret
= build_uri_list(buffer
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
), xaddrs_list
);
1032 if (FAILED(ret
)) goto cleanup
;
1034 ret
= add_child_element(impl
->xmlContext
, hello_element
, discoveryNsUri
, xAddrsString
, buffer
, NULL
);
1035 if (FAILED(ret
)) goto cleanup
;
1038 /* <wsd:MetadataVersion> */
1039 ret
= add_child_element(impl
->xmlContext
, hello_element
, discoveryNsUri
, metadataVersionString
,
1040 ulonglong_to_string(hello_element
, min(UINT_MAX
, metadata_ver
)), NULL
);
1042 if (FAILED(ret
)) goto cleanup
;
1044 /* Write any body elements */
1047 ret
= duplicate_element(hello_element
, any
, discoveredNamespaces
);
1048 if (FAILED(ret
)) goto cleanup
;
1051 /* Write and send the message */
1052 ret
= write_and_send_message(impl
, &soapHeader
, body_element
, discoveredNamespaces
, NULL
, APP_MAX_DELAY
);
1056 ret
= E_OUTOFMEMORY
;
1059 WSDFreeLinkedMemory(body_name
);
1060 WSDFreeLinkedMemory(body_element
);
1061 WSDFreeLinkedMemory(discoveredNamespaces
);
1066 HRESULT
send_bye_message(IWSDiscoveryPublisherImpl
*impl
, LPCWSTR id
, ULONGLONG instance_id
, ULONGLONG msg_num
,
1067 LPCWSTR session_id
, const WSDXML_ELEMENT
*any
)
1069 WSDXML_ELEMENT
*body_element
= NULL
, *bye_element
, *endpoint_reference_element
;
1070 struct list
*discovered_namespaces
= NULL
;
1071 WSDXML_NAME
*body_name
= NULL
;
1072 WSD_SOAP_HEADER soap_header
;
1073 WSD_APP_SEQUENCE sequence
;
1074 WCHAR message_id
[64];
1075 HRESULT ret
= E_OUTOFMEMORY
;
1077 sequence
.InstanceId
= instance_id
;
1078 sequence
.MessageNumber
= msg_num
;
1079 sequence
.SequenceId
= session_id
;
1081 if (!create_guid(message_id
)) goto failed
;
1083 discovered_namespaces
= WSDAllocateLinkedMemory(NULL
, sizeof(struct list
));
1084 if (!discovered_namespaces
) goto failed
;
1086 list_init(discovered_namespaces
);
1088 populate_soap_header(&soap_header
, discoveryTo
, actionBye
, message_id
, &sequence
, NULL
);
1090 ret
= IWSDXMLContext_AddNameToNamespace(impl
->xmlContext
, envelopeNsUri
, bodyString
, &body_name
);
1091 if (FAILED(ret
)) goto cleanup
;
1093 /* <soap:Body>, <wsd:Bye> */
1094 ret
= WSDXMLBuildAnyForSingleElement(body_name
, NULL
, &body_element
);
1095 if (FAILED(ret
)) goto cleanup
;
1097 ret
= add_child_element(impl
->xmlContext
, body_element
, discoveryNsUri
, byeString
, NULL
, &bye_element
);
1098 if (FAILED(ret
)) goto cleanup
;
1100 /* <wsa:EndpointReference>, <wsa:Address> */
1101 ret
= add_child_element(impl
->xmlContext
, bye_element
, addressingNsUri
, endpointReferenceString
, NULL
,
1102 &endpoint_reference_element
);
1103 if (FAILED(ret
)) goto cleanup
;
1105 ret
= add_child_element(impl
->xmlContext
, endpoint_reference_element
, addressingNsUri
, addressString
, id
, NULL
);
1106 if (FAILED(ret
)) goto cleanup
;
1108 /* Write any body elements */
1111 ret
= duplicate_element(bye_element
, any
, discovered_namespaces
);
1112 if (FAILED(ret
)) goto cleanup
;
1115 /* Write and send the message */
1116 ret
= write_and_send_message(impl
, &soap_header
, body_element
, discovered_namespaces
, NULL
, 0);
1120 ret
= E_OUTOFMEMORY
;
1123 WSDFreeLinkedMemory(body_name
);
1124 WSDFreeLinkedMemory(body_element
);
1125 WSDFreeLinkedMemory(discovered_namespaces
);
1130 HRESULT
send_probe_matches_message(IWSDiscoveryPublisherImpl
*impl
, const WSD_SOAP_MESSAGE
*probe_msg
,
1131 IWSDMessageParameters
*message_params
, LPCWSTR id
, ULONGLONG metadata_ver
, ULONGLONG instance_id
,
1132 ULONGLONG msg_num
, LPCWSTR session_id
, const WSD_NAME_LIST
*types_list
, const WSD_URI_LIST
*scopes_list
,
1133 const WSD_URI_LIST
*xaddrs_list
, const WSDXML_ELEMENT
*header_any
, const WSDXML_ELEMENT
*ref_param_any
,
1134 const WSDXML_ELEMENT
*endpoint_ref_any
, const WSDXML_ELEMENT
*any
)
1136 WSDXML_ELEMENT
*body_element
= NULL
, *probe_matches_element
, *probe_match_element
, *endpoint_ref_element
;
1137 WSDXML_ELEMENT
*ref_params_element
= NULL
;
1138 struct list
*discovered_namespaces
= NULL
;
1139 IWSDUdpAddress
*remote_udp_addr
= NULL
;
1140 IWSDAddress
*remote_addr
= NULL
;
1141 WSDXML_NAME
*body_name
= NULL
;
1142 WSD_SOAP_HEADER soap_header
;
1143 WSD_APP_SEQUENCE sequence
;
1148 ret
= IWSDMessageParameters_GetRemoteAddress(message_params
, &remote_addr
);
1152 WARN("Unable to retrieve remote address from IWSDMessageParameters\n");
1156 ret
= IWSDAddress_QueryInterface(remote_addr
, &IID_IWSDUdpAddress
, (LPVOID
*) &remote_udp_addr
);
1160 WARN("Remote address is not a UDP address\n");
1164 sequence
.InstanceId
= instance_id
;
1165 sequence
.MessageNumber
= msg_num
;
1166 sequence
.SequenceId
= session_id
;
1168 if (!create_guid(msg_id
)) goto failed
;
1170 discovered_namespaces
= WSDAllocateLinkedMemory(NULL
, sizeof(struct list
));
1171 if (!discovered_namespaces
) goto failed
;
1173 list_init(discovered_namespaces
);
1175 populate_soap_header(&soap_header
, anonymousTo
, actionProbeMatches
, msg_id
, &sequence
, header_any
);
1176 soap_header
.RelatesTo
.MessageID
= probe_msg
->Header
.MessageID
;
1178 ret
= IWSDXMLContext_AddNameToNamespace(impl
->xmlContext
, envelopeNsUri
, bodyString
, &body_name
);
1179 if (FAILED(ret
)) goto cleanup
;
1181 /* <soap:Body>, <wsd:ProbeMatches> */
1182 ret
= WSDXMLBuildAnyForSingleElement(body_name
, NULL
, &body_element
);
1183 if (FAILED(ret
)) goto cleanup
;
1185 ret
= add_child_element(impl
->xmlContext
, body_element
, discoveryNsUri
, probeMatchesString
, NULL
,
1186 &probe_matches_element
);
1187 if (FAILED(ret
)) goto cleanup
;
1189 /* <wsd:ProbeMatch> */
1190 ret
= add_child_element(impl
->xmlContext
, probe_matches_element
, discoveryNsUri
, probeMatchString
, NULL
,
1191 &probe_match_element
);
1192 if (FAILED(ret
)) goto cleanup
;
1194 /* <wsa:EndpointReference>, <wsa:Address> */
1195 ret
= add_child_element(impl
->xmlContext
, probe_match_element
, addressingNsUri
, endpointReferenceString
, NULL
,
1196 &endpoint_ref_element
);
1197 if (FAILED(ret
)) goto cleanup
;
1199 ret
= add_child_element(impl
->xmlContext
, endpoint_ref_element
, addressingNsUri
, addressString
, id
, NULL
);
1200 if (FAILED(ret
)) goto cleanup
;
1202 /* Write any reference parameters */
1203 if (ref_param_any
!= NULL
)
1205 ret
= add_child_element(impl
->xmlContext
, endpoint_ref_element
, addressingNsUri
, referenceParametersString
,
1206 NULL
, &ref_params_element
);
1207 if (FAILED(ret
)) goto cleanup
;
1209 ret
= duplicate_element(ref_params_element
, ref_param_any
, discovered_namespaces
);
1210 if (FAILED(ret
)) goto cleanup
;
1213 /* Write any endpoint reference headers */
1214 if (endpoint_ref_any
!= NULL
)
1216 ret
= duplicate_element(endpoint_ref_element
, endpoint_ref_any
, discovered_namespaces
);
1217 if (FAILED(ret
)) goto cleanup
;
1221 if (types_list
!= NULL
)
1223 buffer
= WSDAllocateLinkedMemory(probe_match_element
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
));
1224 if (buffer
== NULL
) goto failed
;
1226 ret
= build_types_list(buffer
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
), types_list
, discovered_namespaces
);
1227 if (FAILED(ret
)) goto cleanup
;
1229 ret
= add_child_element(impl
->xmlContext
, probe_match_element
, discoveryNsUri
, typesString
, buffer
, NULL
);
1230 if (FAILED(ret
)) goto cleanup
;
1234 if (scopes_list
!= NULL
)
1236 buffer
= WSDAllocateLinkedMemory(probe_match_element
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
));
1237 if (buffer
== NULL
) goto failed
;
1239 ret
= build_uri_list(buffer
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
), scopes_list
);
1240 if (FAILED(ret
)) goto cleanup
;
1242 ret
= add_child_element(impl
->xmlContext
, probe_match_element
, discoveryNsUri
, scopesString
, buffer
, NULL
);
1243 if (FAILED(ret
)) goto cleanup
;
1247 if (xaddrs_list
!= NULL
)
1249 buffer
= WSDAllocateLinkedMemory(probe_match_element
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
));
1250 if (buffer
== NULL
) goto failed
;
1252 ret
= build_uri_list(buffer
, WSD_MAX_TEXT_LENGTH
* sizeof(WCHAR
), xaddrs_list
);
1253 if (FAILED(ret
)) goto cleanup
;
1255 ret
= add_child_element(impl
->xmlContext
, probe_match_element
, discoveryNsUri
, xAddrsString
, buffer
, NULL
);
1256 if (FAILED(ret
)) goto cleanup
;
1259 /* <wsd:MetadataVersion> */
1260 ret
= add_child_element(impl
->xmlContext
, probe_match_element
, discoveryNsUri
, metadataVersionString
,
1261 ulonglong_to_string(probe_match_element
, min(UINT_MAX
, metadata_ver
)), NULL
);
1262 if (FAILED(ret
)) goto cleanup
;
1264 /* Write any body elements */
1267 ret
= duplicate_element(probe_match_element
, any
, discovered_namespaces
);
1268 if (FAILED(ret
)) goto cleanup
;
1271 /* Write and send the message */
1272 ret
= write_and_send_message(impl
, &soap_header
, body_element
, discovered_namespaces
, remote_udp_addr
, APP_MAX_DELAY
);
1279 WSDFreeLinkedMemory(body_name
);
1280 WSDFreeLinkedMemory(body_element
);
1281 WSDFreeLinkedMemory(discovered_namespaces
);
1283 if (remote_udp_addr
!= NULL
) IWSDUdpAddress_Release(remote_udp_addr
);
1284 if (remote_addr
!= NULL
) IWSDAddress_Release(remote_addr
);
1289 static LPWSTR
xml_text_to_wide_string(void *parent_memory
, WS_XML_TEXT
*text
)
1291 if (text
->textType
== WS_XML_TEXT_TYPE_UTF8
)
1293 WS_XML_UTF8_TEXT
*utf8_text
= (WS_XML_UTF8_TEXT
*) text
;
1294 return utf8_to_wide(parent_memory
, (const char *) utf8_text
->value
.bytes
, utf8_text
->value
.length
);
1296 else if (text
->textType
== WS_XML_TEXT_TYPE_UTF16
)
1298 WS_XML_UTF16_TEXT
*utf_16_text
= (WS_XML_UTF16_TEXT
*) text
;
1299 return duplicate_string(parent_memory
, (LPCWSTR
) utf_16_text
->bytes
);
1302 FIXME("Support for text type %d not implemented.\n", text
->textType
);
1306 static inline BOOL
read_isspace(unsigned int ch
)
1308 return ch
== ' ' || ch
== '\t' || ch
== '\r' || ch
== '\n';
1311 static HRESULT
str_to_uint64(const unsigned char *str
, ULONG len
, UINT64 max
, UINT64
*ret
)
1313 const unsigned char *ptr
= str
;
1316 while (len
&& read_isspace(*ptr
)) { ptr
++; len
--; }
1317 while (len
&& read_isspace(ptr
[len
- 1])) { len
--; }
1318 if (!len
) return WS_E_INVALID_FORMAT
;
1324 if (!isdigit(*ptr
)) return WS_E_INVALID_FORMAT
;
1327 if ((*ret
> max
/ 10 || *ret
* 10 > max
- val
)) return WS_E_NUMERIC_OVERFLOW
;
1328 *ret
= *ret
* 10 + val
;
1335 #define MAX_UINT64 (((UINT64)0xffffffff << 32) | 0xffffffff)
1337 static HRESULT
wide_text_to_ulonglong(LPCWSTR text
, ULONGLONG
*value
)
1343 utf8_text
= wide_to_utf8(text
, &utf8_length
);
1345 if (utf8_text
== NULL
) return E_OUTOFMEMORY
;
1346 if (utf8_length
== 1) return E_FAIL
;
1348 ret
= str_to_uint64((const unsigned char *) utf8_text
, utf8_length
- 1, MAX_UINT64
, value
);
1349 heap_free(utf8_text
);
1354 static HRESULT
move_to_element(WS_XML_READER
*reader
, const char *element_name
, WS_XML_STRING
*uri
)
1356 WS_XML_STRING envelope
;
1360 envelope
.bytes
= (BYTE
*) element_name
;
1361 envelope
.length
= strlen(element_name
);
1362 envelope
.dictionary
= NULL
;
1365 ret
= WsReadToStartElement(reader
, &envelope
, uri
, &found
, NULL
);
1366 if (FAILED(ret
)) return ret
;
1368 return found
? ret
: E_FAIL
;
1371 static void trim_trailing_slash(LPWSTR uri
)
1373 /* Trim trailing slash from URI */
1374 int uri_len
= lstrlenW(uri
);
1375 if (uri_len
> 0 && uri
[uri_len
- 1] == '/') uri
[uri_len
- 1] = 0;
1378 static HRESULT
ws_element_to_wsdxml_element(WS_XML_READER
*reader
, IWSDXMLContext
*context
, WSDXML_ELEMENT
*parent_element
)
1380 WSDXML_ATTRIBUTE
*cur_wsd_attrib
= NULL
, *new_wsd_attrib
= NULL
;
1381 const WS_XML_ELEMENT_NODE
*element_node
= NULL
;
1382 WSDXML_ELEMENT
*cur_element
= parent_element
;
1383 const WS_XML_TEXT_NODE
*text_node
= NULL
;
1384 LPWSTR uri
= NULL
, element_name
= NULL
;
1385 WS_XML_STRING
*ns_string
= NULL
;
1386 WS_XML_ATTRIBUTE
*attrib
= NULL
;
1387 WSDXML_ELEMENT
*element
= NULL
;
1388 const WS_XML_NODE
*node
= NULL
;
1389 WSDXML_NAME
*name
= NULL
;
1390 WSDXML_TEXT
*text
= NULL
;
1396 if (cur_element
== NULL
) break;
1398 ret
= WsReadNode(reader
, NULL
);
1399 if (FAILED(ret
)) goto cleanup
;
1401 ret
= WsGetReaderNode(reader
, &node
, NULL
);
1402 if (FAILED(ret
)) goto cleanup
;
1404 switch (node
->nodeType
)
1406 case WS_XML_NODE_TYPE_ELEMENT
:
1407 element_node
= (const WS_XML_ELEMENT_NODE
*) node
;
1409 uri
= utf8_to_wide(NULL
, (const char *) element_node
->ns
->bytes
, element_node
->ns
->length
);
1410 if (uri
== NULL
) goto outofmemory
;
1412 /* Link element_name to uri so they will be freed at the same time */
1413 element_name
= utf8_to_wide(uri
, (const char *) element_node
->localName
->bytes
,
1414 element_node
->localName
->length
);
1415 if (element_name
== NULL
) goto outofmemory
;
1417 trim_trailing_slash(uri
);
1419 ret
= IWSDXMLContext_AddNameToNamespace(context
, uri
, element_name
, &name
);
1420 if (FAILED(ret
)) goto cleanup
;
1422 WSDFreeLinkedMemory(uri
);
1425 ret
= WSDXMLBuildAnyForSingleElement(name
, NULL
, &element
);
1426 if (FAILED(ret
)) goto cleanup
;
1427 WSDXMLAddChild(cur_element
, element
);
1429 cur_wsd_attrib
= NULL
;
1431 /* Add attributes */
1432 for (i
= 0; i
< element_node
->attributeCount
; i
++)
1434 attrib
= element_node
->attributes
[i
];
1435 if (attrib
->isXmlNs
) continue;
1437 new_wsd_attrib
= WSDAllocateLinkedMemory(element
, sizeof(WSDXML_ATTRIBUTE
));
1438 if (new_wsd_attrib
== NULL
) goto outofmemory
;
1440 ns_string
= attrib
->ns
;
1441 if (ns_string
->length
== 0) ns_string
= element_node
->ns
;
1443 uri
= utf8_to_wide(NULL
, (const char *) ns_string
->bytes
, ns_string
->length
);
1444 if (uri
== NULL
) goto outofmemory
;
1446 trim_trailing_slash(uri
);
1448 /* Link element_name to uri so they will be freed at the same time */
1449 element_name
= utf8_to_wide(uri
, (const char *) attrib
->localName
->bytes
, attrib
->localName
->length
);
1450 if (element_name
== NULL
) goto outofmemory
;
1452 ret
= IWSDXMLContext_AddNameToNamespace(context
, uri
, element_name
, &name
);
1453 if (FAILED(ret
)) goto cleanup
;
1455 WSDFreeLinkedMemory(uri
);
1458 new_wsd_attrib
->Value
= xml_text_to_wide_string(new_wsd_attrib
, attrib
->value
);
1459 if (new_wsd_attrib
->Value
== NULL
) goto outofmemory
;
1461 new_wsd_attrib
->Name
= name
;
1462 new_wsd_attrib
->Element
= cur_element
;
1463 new_wsd_attrib
->Next
= NULL
;
1465 if (cur_wsd_attrib
== NULL
)
1466 element
->FirstAttribute
= new_wsd_attrib
;
1468 cur_wsd_attrib
->Next
= new_wsd_attrib
;
1470 cur_wsd_attrib
= new_wsd_attrib
;
1473 cur_element
= element
;
1476 case WS_XML_NODE_TYPE_TEXT
:
1477 text_node
= (const WS_XML_TEXT_NODE
*) node
;
1479 if (cur_element
== NULL
)
1481 WARN("No parent element open but encountered text element!\n");
1485 if (cur_element
->FirstChild
!= NULL
)
1487 WARN("Text node encountered but parent already has child!\n");
1491 text
= WSDAllocateLinkedMemory(element
, sizeof(WSDXML_TEXT
));
1492 if (text
== NULL
) goto outofmemory
;
1494 text
->Node
.Parent
= element
;
1495 text
->Node
.Next
= NULL
;
1496 text
->Node
.Type
= TextType
;
1497 text
->Text
= xml_text_to_wide_string(text
, text_node
->text
);
1499 if (text
->Text
== NULL
)
1501 WARN("Text node returned null string.\n");
1502 WSDFreeLinkedMemory(text
);
1506 cur_element
->FirstChild
= (WSDXML_NODE
*) text
;
1509 case WS_XML_NODE_TYPE_END_ELEMENT
:
1510 /* Go up a level to the parent element */
1511 cur_element
= cur_element
->Node
.Parent
;
1522 ret
= E_OUTOFMEMORY
;
1525 /* Free uri and element_name if applicable */
1526 WSDFreeLinkedMemory(uri
);
1530 static WSDXML_ELEMENT
*find_element(WSDXML_ELEMENT
*parent
, LPCWSTR name
, LPCWSTR ns_uri
)
1532 WSDXML_ELEMENT
*cur
= (WSDXML_ELEMENT
*) parent
->FirstChild
;
1536 if ((lstrcmpW(cur
->Name
->LocalName
, name
) == 0) && (lstrcmpW(cur
->Name
->Space
->Uri
, ns_uri
) == 0))
1539 cur
= (WSDXML_ELEMENT
*) cur
->Node
.Next
;
1545 static void remove_element(WSDXML_ELEMENT
*element
)
1549 if (element
== NULL
)
1552 if (element
->Node
.Parent
->FirstChild
== (WSDXML_NODE
*) element
)
1553 element
->Node
.Parent
->FirstChild
= element
->Node
.Next
;
1556 cur
= element
->Node
.Parent
->FirstChild
;
1560 if (cur
->Next
== (WSDXML_NODE
*) element
)
1562 cur
->Next
= element
->Node
.Next
;
1570 WSDDetachLinkedMemory(element
);
1571 WSDFreeLinkedMemory(element
);
1574 static WSD_NAME_LIST
*build_types_list_from_string(IWSDXMLContext
*context
, LPCWSTR buffer
, void *parent
)
1576 WSD_NAME_LIST
*list
= NULL
, *cur_list
= NULL
, *prev_list
= NULL
;
1577 LPWSTR name_start
= NULL
, temp_buffer
= NULL
;
1578 LPCWSTR prefix_start
= buffer
;
1579 WSDXML_NAMESPACE
*ns
;
1586 temp_buffer
= duplicate_string(parent
, buffer
);
1587 if (temp_buffer
== NULL
) goto cleanup
;
1589 buffer_len
= lstrlenW(temp_buffer
);
1591 list
= WSDAllocateLinkedMemory(parent
, sizeof(WSD_NAME_LIST
));
1592 if (list
== NULL
) goto cleanup
;
1594 ZeroMemory(list
, sizeof(WSD_NAME_LIST
));
1595 prefix_start
= temp_buffer
;
1597 for (i
= 0; i
< buffer_len
; i
++)
1599 if (temp_buffer
[i
] == ':')
1602 name_start
= &temp_buffer
[i
+ 1];
1604 else if ((temp_buffer
[i
] == ' ') || (i
== buffer_len
- 1))
1606 WSDXML_NAMESPACE
*known_ns
;
1608 if (temp_buffer
[i
] == ' ')
1611 if (cur_list
== NULL
)
1615 cur_list
= WSDAllocateLinkedMemory(parent
, sizeof(WSD_NAME_LIST
));
1616 if (cur_list
== NULL
) goto cleanup
;
1618 prev_list
->Next
= cur_list
;
1621 name
= WSDAllocateLinkedMemory(cur_list
, sizeof(WSDXML_NAME
));
1622 if (name
== NULL
) goto cleanup
;
1624 ns
= WSDAllocateLinkedMemory(cur_list
, sizeof(WSDXML_NAMESPACE
));
1625 if (ns
== NULL
) goto cleanup
;
1627 ZeroMemory(ns
, sizeof(WSDXML_NAMESPACE
));
1628 ns
->PreferredPrefix
= duplicate_string(ns
, prefix_start
);
1630 known_ns
= xml_context_find_namespace_by_prefix(context
, ns
->PreferredPrefix
);
1632 if (known_ns
!= NULL
)
1633 ns
->Uri
= duplicate_string(ns
, known_ns
->Uri
);
1636 name
->LocalName
= duplicate_string(name
, name_start
);
1638 cur_list
->Element
= name
;
1639 prefix_start
= &temp_buffer
[i
+ 1];
1644 WSDFreeLinkedMemory(temp_buffer
);
1648 WSDFreeLinkedMemory(list
);
1649 WSDFreeLinkedMemory(temp_buffer
);
1654 static WSDXML_TYPE
*generate_type(LPCWSTR uri
, void *parent
)
1656 WSDXML_TYPE
*type
= WSDAllocateLinkedMemory(parent
, sizeof(WSDXML_TYPE
));
1661 type
->Uri
= duplicate_string(parent
, uri
);
1667 static BOOL
is_duplicate_message(IWSDiscoveryPublisherImpl
*impl
, LPCWSTR id
)
1669 struct message_id
*msg_id
, *msg_id_cursor
;
1673 EnterCriticalSection(&impl
->message_ids_critical_section
);
1675 LIST_FOR_EACH_ENTRY_SAFE(msg_id
, msg_id_cursor
, &impl
->message_ids
, struct message_id
, entry
)
1677 if (lstrcmpW(msg_id
->id
, id
) == 0)
1684 msg_id
= heap_alloc(sizeof(*msg_id
));
1685 if (!msg_id
) goto end
;
1687 len
= (lstrlenW(id
) + 1) * sizeof(WCHAR
);
1688 msg_id
->id
= heap_alloc(len
);
1696 memcpy(msg_id
->id
, id
, len
);
1697 list_add_tail(&impl
->message_ids
, &msg_id
->entry
);
1700 LeaveCriticalSection(&impl
->message_ids_critical_section
);
1704 HRESULT
read_message(IWSDiscoveryPublisherImpl
*impl
, const char *xml
, int xml_length
, WSD_SOAP_MESSAGE
**out_msg
, int *msg_type
)
1706 WSDXML_ELEMENT
*envelope
= NULL
, *header_element
, *appsequence_element
, *body_element
;
1707 WS_XML_READER_TEXT_ENCODING encoding
;
1708 WS_XML_ELEMENT_NODE
*envelope_node
;
1709 WSD_SOAP_MESSAGE
*soap_msg
= NULL
;
1710 WS_XML_READER_BUFFER_INPUT input
;
1711 WS_XML_ATTRIBUTE
*attrib
= NULL
;
1712 IWSDXMLContext
*context
= NULL
;
1713 WS_XML_STRING
*soap_uri
= NULL
;
1714 const WS_XML_NODE
*node
;
1715 WS_XML_READER
*reader
;
1716 LPCWSTR value
= NULL
;
1722 *msg_type
= MSGTYPE_UNKNOWN
;
1724 ret
= WsCreateHeap(16384, 4096, NULL
, 0, &heap
, NULL
);
1725 if (FAILED(ret
)) goto cleanup
;
1727 ret
= WsCreateReader(NULL
, 0, &reader
, NULL
);
1728 if (FAILED(ret
)) goto cleanup
;
1730 encoding
.encoding
.encodingType
= WS_XML_READER_ENCODING_TYPE_TEXT
;
1731 encoding
.charSet
= WS_CHARSET_AUTO
;
1733 input
.input
.inputType
= WS_XML_READER_INPUT_TYPE_BUFFER
;
1734 input
.encodedData
= (char *) xml
;
1735 input
.encodedDataSize
= xml_length
;
1737 ret
= WsSetInput(reader
, (WS_XML_READER_ENCODING
*) &encoding
, (WS_XML_READER_INPUT
*) &input
, NULL
, 0, NULL
);
1738 if (FAILED(ret
)) goto cleanup
;
1740 soap_uri
= populate_xml_string(envelopeNsUri
);
1741 if (soap_uri
== NULL
) goto outofmemory
;
1743 ret
= move_to_element(reader
, "Envelope", soap_uri
);
1744 if (FAILED(ret
)) goto cleanup
;
1746 ret
= WsGetReaderNode(reader
, &node
, NULL
);
1747 if (FAILED(ret
)) goto cleanup
;
1749 if (node
->nodeType
!= WS_XML_NODE_TYPE_ELEMENT
)
1751 WARN("Unexpected node type (%d)\n", node
->nodeType
);
1756 envelope_node
= (WS_XML_ELEMENT_NODE
*) node
;
1758 ret
= WSDXMLCreateContext(&context
);
1759 if (FAILED(ret
)) goto cleanup
;
1761 /* Find XML namespaces from the envelope element's attributes */
1762 for (i
= 0; i
< envelope_node
->attributeCount
; i
++)
1764 attrib
= envelope_node
->attributes
[i
];
1766 if (attrib
->isXmlNs
)
1768 uri
= utf8_to_wide(NULL
, (const char *) attrib
->ns
->bytes
, attrib
->ns
->length
);
1769 if (uri
== NULL
) continue;
1771 trim_trailing_slash(uri
);
1773 prefix
= utf8_to_wide(uri
, (const char *) attrib
->localName
->bytes
, attrib
->localName
->length
);
1777 WSDFreeLinkedMemory(uri
);
1781 IWSDXMLContext_AddNamespace(context
, uri
, prefix
, NULL
);
1782 WSDFreeLinkedMemory(uri
);
1786 /* Create the SOAP message to return to the caller */
1787 soap_msg
= WSDAllocateLinkedMemory(NULL
, sizeof(WSD_SOAP_MESSAGE
));
1788 if (soap_msg
== NULL
) goto outofmemory
;
1790 ZeroMemory(soap_msg
, sizeof(WSD_SOAP_MESSAGE
));
1792 envelope
= WSDAllocateLinkedMemory(soap_msg
, sizeof(WSDXML_ELEMENT
));
1793 if (envelope
== NULL
) goto outofmemory
;
1795 ZeroMemory(envelope
, sizeof(WSDXML_ELEMENT
));
1797 ret
= ws_element_to_wsdxml_element(reader
, context
, envelope
);
1798 if (FAILED(ret
)) goto cleanup
;
1800 /* Find the header element */
1801 header_element
= find_element(envelope
, headerString
, envelopeNsUri
);
1803 if (header_element
== NULL
)
1805 WARN("Unable to find header element in received SOAP message\n");
1810 ret
= WSDXMLGetValueFromAny(addressingNsUri
, actionString
, (WSDXML_ELEMENT
*) header_element
->FirstChild
, &value
);
1811 if (FAILED(ret
)) goto cleanup
;
1812 soap_msg
->Header
.Action
= duplicate_string(soap_msg
, value
);
1813 if (soap_msg
->Header
.Action
== NULL
) goto outofmemory
;
1815 ret
= WSDXMLGetValueFromAny(addressingNsUri
, toString
, (WSDXML_ELEMENT
*) header_element
->FirstChild
, &value
);
1816 if (FAILED(ret
)) goto cleanup
;
1817 soap_msg
->Header
.To
= duplicate_string(soap_msg
, value
);
1818 if (soap_msg
->Header
.To
== NULL
) goto outofmemory
;
1820 ret
= WSDXMLGetValueFromAny(addressingNsUri
, messageIdString
, (WSDXML_ELEMENT
*) header_element
->FirstChild
, &value
);
1821 if (FAILED(ret
)) goto cleanup
;
1823 /* Detect duplicate messages */
1824 if (is_duplicate_message(impl
, value
))
1830 soap_msg
->Header
.MessageID
= duplicate_string(soap_msg
, value
);
1831 if (soap_msg
->Header
.MessageID
== NULL
) goto outofmemory
;
1833 /* Look for optional AppSequence element */
1834 appsequence_element
= find_element(header_element
, appSequenceString
, discoveryNsUri
);
1836 if (appsequence_element
!= NULL
)
1838 WSDXML_ATTRIBUTE
*current_attrib
;
1840 soap_msg
->Header
.AppSequence
= WSDAllocateLinkedMemory(soap_msg
, sizeof(WSD_APP_SEQUENCE
));
1841 if (soap_msg
->Header
.AppSequence
== NULL
) goto outofmemory
;
1843 ZeroMemory(soap_msg
->Header
.AppSequence
, sizeof(WSD_APP_SEQUENCE
));
1845 current_attrib
= appsequence_element
->FirstAttribute
;
1847 while (current_attrib
!= NULL
)
1849 if (lstrcmpW(current_attrib
->Name
->Space
->Uri
, discoveryNsUri
) != 0)
1851 current_attrib
= current_attrib
->Next
;
1855 if (lstrcmpW(current_attrib
->Name
->LocalName
, instanceIdString
) == 0)
1857 ret
= wide_text_to_ulonglong(current_attrib
->Value
, &soap_msg
->Header
.AppSequence
->InstanceId
);
1858 if (FAILED(ret
)) goto cleanup
;
1860 else if (lstrcmpW(current_attrib
->Name
->LocalName
, messageNumberString
) == 0)
1862 ret
= wide_text_to_ulonglong(current_attrib
->Value
, &soap_msg
->Header
.AppSequence
->MessageNumber
);
1863 if (FAILED(ret
)) goto cleanup
;
1865 else if (lstrcmpW(current_attrib
->Name
->LocalName
, sequenceIdString
) == 0)
1867 soap_msg
->Header
.AppSequence
->SequenceId
= duplicate_string(soap_msg
, current_attrib
->Value
);
1868 if (soap_msg
->Header
.AppSequence
->SequenceId
== NULL
) goto outofmemory
;
1871 current_attrib
= current_attrib
->Next
;
1875 /* Now detach and free known headers to leave the "any" elements */
1876 remove_element(find_element(header_element
, actionString
, addressingNsUri
));
1877 remove_element(find_element(header_element
, toString
, addressingNsUri
));
1878 remove_element(find_element(header_element
, messageIdString
, addressingNsUri
));
1879 remove_element(find_element(header_element
, appSequenceString
, discoveryNsUri
));
1881 soap_msg
->Header
.AnyHeaders
= (WSDXML_ELEMENT
*) header_element
->FirstChild
;
1883 if (soap_msg
->Header
.AnyHeaders
!= NULL
)
1884 soap_msg
->Header
.AnyHeaders
->Node
.Parent
= NULL
;
1886 /* Find the body element */
1887 body_element
= find_element(envelope
, bodyString
, envelopeNsUri
);
1889 if (body_element
== NULL
)
1891 WARN("Unable to find body element in received SOAP message\n");
1896 /* Now figure out which message we've been sent */
1897 if (lstrcmpW(soap_msg
->Header
.Action
, actionProbe
) == 0)
1899 WSDXML_ELEMENT
*probe_element
;
1900 WSD_PROBE
*probe
= NULL
;
1902 probe_element
= find_element(body_element
, probeString
, discoveryNsUri
);
1903 if (probe_element
== NULL
) goto cleanup
;
1905 probe
= WSDAllocateLinkedMemory(soap_msg
, sizeof(WSD_PROBE
));
1906 if (probe
== NULL
) goto cleanup
;
1908 ZeroMemory(probe
, sizeof(WSD_PROBE
));
1910 /* Check for the "types" element */
1911 ret
= WSDXMLGetValueFromAny(discoveryNsUri
, typesString
, (WSDXML_ELEMENT
*) probe_element
->FirstChild
, &value
);
1915 WARN("Unable to find Types element in received Probe message\n");
1919 probe
->Types
= build_types_list_from_string(context
, value
, probe
);
1921 /* Now detach and free known headers to leave the "any" elements */
1922 remove_element(find_element(probe_element
, typesString
, discoveryNsUri
));
1923 remove_element(find_element(probe_element
, scopesString
, discoveryNsUri
));
1925 probe
->Any
= (WSDXML_ELEMENT
*) probe_element
->FirstChild
;
1927 if (probe
->Any
!= NULL
)
1928 probe
->Any
->Node
.Parent
= NULL
;
1930 soap_msg
->Body
= probe
;
1931 soap_msg
->BodyType
= generate_type(actionProbe
, soap_msg
);
1932 if (soap_msg
->BodyType
== NULL
) goto cleanup
;
1934 *out_msg
= soap_msg
;
1935 soap_msg
= NULL
; /* caller will clean this up */
1936 *msg_type
= MSGTYPE_PROBE
;
1942 ret
= E_OUTOFMEMORY
;
1945 free_xml_string(soap_uri
);
1946 WSDFreeLinkedMemory(soap_msg
);
1947 if (context
!= NULL
) IWSDXMLContext_Release(context
);