wevtapi: Fix typo in spec file.
[wine/zf.git] / dlls / wsdapi / soap.c
blobe1233986cc3f4a91e996c5f42fd8c25d6e0b098f
1 /*
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
21 #include <stdarg.h>
22 #include <limits.h>
24 #define COBJMACROS
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[] = {
36 'u','r','n',':',
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','/',
46 'r','o','l','e','/',
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','/',
75 'B','y','e', 0 };
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
121 struct list entry;
122 LPCWSTR prefix;
123 LPCWSTR uri;
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;
144 return new_str;
147 static char *wide_to_utf8(LPCWSTR wide_string, int *length)
149 char *new_string = NULL;
151 if (wide_string == NULL)
152 return NULL;
154 *length = WideCharToMultiByte(CP_UTF8, 0, wide_string, -1, NULL, 0, NULL, NULL);
156 if (*length < 0)
157 return NULL;
159 new_string = heap_alloc(*length);
160 WideCharToMultiByte(CP_UTF8, 0, wide_string, -1, new_string, *length, NULL, NULL);
162 return new_string;
165 static WS_XML_STRING *populate_xml_string(LPCWSTR str)
167 WS_XML_STRING *xml = heap_alloc_zero(sizeof(WS_XML_STRING));
168 int utf8Length;
170 if (xml == NULL)
171 return NULL;
173 xml->bytes = (BYTE *)wide_to_utf8(str, &utf8Length);
175 if (xml->bytes == NULL)
177 heap_free(xml);
178 return NULL;
181 xml->dictionary = NULL;
182 xml->id = 0;
183 xml->length = (xml->bytes == NULL) ? 0 : (utf8Length - 1);
185 return xml;
188 static inline void free_xml_string(WS_XML_STRING *value)
190 if (value == NULL)
191 return;
193 heap_free(value->bytes);
195 heap_free(value);
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;
203 int text_len;
205 if (attribute == NULL)
206 return S_OK;
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;
217 ns_prefix = NULL;
219 else
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;
243 cleanup:
244 free_xml_string(local_name);
245 free_xml_string(element_ns);
246 free_xml_string(ns_prefix);
248 return ret;
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;
258 int text_len;
259 HRESULT ret = E_OUTOFMEMORY;
261 if (element == NULL)
262 return S_OK;
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);
316 cleanup:
317 free_xml_string(local_name);
318 free_xml_string(element_ns);
319 free_xml_string(ns_prefix);
321 return ret;
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;
329 HRESULT ret;
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);
342 if (FAILED(ret))
344 WSDFreeLinkedMemory(element_obj);
345 return ret;
348 if (out != NULL) *out = element_obj;
349 return ret;
352 HRESULT register_namespaces(IWSDXMLContext *xml_context)
354 HRESULT ret;
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;
370 UUID uuid;
372 if (UuidCreate(&uuid) != RPC_S_OK)
373 return FALSE;
375 UuidToStringW(&uuid, (RPC_WSTR*)&uuidString);
377 if (uuidString == NULL)
378 return FALSE;
380 wsprintfW(buffer, formatString, uuidString);
381 RpcStringFreeW((RPC_WSTR*)&uuidString);
383 return TRUE;
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));
391 header->To = to;
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 };
405 LPWSTR ret;
407 ret = WSDAllocateLinkedMemory(parent, MAX_ULONGLONG_STRING_SIZE * sizeof(WCHAR));
409 if (ret == NULL)
410 return NULL;
412 wsprintfW(ret, formatString, value);
413 return ret;
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;
421 if (ns_uri == NULL)
423 name_obj = WSDAllocateLinkedMemory(NULL, sizeof(WSDXML_NAME));
424 name_obj->LocalName = duplicate_string(name_obj, name);
425 name_obj->Space = NULL;
427 else
429 if (FAILED(IWSDXMLContext_AddNameToNamespace(xml_context, ns_uri, name, &name_obj)))
430 return NULL;
433 attribute = WSDAllocateLinkedMemory(parent, sizeof(WSDXML_ATTRIBUTE));
435 if (attribute == NULL)
437 WSDFreeLinkedMemory(name_obj);
438 return NULL;
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;
454 else
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;
467 return 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;
479 else
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;
488 break;
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,
499 ULONGLONG value)
501 WSDXML_ATTRIBUTE *attribute = add_attribute(xml_context, parent, ns_uri, name);
503 if (attribute == NULL)
504 return E_FAIL;
506 attribute->Value = ulonglong_to_string(attribute, value);
508 if (attribute->Value == NULL)
510 remove_attribute(parent, attribute);
511 return E_FAIL;
514 return S_OK;
517 static HRESULT add_string_attribute(IWSDXMLContext *xml_context, WSDXML_ELEMENT *parent, LPCWSTR ns_uri, LPCWSTR name,
518 LPCWSTR value)
520 WSDXML_ATTRIBUTE *attribute = add_attribute(xml_context, parent, ns_uri, name);
522 if (attribute == NULL)
523 return E_FAIL;
525 attribute->Value = duplicate_string(attribute, value);
527 if (attribute->Value == NULL)
529 remove_attribute(parent, attribute);
530 return E_FAIL;
533 return S_OK;
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));
548 if (ns == NULL)
549 return FALSE;
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))
555 return FALSE;
557 list_add_tail(namespaces, &ns->entry);
558 return TRUE;
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)
575 return E_INVALIDARG;
577 if (cur != list)
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))
585 return E_FAIL;
587 cur = cur->Next;
588 } while (cur != NULL);
590 return S_OK;
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)
606 return E_INVALIDARG;
608 if (cur != list)
609 *cur_buf_pos++ = ' ';
611 memcpy(cur_buf_pos, cur->Element, memory_needed);
612 cur_buf_pos += string_len;
614 cur = cur->Next;
615 } while (cur != NULL);
617 return S_OK;
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;
626 HRESULT ret;
628 /* First record the namespace in the discovered namespaces list */
629 if (!add_discovered_namespace(namespaces, node->Name->Space))
630 return E_FAIL;
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)))
670 goto failed;
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;
684 else
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;
694 return ret;
696 failed:
697 ret = E_FAIL;
699 cleanup:
700 WSDXMLCleanupElement(new_element);
701 return ret;
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;
709 HRESULT ret;
711 /* <s:Header> */
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);
720 /* <a:Action> */
721 ret = add_child_element(xml_context, header_element, addressingNsUri, actionString, header->Action, &temp_element);
722 if (FAILED(ret)) goto cleanup;
724 /* <a:MessageId> */
725 ret = add_child_element(xml_context, header_element, addressingNsUri, messageIdString, header->MessageID, &temp_element);
726 if (FAILED(ret)) goto cleanup;
728 /* <a:To> */
729 ret = add_child_element(xml_context, header_element, addressingNsUri, toString, header->To, &temp_element);
730 if (FAILED(ret)) goto cleanup;
732 /* <a:RelatesTo> */
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;
770 /* </s:Header> */
772 *out_element = header_element;
773 return ret;
775 cleanup:
776 if (header_name != NULL) WSDFreeLinkedMemory(header_name);
777 WSDXMLCleanupElement(header_element);
779 return ret;
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;
808 envelope.id = 0;
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;
832 /* <s:Envelope> */
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);
850 tmp_prefix = NULL;
851 tmp_uri = NULL;
853 /* Write the header */
854 ret = write_xml_element(header_element, writer);
855 if (FAILED(ret)) goto cleanup;
857 /* Write the body */
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;
864 /* </s:Envelope> */
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;
870 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);
880 if (writer != NULL)
881 WsFreeWriter(writer);
883 /* Don't free the heap unless the operation has failed */
884 if ((FAILED(ret)) && (*heap != NULL))
886 WsFreeHeap(*heap);
887 *heap = NULL;
890 return ret;
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;
899 char *xml = NULL;
900 char *full_xml;
901 HRESULT ret;
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)
911 WsFreeHeap(heap);
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;
924 else
926 /* Send the message via UDP unicast */
927 ret = send_udp_unicast(full_xml, xml_length + xml_header_len, remote_address, max_initial_delay);
930 heap_free(full_xml);
931 WsFreeHeap(heap);
933 return ret;
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;
948 LPWSTR buffer;
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;
999 /* <wsd:Types> */
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;
1012 /* <wsd:Scopes> */
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;
1025 /* <wsd:XAddrs> */
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 */
1045 if (any != NULL)
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);
1053 goto cleanup;
1055 failed:
1056 ret = E_OUTOFMEMORY;
1058 cleanup:
1059 WSDFreeLinkedMemory(body_name);
1060 WSDFreeLinkedMemory(body_element);
1061 WSDFreeLinkedMemory(discoveredNamespaces);
1063 return ret;
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 */
1109 if (any != NULL)
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);
1117 goto cleanup;
1119 failed:
1120 ret = E_OUTOFMEMORY;
1122 cleanup:
1123 WSDFreeLinkedMemory(body_name);
1124 WSDFreeLinkedMemory(body_element);
1125 WSDFreeLinkedMemory(discovered_namespaces);
1127 return ret;
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;
1144 WCHAR msg_id[64];
1145 LPWSTR buffer;
1146 HRESULT ret;
1148 ret = IWSDMessageParameters_GetRemoteAddress(message_params, &remote_addr);
1150 if (FAILED(ret))
1152 WARN("Unable to retrieve remote address from IWSDMessageParameters\n");
1153 return ret;
1156 ret = IWSDAddress_QueryInterface(remote_addr, &IID_IWSDUdpAddress, (LPVOID *) &remote_udp_addr);
1158 if (FAILED(ret))
1160 WARN("Remote address is not a UDP address\n");
1161 goto cleanup;
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;
1220 /* <wsd:Types> */
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;
1233 /* <wsd:Scopes> */
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;
1246 /* <wsd:XAddrs> */
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 */
1265 if (any != NULL)
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);
1273 goto cleanup;
1275 failed:
1276 ret = E_FAIL;
1278 cleanup:
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);
1286 return ret;
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);
1303 return NULL;
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;
1315 *ret = 0;
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;
1320 while (len--)
1322 unsigned int val;
1324 if (!isdigit(*ptr)) return WS_E_INVALID_FORMAT;
1325 val = *ptr - '0';
1327 if ((*ret > max / 10 || *ret * 10 > max - val)) return WS_E_NUMERIC_OVERFLOW;
1328 *ret = *ret * 10 + val;
1329 ptr++;
1332 return S_OK;
1335 #define MAX_UINT64 (((UINT64)0xffffffff << 32) | 0xffffffff)
1337 static HRESULT wide_text_to_ulonglong(LPCWSTR text, ULONGLONG *value)
1339 char *utf8_text;
1340 int utf8_length;
1341 HRESULT ret;
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);
1351 return ret;
1354 static HRESULT move_to_element(WS_XML_READER *reader, const char *element_name, WS_XML_STRING *uri)
1356 WS_XML_STRING envelope;
1357 BOOL found = FALSE;
1358 HRESULT ret;
1360 envelope.bytes = (BYTE *) element_name;
1361 envelope.length = strlen(element_name);
1362 envelope.dictionary = NULL;
1363 envelope.id = 0;
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;
1391 HRESULT ret;
1392 int i;
1394 for (;;)
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);
1423 uri = NULL;
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);
1456 uri = NULL;
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;
1467 else
1468 cur_wsd_attrib->Next = new_wsd_attrib;
1470 cur_wsd_attrib = new_wsd_attrib;
1473 cur_element = element;
1474 break;
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");
1482 continue;
1485 if (cur_element->FirstChild != NULL)
1487 WARN("Text node encountered but parent already has child!\n");
1488 continue;
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);
1503 continue;
1506 cur_element->FirstChild = (WSDXML_NODE *) text;
1507 break;
1509 case WS_XML_NODE_TYPE_END_ELEMENT:
1510 /* Go up a level to the parent element */
1511 cur_element = cur_element->Node.Parent;
1512 break;
1514 default:
1515 break;
1519 return S_OK;
1521 outofmemory:
1522 ret = E_OUTOFMEMORY;
1524 cleanup:
1525 /* Free uri and element_name if applicable */
1526 WSDFreeLinkedMemory(uri);
1527 return ret;
1530 static WSDXML_ELEMENT *find_element(WSDXML_ELEMENT *parent, LPCWSTR name, LPCWSTR ns_uri)
1532 WSDXML_ELEMENT *cur = (WSDXML_ELEMENT *) parent->FirstChild;
1534 while (cur != NULL)
1536 if ((lstrcmpW(cur->Name->LocalName, name) == 0) && (lstrcmpW(cur->Name->Space->Uri, ns_uri) == 0))
1537 return cur;
1539 cur = (WSDXML_ELEMENT *) cur->Node.Next;
1542 return NULL;
1545 static void remove_element(WSDXML_ELEMENT *element)
1547 WSDXML_NODE *cur;
1549 if (element == NULL)
1550 return;
1552 if (element->Node.Parent->FirstChild == (WSDXML_NODE *) element)
1553 element->Node.Parent->FirstChild = element->Node.Next;
1554 else
1556 cur = element->Node.Parent->FirstChild;
1558 while (cur != NULL)
1560 if (cur->Next == (WSDXML_NODE *) element)
1562 cur->Next = element->Node.Next;
1563 break;
1566 cur = cur->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;
1580 WSDXML_NAME *name;
1581 int buffer_len, i;
1583 if (buffer == NULL)
1584 return NULL;
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] == ':')
1601 temp_buffer[i] = 0;
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] == ' ')
1609 temp_buffer[i] = 0;
1611 if (cur_list == NULL)
1612 cur_list = list;
1613 else
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);
1635 name->Space = ns;
1636 name->LocalName = duplicate_string(name, name_start);
1638 cur_list->Element = name;
1639 prefix_start = &temp_buffer[i + 1];
1640 name_start = NULL;
1644 WSDFreeLinkedMemory(temp_buffer);
1645 return list;
1647 cleanup:
1648 WSDFreeLinkedMemory(list);
1649 WSDFreeLinkedMemory(temp_buffer);
1651 return NULL;
1654 static WSDXML_TYPE *generate_type(LPCWSTR uri, void *parent)
1656 WSDXML_TYPE *type = WSDAllocateLinkedMemory(parent, sizeof(WSDXML_TYPE));
1658 if (type == NULL)
1659 return NULL;
1661 type->Uri = duplicate_string(parent, uri);
1662 type->Table = NULL;
1664 return type;
1667 static BOOL is_duplicate_message(IWSDiscoveryPublisherImpl *impl, LPCWSTR id)
1669 struct message_id *msg_id, *msg_id_cursor;
1670 BOOL ret = FALSE;
1671 int len;
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)
1679 ret = TRUE;
1680 goto end;
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);
1690 if (!msg_id->id)
1692 heap_free(msg_id);
1693 goto end;
1696 memcpy(msg_id->id, id, len);
1697 list_add_tail(&impl->message_ids, &msg_id->entry);
1699 end:
1700 LeaveCriticalSection(&impl->message_ids_critical_section);
1701 return ret;
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;
1717 LPWSTR uri, prefix;
1718 WS_HEAP *heap;
1719 HRESULT ret;
1720 int i;
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);
1752 ret = E_FAIL;
1753 goto cleanup;
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);
1775 if (prefix == NULL)
1777 WSDFreeLinkedMemory(uri);
1778 continue;
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");
1806 ret = E_FAIL;
1807 goto cleanup;
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))
1826 ret = E_FAIL;
1827 goto cleanup;
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;
1852 continue;
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");
1892 ret = E_FAIL;
1893 goto cleanup;
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);
1913 if (FAILED(ret))
1915 WARN("Unable to find Types element in received Probe message\n");
1916 goto cleanup;
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;
1939 goto cleanup;
1941 outofmemory:
1942 ret = E_OUTOFMEMORY;
1944 cleanup:
1945 free_xml_string(soap_uri);
1946 WSDFreeLinkedMemory(soap_msg);
1947 if (context != NULL) IWSDXMLContext_Release(context);
1949 return ret;