wsdapi: Add InstanceId and MessageNumber to SOAP header.
[wine.git] / dlls / wsdapi / soap.c
blob06d0129b13da59574693047400d5886a552429cc
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 actionHello[] = {
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','5','/','0','4','/',
45 'd','i','s','c','o','v','e','r','y','/',
46 'H','e','l','l','o', 0 };
48 static const WCHAR addressingNsUri[] = {
49 'h','t','t','p',':','/','/',
50 's','c','h','e','m','a','s','.','x','m','l','s','o','a','p','.','o','r','g','/',
51 'w','s','/','2','0','0','4','/','0','8','/','a','d','d','r','e','s','s','i','n','g', 0 };
53 static const WCHAR discoveryNsUri[] = {
54 'h','t','t','p',':','/','/',
55 's','c','h','e','m','a','s','.','x','m','l','s','o','a','p','.','o','r','g','/',
56 'w','s','/','2','0','0','5','/','0','4','/','d','i','s','c','o','v','e','r','y', 0 };
58 static const WCHAR envelopeNsUri[] = {
59 'h','t','t','p',':','/','/',
60 'w','w','w','.','w','3','.','o','r','g','/',
61 '2','0','0','3','/','0','5','/','s','o','a','p','-','e','n','v','e','l','o','p','e', 0 };
63 static const WCHAR addressingPrefix[] = { 'w','s','a', 0 };
64 static const WCHAR discoveryPrefix[] = { 'w','s','d', 0 };
65 static const WCHAR envelopePrefix[] = { 's','o','a','p', 0 };
66 static const WCHAR headerString[] = { 'H','e','a','d','e','r', 0 };
67 static const WCHAR actionString[] = { 'A','c','t','i','o','n', 0 };
68 static const WCHAR messageIdString[] = { 'M','e','s','s','a','g','e','I','D', 0 };
69 static const WCHAR toString[] = { 'T','o', 0 };
70 static const WCHAR relatesToString[] = { 'R','e','l','a','t','e','s','T','o', 0 };
71 static const WCHAR appSequenceString[] = { 'A','p','p','S','e','q','u','e','n','c','e', 0 };
72 static const WCHAR instanceIdString[] = { 'I','n','s','t','a','n','c','e','I','d', 0 };
73 static const WCHAR messageNumberString[] = { 'M','e','s','s','a','g','e','N','u','m','b','e','r', 0 };
74 static const WCHAR emptyString[] = { 0 };
76 struct discovered_namespace
78 struct list entry;
79 LPCWSTR prefix;
80 LPCWSTR uri;
83 static char *wide_to_utf8(LPCWSTR wide_string, int *length)
85 char *new_string = NULL;
87 if (wide_string == NULL)
88 return NULL;
90 *length = WideCharToMultiByte(CP_UTF8, 0, wide_string, -1, NULL, 0, NULL, NULL);
92 if (*length < 0)
93 return NULL;
95 new_string = heap_alloc(*length);
96 WideCharToMultiByte(CP_UTF8, 0, wide_string, -1, new_string, *length, NULL, NULL);
98 return new_string;
101 static WS_XML_STRING *populate_xml_string(LPCWSTR str)
103 WS_XML_STRING *xml = heap_alloc_zero(sizeof(WS_XML_STRING));
104 int utf8Length;
106 if (xml == NULL)
107 return NULL;
109 xml->bytes = (BYTE *)wide_to_utf8(str, &utf8Length);
111 if (xml->bytes == NULL)
113 heap_free(xml);
114 return NULL;
117 xml->dictionary = NULL;
118 xml->id = 0;
119 xml->length = (xml->bytes == NULL) ? 0 : (utf8Length - 1);
121 return xml;
124 static inline void free_xml_string(WS_XML_STRING *value)
126 if (value == NULL)
127 return;
129 if (value->bytes != NULL)
130 heap_free(value->bytes);
132 heap_free(value);
135 static HRESULT write_xml_attribute(WSDXML_ATTRIBUTE *attribute, WS_XML_WRITER *writer)
137 WS_XML_STRING *local_name = NULL, *element_ns = NULL, *ns_prefix = NULL;
138 WS_XML_UTF16_TEXT utf16_text;
139 HRESULT ret = E_OUTOFMEMORY;
140 int text_len;
142 if (attribute == NULL)
143 return S_OK;
145 /* Start the attribute */
146 local_name = populate_xml_string(attribute->Name->LocalName);
147 if (local_name == NULL) goto cleanup;
149 if (attribute->Name->Space == NULL)
151 element_ns = populate_xml_string(emptyString);
152 if (element_ns == NULL) goto cleanup;
154 ns_prefix = NULL;
156 else
158 element_ns = populate_xml_string(attribute->Name->Space->Uri);
159 if (element_ns == NULL) goto cleanup;
161 ns_prefix = populate_xml_string(attribute->Name->Space->PreferredPrefix);
162 if (ns_prefix == NULL) goto cleanup;
165 ret = WsWriteStartAttribute(writer, ns_prefix, local_name, element_ns, FALSE, NULL);
166 if (FAILED(ret)) goto cleanup;
168 text_len = lstrlenW(attribute->Value);
170 utf16_text.text.textType = WS_XML_TEXT_TYPE_UTF16;
171 utf16_text.bytes = (BYTE *)attribute->Value;
172 utf16_text.byteCount = min(WSD_MAX_TEXT_LENGTH, text_len) * sizeof(WCHAR);
174 ret = WsWriteText(writer, (WS_XML_TEXT *)&utf16_text, NULL);
175 if (FAILED(ret)) goto cleanup;
177 ret = WsWriteEndAttribute(writer, NULL);
178 if (FAILED(ret)) goto cleanup;
180 cleanup:
181 free_xml_string(local_name);
182 free_xml_string(element_ns);
183 free_xml_string(ns_prefix);
185 return ret;
188 static HRESULT write_xml_element(WSDXML_ELEMENT *element, WS_XML_WRITER *writer)
190 WS_XML_STRING *local_name = NULL, *element_ns = NULL, *ns_prefix = NULL;
191 WSDXML_ATTRIBUTE *current_attribute;
192 WS_XML_UTF16_TEXT utf16_text;
193 WSDXML_NODE *current_child;
194 WSDXML_TEXT *node_as_text;
195 int text_len;
196 HRESULT ret = E_OUTOFMEMORY;
198 if (element == NULL)
199 return S_OK;
201 /* Start the element */
202 local_name = populate_xml_string(element->Name->LocalName);
203 if (local_name == NULL) goto cleanup;
205 element_ns = populate_xml_string(element->Name->Space->Uri);
206 if (element_ns == NULL) goto cleanup;
208 ns_prefix = populate_xml_string(element->Name->Space->PreferredPrefix);
209 if (ns_prefix == NULL) goto cleanup;
211 ret = WsWriteStartElement(writer, ns_prefix, local_name, element_ns, NULL);
212 if (FAILED(ret)) goto cleanup;
214 /* Write attributes */
215 current_attribute = element->FirstAttribute;
217 while (current_attribute != NULL)
219 ret = write_xml_attribute(current_attribute, writer);
220 if (FAILED(ret)) goto cleanup;
221 current_attribute = current_attribute->Next;
224 /* Write child elements */
225 current_child = element->FirstChild;
227 while (current_child != NULL)
229 if (current_child->Type == ElementType)
231 ret = write_xml_element((WSDXML_ELEMENT *)current_child, writer);
232 if (FAILED(ret)) goto cleanup;
234 else if (current_child->Type == TextType)
236 node_as_text = (WSDXML_TEXT *)current_child;
237 text_len = lstrlenW(node_as_text->Text);
239 utf16_text.text.textType = WS_XML_TEXT_TYPE_UTF16;
240 utf16_text.byteCount = min(WSD_MAX_TEXT_LENGTH, text_len) * sizeof(WCHAR);
241 utf16_text.bytes = (BYTE *)node_as_text->Text;
243 ret = WsWriteText(writer, (WS_XML_TEXT *)&utf16_text, NULL);
244 if (FAILED(ret)) goto cleanup;
247 current_child = current_child->Next;
250 /* End the element */
251 ret = WsWriteEndElement(writer, NULL);
253 cleanup:
254 free_xml_string(local_name);
255 free_xml_string(element_ns);
256 free_xml_string(ns_prefix);
258 return ret;
261 static WSDXML_ELEMENT *add_child_element(IWSDXMLContext *xml_context, WSDXML_ELEMENT *parent, LPCWSTR ns_uri,
262 LPCWSTR name, LPCWSTR text)
264 WSDXML_ELEMENT *element_obj;
265 WSDXML_NAME *name_obj;
267 if (FAILED(IWSDXMLContext_AddNameToNamespace(xml_context, ns_uri, name, &name_obj)))
268 return NULL;
270 if (FAILED(WSDXMLBuildAnyForSingleElement(name_obj, text, &element_obj)))
272 WSDFreeLinkedMemory(name_obj);
273 return NULL;
276 WSDFreeLinkedMemory(name_obj);
278 /* Add the element as a child - this will link the element's memory allocation to the parent's */
279 if (FAILED(WSDXMLAddChild(parent, element_obj)))
281 WSDFreeLinkedMemory(element_obj);
282 return NULL;
285 return element_obj;
288 static BOOL create_guid(LPWSTR buffer)
290 const WCHAR formatString[] = { 'u','r','n',':','u','u','i','d',':','%','s', 0 };
292 WCHAR* uuidString = NULL;
293 UUID uuid;
295 if (UuidCreate(&uuid) != RPC_S_OK)
296 return FALSE;
298 UuidToStringW(&uuid, (RPC_WSTR*)&uuidString);
300 if (uuidString == NULL)
301 return FALSE;
303 wsprintfW(buffer, formatString, uuidString);
304 RpcStringFreeW((RPC_WSTR*)&uuidString);
306 return TRUE;
309 static void populate_soap_header(WSD_SOAP_HEADER *header, LPCWSTR to, LPCWSTR action, LPCWSTR message_id,
310 WSD_APP_SEQUENCE *sequence, const WSDXML_ELEMENT *any_headers)
312 ZeroMemory(header, sizeof(WSD_SOAP_HEADER));
314 header->To = to;
315 header->Action = action;
316 header->MessageID = message_id;
317 header->AppSequence = sequence;
318 header->AnyHeaders = (WSDXML_ELEMENT *)any_headers;
320 /* TODO: Implement RelatesTo, ReplyTo, From, FaultTo */
323 #define MAX_ULONGLONG_STRING_SIZE 25
325 static LPWSTR ulonglong_to_string(void *parent, ULONGLONG value)
327 WCHAR formatString[] = { '%','I','6','4','u', 0 };
328 LPWSTR ret;
330 ret = WSDAllocateLinkedMemory(parent, MAX_ULONGLONG_STRING_SIZE * sizeof(WCHAR));
332 if (ret == NULL)
333 return NULL;
335 wsprintfW(ret, formatString, value);
336 return ret;
339 static WSDXML_ATTRIBUTE *add_attribute(IWSDXMLContext *xml_context, WSDXML_ELEMENT *parent, LPCWSTR ns_uri, LPCWSTR name)
341 WSDXML_ATTRIBUTE *attribute, *cur_attrib;
342 WSDXML_NAME *name_obj = NULL;
344 if (ns_uri == NULL)
346 name_obj = WSDAllocateLinkedMemory(NULL, sizeof(WSDXML_NAME));
347 name_obj->LocalName = duplicate_string(name_obj, name);
348 name_obj->Space = NULL;
350 else
352 if (FAILED(IWSDXMLContext_AddNameToNamespace(xml_context, ns_uri, name, &name_obj)))
353 return NULL;
356 attribute = WSDAllocateLinkedMemory(parent, sizeof(WSDXML_ATTRIBUTE));
358 if (attribute == NULL)
360 WSDFreeLinkedMemory(name_obj);
361 return NULL;
364 attribute->Element = parent;
365 attribute->Name = name_obj;
366 attribute->Next = NULL;
367 attribute->Value = NULL;
369 if (name_obj != NULL)
370 WSDAttachLinkedMemory(attribute, name_obj);
372 if (parent->FirstAttribute == NULL)
374 /* Make this the first attribute of the parent */
375 parent->FirstAttribute = attribute;
377 else
379 /* Find the last attribute and add this as the next one */
380 cur_attrib = parent->FirstAttribute;
382 while (cur_attrib->Next != NULL)
384 cur_attrib = cur_attrib->Next;
387 cur_attrib->Next = attribute;
390 return attribute;
393 static void remove_attribute(WSDXML_ELEMENT *parent, WSDXML_ATTRIBUTE *attribute)
395 WSDXML_ATTRIBUTE *cur_attrib;
397 /* Find the last attribute and add this as the next one */
398 cur_attrib = parent->FirstAttribute;
400 if (cur_attrib == attribute)
401 parent->FirstAttribute = cur_attrib->Next;
402 else
404 while (cur_attrib != NULL)
406 /* Is our attribute the next attribute? */
407 if (cur_attrib->Next == attribute)
409 /* Remove it from the list */
410 cur_attrib->Next = attribute->Next;
411 break;
414 cur_attrib = cur_attrib->Next;
418 WSDFreeLinkedMemory(attribute);
421 static BOOL add_ulonglong_attribute(IWSDXMLContext *xml_context, WSDXML_ELEMENT *parent, LPCWSTR ns_uri, LPCWSTR name,
422 ULONGLONG value)
424 WSDXML_ATTRIBUTE *attribute = add_attribute(xml_context, parent, ns_uri, name);
426 if (attribute == NULL)
427 return FALSE;
429 attribute->Value = ulonglong_to_string(attribute, value);
431 if (attribute->Value == NULL)
433 remove_attribute(parent, attribute);
434 return FALSE;
437 return TRUE;
440 static BOOL add_discovered_namespace(struct list *namespaces, WSDXML_NAMESPACE *discovered_ns)
442 struct discovered_namespace *ns;
444 LIST_FOR_EACH_ENTRY(ns, namespaces, struct discovered_namespace, entry)
446 if (lstrcmpW(ns->uri, discovered_ns->Uri) == 0)
447 return TRUE; /* Already added */
450 ns = WSDAllocateLinkedMemory(namespaces, sizeof(struct discovered_namespace));
452 if (ns == NULL)
453 return FALSE;
455 ns->prefix = duplicate_string(ns, discovered_ns->PreferredPrefix);
456 ns->uri = duplicate_string(ns, discovered_ns->Uri);
458 if ((ns->prefix == NULL) || (ns->uri == NULL))
459 return FALSE;
461 list_add_tail(namespaces, &ns->entry);
462 return TRUE;
465 static WSDXML_ELEMENT *create_soap_header_xml_elements(IWSDXMLContext *xml_context, WSD_SOAP_HEADER *header)
467 WSDXML_ELEMENT *header_element = NULL, *app_sequence_element = NULL;
468 WSDXML_NAME *header_name = NULL;
470 /* <s:Header> */
471 if (FAILED(IWSDXMLContext_AddNameToNamespace(xml_context, envelopeNsUri, headerString, &header_name))) goto cleanup;
472 if (FAILED(WSDXMLBuildAnyForSingleElement(header_name, NULL, &header_element))) goto cleanup;
473 WSDFreeLinkedMemory(header_name);
475 /* <a:Action> */
476 if (add_child_element(xml_context, header_element, addressingNsUri, actionString, header->Action) == NULL)
477 goto cleanup;
479 /* <a:MessageId> */
480 if (add_child_element(xml_context, header_element, addressingNsUri, messageIdString, header->MessageID) == NULL)
481 goto cleanup;
483 /* <a:To> */
484 if (add_child_element(xml_context, header_element, addressingNsUri, toString, header->To) == NULL)
485 goto cleanup;
487 /* <a:RelatesTo> */
488 if (header->RelatesTo.MessageID != NULL)
490 if (add_child_element(xml_context, header_element, addressingNsUri, relatesToString,
491 header->RelatesTo.MessageID) == NULL) goto cleanup;
494 /* <d:AppSequence> */
495 app_sequence_element = add_child_element(xml_context, header_element, discoveryNsUri, appSequenceString, emptyString);
496 if (app_sequence_element == NULL) goto cleanup;
498 /* InstanceId attribute */
499 if (!add_ulonglong_attribute(xml_context, app_sequence_element, NULL, instanceIdString, min(UINT_MAX,
500 header->AppSequence->InstanceId))) goto cleanup;
502 /* MessageNumber attribute */
503 if (!add_ulonglong_attribute(xml_context, app_sequence_element, NULL, messageNumberString, min(UINT_MAX,
504 header->AppSequence->MessageNumber))) goto cleanup;
506 /* TODO: SequenceID attribute */
508 /* </d:AppSequence> */
510 /* TODO: Write any headers */
512 /* </s:Header> */
514 return header_element;
516 cleanup:
517 if (header_name != NULL) WSDFreeLinkedMemory(header_name);
518 WSDXMLCleanupElement(header_element);
520 return NULL;
523 static HRESULT create_soap_envelope(IWSDXMLContext *xml_context, WSD_SOAP_HEADER *header, WSDXML_ELEMENT *body_element,
524 WS_HEAP **heap, char **output_xml, ULONG *xml_length, struct list *discovered_namespaces)
526 WS_XML_STRING *actual_envelope_prefix = NULL, *envelope_uri_xmlstr = NULL, *tmp_prefix = NULL, *tmp_uri = NULL;
527 WSDXML_NAMESPACE *addressing_ns = NULL, *discovery_ns = NULL, *envelope_ns = NULL;
528 WSDXML_ELEMENT *header_element = NULL;
529 struct discovered_namespace *ns;
530 WS_XML_BUFFER *buffer = NULL;
531 WS_XML_WRITER *writer = NULL;
532 WS_XML_STRING envelope;
533 HRESULT ret = E_OUTOFMEMORY;
534 static BYTE envelopeString[] = "Envelope";
536 /* Create the necessary XML prefixes */
537 if (FAILED(IWSDXMLContext_AddNamespace(xml_context, addressingNsUri, addressingPrefix, &addressing_ns))) goto cleanup;
538 if (!add_discovered_namespace(discovered_namespaces, addressing_ns)) goto cleanup;
540 if (FAILED(IWSDXMLContext_AddNamespace(xml_context, discoveryNsUri, discoveryPrefix, &discovery_ns))) goto cleanup;
541 if (!add_discovered_namespace(discovered_namespaces, discovery_ns)) goto cleanup;
543 if (FAILED(IWSDXMLContext_AddNamespace(xml_context, envelopeNsUri, envelopePrefix, &envelope_ns))) goto cleanup;
544 if (!add_discovered_namespace(discovered_namespaces, envelope_ns)) goto cleanup;
546 envelope.bytes = envelopeString;
547 envelope.length = sizeof(envelopeString) - 1;
548 envelope.dictionary = NULL;
549 envelope.id = 0;
551 actual_envelope_prefix = populate_xml_string(envelope_ns->PreferredPrefix);
552 envelope_uri_xmlstr = populate_xml_string(envelope_ns->Uri);
554 if ((actual_envelope_prefix == NULL) || (envelope_uri_xmlstr == NULL)) goto cleanup;
556 /* Now try to create the appropriate WebServices buffers, etc */
557 ret = WsCreateHeap(16384, 4096, NULL, 0, heap, NULL);
558 if (FAILED(ret)) goto cleanup;
560 ret = WsCreateXmlBuffer(*heap, NULL, 0, &buffer, NULL);
561 if (FAILED(ret)) goto cleanup;
563 ret = WsCreateWriter(NULL, 0, &writer, NULL);
564 if (FAILED(ret)) goto cleanup;
566 ret = WsSetOutputToBuffer(writer, buffer, NULL, 0, NULL);
567 if (FAILED(ret)) goto cleanup;
569 /* Create the header XML elements */
570 header_element = create_soap_header_xml_elements(xml_context, header);
571 if (header_element == NULL) goto cleanup;
573 /* <s:Envelope> */
574 ret = WsWriteStartElement(writer, actual_envelope_prefix, &envelope, envelope_uri_xmlstr, NULL);
575 if (FAILED(ret)) goto cleanup;
577 LIST_FOR_EACH_ENTRY(ns, discovered_namespaces, struct discovered_namespace, entry)
579 tmp_prefix = populate_xml_string(ns->prefix);
580 tmp_uri = populate_xml_string(ns->uri);
582 if ((tmp_prefix == NULL) || (tmp_uri == NULL)) goto cleanup;
584 ret = WsWriteXmlnsAttribute(writer, tmp_prefix, tmp_uri, FALSE, NULL);
585 if (FAILED(ret)) goto cleanup;
587 free_xml_string(tmp_prefix);
588 free_xml_string(tmp_uri);
591 tmp_prefix = NULL;
592 tmp_uri = NULL;
594 /* Write the header */
595 ret = write_xml_element(header_element, writer);
596 if (FAILED(ret)) goto cleanup;
598 ret = WsWriteEndElement(writer, NULL);
599 if (FAILED(ret)) goto cleanup;
601 /* </s:Envelope> */
603 /* Generate the bytes of the document */
604 ret = WsWriteXmlBufferToBytes(writer, buffer, NULL, NULL, 0, *heap, (void**)output_xml, xml_length, NULL);
605 if (FAILED(ret)) goto cleanup;
607 cleanup:
608 WSDFreeLinkedMemory(addressing_ns);
609 WSDFreeLinkedMemory(discovery_ns);
610 WSDFreeLinkedMemory(envelope_ns);
612 WSDXMLCleanupElement(header_element);
614 free_xml_string(actual_envelope_prefix);
615 free_xml_string(envelope_uri_xmlstr);
617 if (writer != NULL)
618 WsFreeWriter(writer);
620 /* Don't free the heap unless the operation has failed */
621 if ((FAILED(ret)) && (*heap != NULL))
623 WsFreeHeap(*heap);
624 *heap = NULL;
627 return ret;
630 static HRESULT write_and_send_message(IWSDiscoveryPublisherImpl *impl, WSD_SOAP_HEADER *header, WSDXML_ELEMENT *body_element,
631 struct list *discovered_namespaces, IWSDUdpAddress *remote_address, int max_initial_delay)
633 static const char xml_header[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
634 ULONG xml_length = 0, xml_header_len = sizeof(xml_header) - 1;
635 WS_HEAP *heap = NULL;
636 char *xml = NULL;
637 char *full_xml;
638 HRESULT ret;
640 ret = create_soap_envelope(impl->xmlContext, header, NULL, &heap, &xml, &xml_length, discovered_namespaces);
641 if (ret != S_OK) return ret;
643 /* Prefix the XML header */
644 full_xml = heap_alloc(xml_length + xml_header_len + 1);
646 if (full_xml == NULL)
648 WsFreeHeap(heap);
649 return E_OUTOFMEMORY;
652 memcpy(full_xml, xml_header, xml_header_len);
653 memcpy(full_xml + xml_header_len, xml, xml_length);
654 full_xml[xml_length + xml_header_len] = 0;
656 if (remote_address == NULL)
658 /* Send the message via UDP multicast */
659 ret = send_udp_multicast(impl, full_xml, xml_length + xml_header_len + 1, max_initial_delay) ? S_OK : E_FAIL;
661 else
663 /* TODO: Send the message via UDP unicast */
664 FIXME("TODO: Send the message via UDP unicast\n");
667 heap_free(full_xml);
668 WsFreeHeap(heap);
670 return ret;
673 HRESULT send_hello_message(IWSDiscoveryPublisherImpl *impl, LPCWSTR id, ULONGLONG metadata_ver, ULONGLONG instance_id,
674 ULONGLONG msg_num, LPCWSTR session_id, const WSD_NAME_LIST *types_list, const WSD_URI_LIST *scopes_list,
675 const WSD_URI_LIST *xaddrs_list, const WSDXML_ELEMENT *hdr_any, const WSDXML_ELEMENT *ref_param_any,
676 const WSDXML_ELEMENT *endpoint_ref_any, const WSDXML_ELEMENT *any)
678 struct list *discoveredNamespaces = NULL;
679 WSD_SOAP_HEADER soapHeader;
680 WSD_APP_SEQUENCE sequence;
681 WCHAR message_id[64];
682 HRESULT ret = E_OUTOFMEMORY;
684 sequence.InstanceId = instance_id;
685 sequence.MessageNumber = msg_num;
686 sequence.SequenceId = session_id;
688 if (!create_guid(message_id)) goto cleanup;
690 discoveredNamespaces = WSDAllocateLinkedMemory(NULL, sizeof(struct list));
691 if (!discoveredNamespaces) goto cleanup;
693 list_init(discoveredNamespaces);
695 populate_soap_header(&soapHeader, discoveryTo, actionHello, message_id, &sequence, hdr_any);
697 /* TODO: Populate message body */
699 /* Write and send the message */
700 ret = write_and_send_message(impl, &soapHeader, NULL, discoveredNamespaces, NULL, APP_MAX_DELAY);
702 cleanup:
703 WSDFreeLinkedMemory(discoveredNamespaces);
705 return ret;