MiniDLNA cvs 2010-11-11
[tomato.git] / release / src / router / minidlna / upnpdescgen.c
blob31f22c7aae9e44543afd654a386423ea687b9806
1 /* $Id: upnpdescgen.c,v 1.16 2010/11/11 23:48:13 jmaggard Exp $ */
2 /* MiniUPnP project
3 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
5 * Copyright (c) 2006-2008, Thomas Bernard
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * * The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
34 #include "config.h"
35 #include "getifaddr.h"
36 #include "upnpdescgen.h"
37 #include "minidlnapath.h"
38 #include "upnpglobalvars.h"
39 #include "upnpdescstrings.h"
41 #undef DESC_DEBUG
43 static const char * const upnptypes[] =
45 "string",
46 "boolean",
47 "ui2",
48 "ui4",
49 "i4",
50 "uri",
51 "int",
52 "bin.base64"
55 static const char * const upnpdefaultvalues[] =
58 "Unconfigured"
61 static const char * const upnpallowedvalues[] =
63 0, /* 0 */
64 "DSL", /* 1 */
65 "POTS",
66 "Cable",
67 "Ethernet",
69 "Up", /* 6 */
70 "Down",
71 "Initializing",
72 "Unavailable",
74 "TCP", /* 11 */
75 "UDP",
77 "Unconfigured", /* 14 */
78 "IP_Routed",
79 "IP_Bridged",
81 "Unconfigured", /* 18 */
82 "Connecting",
83 "Connected",
84 "PendingDisconnect",
85 "Disconnecting",
86 "Disconnected",
88 "ERROR_NONE", /* 25 */
90 "OK", /* 27 */
91 "ContentFormatMismatch",
92 "InsufficientBandwidth",
93 "UnreliableChannel",
94 "Unknown",
96 "Input", /* 33 */
97 "Output",
99 "BrowseMetadata", /* 36 */
100 "BrowseDirectChildren",
102 "COMPLETED", /* 39 */
103 "ERROR",
104 "IN_PROGRESS",
105 "STOPPED",
107 RESOURCE_PROTOCOL_INFO_VALUES, /* 44 */
109 "0", /* 46 */
111 "", /* 48 */
115 static const char xmlver[] =
116 "<?xml version=\"1.0\"?>\r\n";
117 static const char root_service[] =
118 "scpd xmlns=\"urn:schemas-upnp-org:service-1-0\"";
119 static const char root_device[] =
120 "root xmlns=\"urn:schemas-upnp-org:device-1-0\"";
122 /* root Description of the UPnP Device
123 * fixed to match UPnP_IGD_InternetGatewayDevice 1.0.pdf
124 * presentationURL is only "recommended" but the router doesn't appears
125 * in "Network connections" in Windows XP if it is not present. */
126 static const struct XMLElt rootDesc[] =
128 {root_device, INITHELPER(1,2)},
129 {"specVersion", INITHELPER(3,2)},
130 {"device", INITHELPER(5,14)},
131 {"/major", "1"},
132 {"/minor", "0"},
133 {"/deviceType", "urn:schemas-upnp-org:device:MediaServer:1"},
134 {"/friendlyName", friendly_name}, /* required */
135 {"/manufacturer", ROOTDEV_MANUFACTURER}, /* required */
136 {"/manufacturerURL", ROOTDEV_MANUFACTURERURL}, /* optional */
137 {"/modelDescription", ROOTDEV_MODELDESCRIPTION}, /* recommended */
138 {"/modelName", ROOTDEV_MODELNAME}, /* required */
139 {"/modelNumber", modelnumber},
140 {"/modelURL", ROOTDEV_MODELURL},
141 {"/serialNumber", serialnumber},
142 {"/UDN", uuidvalue}, /* required */
143 {"/dlna:X_DLNADOC xmlns:dlna=\"urn:schemas-dlna-org:device-1-0\"", "DMS-1.50"},
144 {"/presentationURL", presentationurl}, /* recommended */
145 {"iconList", INITHELPER(19,4)},
146 {"serviceList", INITHELPER(43,3)},
147 {"icon", INITHELPER(23,5)},
148 {"icon", INITHELPER(28,5)},
149 {"icon", INITHELPER(33,5)},
150 {"icon", INITHELPER(38,5)},
151 {"/mimetype", "image/png"},
152 {"/width", "48"},
153 {"/height", "48"},
154 {"/depth", "24"},
155 {"/url", "/icons/sm.png"},
156 {"/mimetype", "image/png"},
157 {"/width", "120"},
158 {"/height", "120"},
159 {"/depth", "24"},
160 {"/url", "/icons/lrg.png"},
161 {"/mimetype", "image/jpeg"},
162 {"/width", "48"},
163 {"/height", "48"},
164 {"/depth", "24"},
165 {"/url", "/icons/sm.jpg"},
166 {"/mimetype", "image/jpeg"},
167 {"/width", "120"},
168 {"/height", "120"},
169 {"/depth", "24"},
170 {"/url", "/icons/lrg.jpg"},
171 {"service", INITHELPER(46,5)},
172 {"service", INITHELPER(51,5)},
173 {"service", INITHELPER(56,5)},
174 {"/serviceType", "urn:schemas-upnp-org:service:ContentDirectory:1"},
175 {"/serviceId", "urn:upnp-org:serviceId:ContentDirectory"},
176 {"/controlURL", CONTENTDIRECTORY_CONTROLURL},
177 {"/eventSubURL", CONTENTDIRECTORY_EVENTURL},
178 {"/SCPDURL", CONTENTDIRECTORY_PATH},
179 {"/serviceType", "urn:schemas-upnp-org:service:ConnectionManager:1"},
180 {"/serviceId", "urn:upnp-org:serviceId:ConnectionManager"},
181 {"/controlURL", CONNECTIONMGR_CONTROLURL},
182 {"/eventSubURL", CONNECTIONMGR_EVENTURL},
183 {"/SCPDURL", CONNECTIONMGR_PATH},
184 {"/serviceType", "urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1"},
185 {"/serviceId", "urn:microsoft.com:serviceId:X_MS_MediaReceiverRegistrar"},
186 {"/controlURL", X_MS_MEDIARECEIVERREGISTRAR_CONTROLURL},
187 {"/eventSubURL", X_MS_MEDIARECEIVERREGISTRAR_EVENTURL},
188 {"/SCPDURL", X_MS_MEDIARECEIVERREGISTRAR_PATH},
189 {0, 0}
192 static const struct argument AddPortMappingArgs[] =
194 {NULL, 1, 11},
195 {NULL, 1, 12},
196 {NULL, 1, 14},
197 {NULL, 1, 13},
198 {NULL, 1, 15},
199 {NULL, 1, 9},
200 {NULL, 1, 16},
201 {NULL, 1, 10},
202 {NULL, 0, 0}
205 static const struct argument DeletePortMappingArgs[] =
207 {NULL, 1, 11},
208 {NULL, 1, 12},
209 {NULL, 1, 14},
210 {NULL, 0, 0}
213 static const struct argument SetConnectionTypeArgs[] =
215 {NULL, 1, 0},
216 {NULL, 0, 0}
219 static const struct argument GetConnectionTypeInfoArgs[] =
221 {NULL, 2, 0},
222 {NULL, 2, 1},
223 {NULL, 0, 0}
226 static const struct argument GetNATRSIPStatusArgs[] =
228 {NULL, 2, 5},
229 {NULL, 2, 6},
230 {NULL, 0, 0}
233 static const struct argument GetGenericPortMappingEntryArgs[] =
235 {NULL, 1, 8},
236 {NULL, 2, 11},
237 {NULL, 2, 12},
238 {NULL, 2, 14},
239 {NULL, 2, 13},
240 {NULL, 2, 15},
241 {NULL, 2, 9},
242 {NULL, 2, 16},
243 {NULL, 2, 10},
244 {NULL, 0, 0}
247 static const struct argument GetSpecificPortMappingEntryArgs[] =
249 {NULL, 1, 11},
250 {NULL, 1, 12},
251 {NULL, 1, 14},
252 {NULL, 2, 13},
253 {NULL, 2, 15},
254 {NULL, 2, 9},
255 {NULL, 2, 16},
256 {NULL, 2, 10},
257 {NULL, 0, 0}
260 /* For ConnectionManager */
261 static const struct argument GetProtocolInfoArgs[] =
263 {"Source", 2, 0},
264 {"Sink", 2, 1},
265 {NULL, 0, 0}
268 static const struct argument PrepareForConnectionArgs[] =
270 {"RemoteProtocolInfo", 1, 6},
271 {"PeerConnectionManager", 1, 4},
272 {"PeerConnectionID", 1, 7},
273 {"Direction", 1, 5},
274 {"ConnectionID", 2, 7},
275 {"AVTransportID", 2, 8},
276 {"RcsID", 2, 9},
277 {NULL, 0, 0}
280 static const struct argument ConnectionCompleteArgs[] =
282 {"ConnectionID", 1, 7},
283 {NULL, 0, 0}
286 static const struct argument GetCurrentConnectionIDsArgs[] =
288 {"ConnectionIDs", 2, 2},
289 {NULL, 0, 0}
292 static const struct argument GetCurrentConnectionInfoArgs[] =
294 {"ConnectionID", 1, 7},
295 {"RcsID", 2, 9},
296 {"AVTransportID", 2, 8},
297 {"ProtocolInfo", 2, 6},
298 {"PeerConnectionManager", 2, 4},
299 {"PeerConnectionID", 2, 7},
300 {"Direction", 2, 5},
301 {"Status", 2, 3},
302 {NULL, 0, 0}
305 static const struct action ConnectionManagerActions[] =
307 {"GetProtocolInfo", GetProtocolInfoArgs}, /* R */
308 //OPTIONAL {"PrepareForConnection", PrepareForConnectionArgs}, /* R */
309 //OPTIONAL {"ConnectionComplete", ConnectionCompleteArgs}, /* R */
310 {"GetCurrentConnectionIDs", GetCurrentConnectionIDsArgs}, /* R */
311 {"GetCurrentConnectionInfo", GetCurrentConnectionInfoArgs}, /* R */
312 {0, 0}
315 static const struct stateVar ConnectionManagerVars[] =
317 {"SourceProtocolInfo", 1<<7, 0, 0, 44}, /* required */
318 {"SinkProtocolInfo", 1<<7, 0, 0, 48}, /* required */
319 {"CurrentConnectionIDs", 1<<7, 0, 0, 46}, /* required */
320 {"A_ARG_TYPE_ConnectionStatus", 0, 0, 27}, /* required */
321 {"A_ARG_TYPE_ConnectionManager", 0, 0}, /* required */
322 {"A_ARG_TYPE_Direction", 0, 0, 33}, /* required */
323 {"A_ARG_TYPE_ProtocolInfo", 0, 0}, /* required */
324 {"A_ARG_TYPE_ConnectionID", 4, 0}, /* required */
325 {"A_ARG_TYPE_AVTransportID", 4, 0}, /* required */
326 {"A_ARG_TYPE_RcsID", 4, 0}, /* required */
327 {0, 0}
330 static const struct argument GetSearchCapabilitiesArgs[] =
332 {"SearchCaps", 2, 10},
333 {0, 0}
336 static const struct argument GetSortCapabilitiesArgs[] =
338 {"SortCaps", 2, 11},
339 {0, 0}
342 static const struct argument GetSystemUpdateIDArgs[] =
344 {"Id", 2, 12},
345 {0, 0}
348 static const struct argument BrowseArgs[] =
350 {"ObjectID", 1, 1},
351 {"BrowseFlag", 1, 4},
352 {"Filter", 1, 5},
353 {"StartingIndex", 1, 7},
354 {"RequestedCount", 1, 8},
355 {"SortCriteria", 1, 6},
356 {"Result", 2, 2},
357 {"NumberReturned", 2, 8},
358 {"TotalMatches", 2, 8},
359 {"UpdateID", 2, 9},
360 {0, 0}
363 static const struct argument SearchArgs[] =
365 {"ContainerID", 1, 1},
366 {"SearchCriteria", 1, 3},
367 {"Filter", 1, 5},
368 {"StartingIndex", 1, 7},
369 {"RequestedCount", 1, 8},
370 {"SortCriteria", 1, 6},
371 {"Result", 2, 2},
372 {"NumberReturned", 2, 8},
373 {"TotalMatches", 2, 8},
374 {"UpdateID", 2, 9},
375 {0, 0}
378 static const struct action ContentDirectoryActions[] =
380 {"GetSearchCapabilities", GetSearchCapabilitiesArgs}, /* R */
381 {"GetSortCapabilities", GetSortCapabilitiesArgs}, /* R */
382 {"GetSystemUpdateID", GetSystemUpdateIDArgs}, /* R */
383 {"Browse", BrowseArgs}, /* R */
384 {"Search", SearchArgs}, /* O */
385 #if 0 // Not implementing optional features yet...
386 {"CreateObject", CreateObjectArgs}, /* O */
387 {"DestroyObject", DestroyObjectArgs}, /* O */
388 {"UpdateObject", UpdateObjectArgs}, /* O */
389 {"ImportResource", ImportResourceArgs}, /* O */
390 {"ExportResource", ExportResourceArgs}, /* O */
391 {"StopTransferResource", StopTransferResourceArgs}, /* O */
392 {"GetTransferProgress", GetTransferProgressArgs}, /* O */
393 {"DeleteResource", DeleteResourceArgs}, /* O */
394 {"CreateReference", CreateReferenceArgs}, /* O */
395 #endif
396 {0, 0}
399 static const struct stateVar ContentDirectoryVars[] =
401 {"TransferIDs", 1<<7, 0, 0, 48}, /* 0 */
402 {"A_ARG_TYPE_ObjectID", 0, 0},
403 {"A_ARG_TYPE_Result", 0, 0},
404 {"A_ARG_TYPE_SearchCriteria", 0, 0},
405 {"A_ARG_TYPE_BrowseFlag", 0, 0, 36},
406 /* Allowed Values : BrowseMetadata / BrowseDirectChildren */
407 {"A_ARG_TYPE_Filter", 0, 0}, /* 5 */
408 {"A_ARG_TYPE_SortCriteria", 0, 0},
409 {"A_ARG_TYPE_Index", 3, 0},
410 {"A_ARG_TYPE_Count", 3, 0},
411 {"A_ARG_TYPE_UpdateID", 3, 0},
412 //JM{"A_ARG_TYPE_TransferID", 3, 0}, /* 10 */
413 //JM{"A_ARG_TYPE_TransferStatus", 0, 0, 39},
414 /* Allowed Values : COMPLETED / ERROR / IN_PROGRESS / STOPPED */
415 //JM{"A_ARG_TYPE_TransferLength", 0, 0},
416 //JM{"A_ARG_TYPE_TransferTotal", 0, 0},
417 //JM{"A_ARG_TYPE_TagValueList", 0, 0},
418 //JM{"A_ARG_TYPE_URI", 5, 0}, /* 15 */
419 {"SearchCapabilities", 0, 0},
420 {"SortCapabilities", 0, 0},
421 {"SystemUpdateID", 3|0x80, 0, 0, 255},
422 //{"ContainerUpdateIDs", 0, 0},
423 {0, 0}
426 static const struct argument GetIsAuthorizedArgs[] =
428 {"DeviceID", 1, 0},
429 {"Result", 2, 3},
430 {NULL, 0, 0}
433 static const struct argument GetIsValidatedArgs[] =
435 {"DeviceID", 1, 0},
436 {"Result", 2, 3},
437 {NULL, 0, 0}
440 static const struct argument GetRegisterDeviceArgs[] =
442 {"RegistrationReqMsg", 1, 1},
443 {"RegistrationRespMsg", 2, 2},
444 {NULL, 0, 0}
447 static const struct action X_MS_MediaReceiverRegistrarActions[] =
449 {"IsAuthorized", GetIsAuthorizedArgs}, /* R */
450 {"IsValidated", GetIsValidatedArgs}, /* R */
451 #if 0 // Not needed? WMP12 still works. Need to check with 360 and WMP11.
452 {"RegisterDevice", GetRegisterDeviceArgs}, /* R */
453 #endif
454 {0, 0}
457 static const struct stateVar X_MS_MediaReceiverRegistrarVars[] =
459 {"A_ARG_TYPE_DeviceID", 0, 0},
460 {"A_ARG_TYPE_RegistrationReqMsg", 7, 0},
461 {"A_ARG_TYPE_RegistrationRespMsg", 7, 0},
462 {"A_ARG_TYPE_Result", 6, 0},
463 {"AuthorizationDeniedUpdateID", 3, 0},
464 {"AuthorizationGrantedUpdateID", 3, 0},
465 {"ValidationRevokedUpdateID", 3, 0},
466 {"ValidationSucceededUpdateID", 3, 0},
467 {0, 0}
470 /* WANCfg.xml */
471 /* See UPnP_IGD_WANCommonInterfaceConfig 1.0.pdf */
473 static const struct argument GetCommonLinkPropertiesArgs[] =
475 {NULL, 2, 0},
476 {NULL, 2, 1},
477 {NULL, 2, 2},
478 {NULL, 2, 3},
479 {NULL, 0, 0}
482 static const struct argument GetTotalBytesSentArgs[] =
484 {NULL, 2, 4},
485 {NULL, 0, 0}
488 static const struct argument GetTotalBytesReceivedArgs[] =
490 {NULL, 2, 5},
491 {NULL, 0, 0}
494 static const struct argument GetTotalPacketsSentArgs[] =
496 {NULL, 2, 6},
497 {NULL, 0, 0}
500 static const struct argument GetTotalPacketsReceivedArgs[] =
502 {NULL, 2, 7},
503 {NULL, 0, 0}
506 static const struct serviceDesc scpdContentDirectory =
507 { ContentDirectoryActions, ContentDirectoryVars };
509 static const struct serviceDesc scpdConnectionManager =
510 { ConnectionManagerActions, ConnectionManagerVars };
512 static const struct serviceDesc scpdX_MS_MediaReceiverRegistrar =
513 { X_MS_MediaReceiverRegistrarActions, X_MS_MediaReceiverRegistrarVars };
515 /* strcat_str()
516 * concatenate the string and use realloc to increase the
517 * memory buffer if needed. */
518 static char *
519 strcat_str(char * str, int * len, int * tmplen, const char * s2)
521 int s2len;
522 s2len = (int)strlen(s2);
523 if(*tmplen <= (*len + s2len))
525 if(s2len < 256)
526 *tmplen += 256;
527 else
528 *tmplen += s2len + 1;
529 str = (char *)realloc(str, *tmplen);
531 /*strcpy(str + *len, s2); */
532 memcpy(str + *len, s2, s2len + 1);
533 *len += s2len;
534 return str;
537 /* strcat_char() :
538 * concatenate a character and use realloc to increase the
539 * size of the memory buffer if needed */
540 static char *
541 strcat_char(char * str, int * len, int * tmplen, char c)
543 if(*tmplen <= (*len + 1))
545 *tmplen += 256;
546 str = (char *)realloc(str, *tmplen);
548 str[*len] = c;
549 (*len)++;
550 return str;
553 /* iterative subroutine using a small stack
554 * This way, the progam stack usage is kept low */
555 static char *
556 genXML(char * str, int * len, int * tmplen,
557 const struct XMLElt * p)
559 u_int16_t i, j, k;
560 int top;
561 const char * eltname, *s;
562 char c;
563 char element[64];
564 struct {
565 unsigned short i;
566 unsigned short j;
567 const char * eltname;
568 } pile[16]; /* stack */
569 top = -1;
570 i = 0; /* current node */
571 j = 1; /* i + number of nodes*/
572 for(;;)
574 eltname = p[i].eltname;
575 if(!eltname)
576 return str;
577 if(eltname[0] == '/')
579 #ifdef DESC_DEBUG
580 printf("DBG: <%s>%s<%s>\n", eltname+1, p[i].data, eltname);
581 #endif
582 str = strcat_char(str, len, tmplen, '<');
583 str = strcat_str(str, len, tmplen, eltname+1);
584 str = strcat_char(str, len, tmplen, '>');
585 str = strcat_str(str, len, tmplen, p[i].data);
586 str = strcat_char(str, len, tmplen, '<');
587 sscanf(eltname, "%s", element);
588 str = strcat_str(str, len, tmplen, element);
589 str = strcat_char(str, len, tmplen, '>');
590 for(;;)
592 if(top < 0)
593 return str;
594 i = ++(pile[top].i);
595 j = pile[top].j;
596 #ifdef DESC_DEBUG
597 printf("DBG: pile[%d]\t%d %d\n", top, i, j);
598 #endif
599 if(i==j)
601 #ifdef DESC_DEBUG
602 printf("DBG: i==j, </%s>\n", pile[top].eltname);
603 #endif
604 str = strcat_char(str, len, tmplen, '<');
605 str = strcat_char(str, len, tmplen, '/');
606 s = pile[top].eltname;
607 for(c = *s; c > ' '; c = *(++s))
608 str = strcat_char(str, len, tmplen, c);
609 str = strcat_char(str, len, tmplen, '>');
610 top--;
612 else
613 break;
616 else
618 #ifdef DESC_DEBUG
619 printf("DBG: [%d] <%s>\n", i, eltname);
620 #endif
621 str = strcat_char(str, len, tmplen, '<');
622 str = strcat_str(str, len, tmplen, eltname);
623 str = strcat_char(str, len, tmplen, '>');
624 k = i;
625 /*i = p[k].index; */
626 /*j = i + p[k].nchild; */
627 i = (unsigned long)p[k].data & 0xffff;
628 j = i + ((unsigned long)p[k].data >> 16);
629 top++;
630 #ifdef DESC_DEBUG
631 printf("DBG: +pile[%d]\t%d %d\n", top, i, j);
632 #endif
633 pile[top].i = i;
634 pile[top].j = j;
635 pile[top].eltname = eltname;
640 /* genRootDesc() :
641 * - Generate the root description of the UPnP device.
642 * - the len argument is used to return the length of
643 * the returned string.
644 * - tmp_uuid argument is used to build the uuid string */
645 char *
646 genRootDesc(int * len)
648 char * str;
649 int tmplen;
650 tmplen = 2048;
651 str = (char *)malloc(tmplen);
652 if(str == NULL)
653 return NULL;
654 * len = strlen(xmlver);
655 /*strcpy(str, xmlver); */
656 memcpy(str, xmlver, *len + 1);
657 str = genXML(str, len, &tmplen, rootDesc);
658 str[*len] = '\0';
659 return str;
662 /* genServiceDesc() :
663 * Generate service description with allowed methods and
664 * related variables. */
665 static char *
666 genServiceDesc(int * len, const struct serviceDesc * s)
668 int i, j;
669 const struct action * acts;
670 const struct stateVar * vars;
671 const struct argument * args;
672 const char * p;
673 char * str;
674 int tmplen;
675 tmplen = 2048;
676 str = (char *)malloc(tmplen);
677 if(str == NULL)
678 return NULL;
679 /*strcpy(str, xmlver); */
680 *len = strlen(xmlver);
681 memcpy(str, xmlver, *len + 1);
683 acts = s->actionList;
684 vars = s->serviceStateTable;
686 str = strcat_char(str, len, &tmplen, '<');
687 str = strcat_str(str, len, &tmplen, root_service);
688 str = strcat_char(str, len, &tmplen, '>');
690 str = strcat_str(str, len, &tmplen,
691 "<specVersion><major>1</major><minor>0</minor></specVersion>");
693 i = 0;
694 str = strcat_str(str, len, &tmplen, "<actionList>");
695 while(acts[i].name)
697 str = strcat_str(str, len, &tmplen, "<action><name>");
698 str = strcat_str(str, len, &tmplen, acts[i].name);
699 str = strcat_str(str, len, &tmplen, "</name>");
700 /* argument List */
701 args = acts[i].args;
702 if(args)
704 str = strcat_str(str, len, &tmplen, "<argumentList>");
705 j = 0;
706 while(args[j].dir)
708 str = strcat_str(str, len, &tmplen, "<argument><name>");
709 p = vars[args[j].relatedVar].name;
710 str = strcat_str(str, len, &tmplen, (args[j].name ? args[j].name : p));
711 str = strcat_str(str, len, &tmplen, "</name><direction>");
712 str = strcat_str(str, len, &tmplen, args[j].dir==1?"in":"out");
713 str = strcat_str(str, len, &tmplen,
714 "</direction><relatedStateVariable>");
715 str = strcat_str(str, len, &tmplen, p);
716 str = strcat_str(str, len, &tmplen,
717 "</relatedStateVariable></argument>");
718 j++;
720 str = strcat_str(str, len, &tmplen,"</argumentList>");
722 str = strcat_str(str, len, &tmplen, "</action>");
723 /*str = strcat_char(str, len, &tmplen, '\n'); // TEMP ! */
724 i++;
726 str = strcat_str(str, len, &tmplen, "</actionList><serviceStateTable>");
727 i = 0;
728 while(vars[i].name)
730 str = strcat_str(str, len, &tmplen,
731 "<stateVariable sendEvents=\"");
732 str = strcat_str(str, len, &tmplen, (vars[i].itype & 0x80)?"yes":"no");
733 str = strcat_str(str, len, &tmplen, "\"><name>");
734 str = strcat_str(str, len, &tmplen, vars[i].name);
735 str = strcat_str(str, len, &tmplen, "</name><dataType>");
736 str = strcat_str(str, len, &tmplen, upnptypes[vars[i].itype & 0x0f]);
737 str = strcat_str(str, len, &tmplen, "</dataType>");
738 if(vars[i].iallowedlist)
740 str = strcat_str(str, len, &tmplen, "<allowedValueList>");
741 for(j=vars[i].iallowedlist; upnpallowedvalues[j]; j++)
743 str = strcat_str(str, len, &tmplen, "<allowedValue>");
744 str = strcat_str(str, len, &tmplen, upnpallowedvalues[j]);
745 str = strcat_str(str, len, &tmplen, "</allowedValue>");
747 str = strcat_str(str, len, &tmplen, "</allowedValueList>");
749 /*if(vars[i].defaultValue) */
750 if(vars[i].idefault)
752 str = strcat_str(str, len, &tmplen, "<defaultValue>");
753 /*str = strcat_str(str, len, &tmplen, vars[i].defaultValue); */
754 str = strcat_str(str, len, &tmplen, upnpdefaultvalues[vars[i].idefault]);
755 str = strcat_str(str, len, &tmplen, "</defaultValue>");
757 str = strcat_str(str, len, &tmplen, "</stateVariable>");
758 /*str = strcat_char(str, len, &tmplen, '\n'); // TEMP ! */
759 i++;
761 str = strcat_str(str, len, &tmplen, "</serviceStateTable></scpd>");
762 str[*len] = '\0';
763 return str;
766 /* genContentDirectory() :
767 * Generate the ContentDirectory xml description */
768 char *
769 genContentDirectory(int * len)
771 return genServiceDesc(len, &scpdContentDirectory);
774 /* genConnectionManager() :
775 * Generate the ConnectionManager xml description */
776 char *
777 genConnectionManager(int * len)
779 return genServiceDesc(len, &scpdConnectionManager);
782 /* genX_MS_MediaReceiverRegistrar() :
783 * Generate the X_MS_MediaReceiverRegistrar xml description */
784 char *
785 genX_MS_MediaReceiverRegistrar(int * len)
787 return genServiceDesc(len, &scpdX_MS_MediaReceiverRegistrar);
790 static char *
791 genEventVars(int * len, const struct serviceDesc * s, const char * servns)
793 const struct stateVar * v;
794 char * str;
795 int tmplen;
796 char buf[512];
797 tmplen = 512;
798 str = (char *)malloc(tmplen);
799 if(str == NULL)
800 return NULL;
801 *len = 0;
802 v = s->serviceStateTable;
803 snprintf(buf, sizeof(buf), "<e:propertyset xmlns:e=\"urn:schemas-upnp-org:event-1-0\" xmlns:s=\"%s\">", servns);
804 str = strcat_str(str, len, &tmplen, buf);
805 while(v->name) {
806 if(v->itype & 0x80) {
807 snprintf(buf, sizeof(buf), "<e:property><%s>", v->name);
808 str = strcat_str(str, len, &tmplen, buf);
809 //printf("<e:property><s:%s>", v->name);
810 switch(v->ieventvalue) {
811 case 0:
812 break;
813 case 255: /* Magical values should go around here */
814 if( strcmp(v->name, "SystemUpdateID") == 0 )
816 snprintf(buf, sizeof(buf), "%d", updateID);
817 str = strcat_str(str, len, &tmplen, buf);
819 break;
820 default:
821 str = strcat_str(str, len, &tmplen, upnpallowedvalues[v->ieventvalue]);
822 //printf("%s", upnpallowedvalues[v->ieventvalue]);
824 snprintf(buf, sizeof(buf), "</%s></e:property>", v->name);
825 str = strcat_str(str, len, &tmplen, buf);
826 //printf("</s:%s></e:property>\n", v->name);
828 v++;
830 str = strcat_str(str, len, &tmplen, "</e:propertyset>");
831 //printf("</e:propertyset>\n");
832 //printf("\n");
833 //printf("%d\n", tmplen);
834 str[*len] = '\0';
835 return str;
838 char *
839 getVarsContentDirectory(int * l)
841 return genEventVars(l,
842 &scpdContentDirectory,
843 "urn:schemas-upnp-org:service:ContentDirectory:1");
846 char *
847 getVarsConnectionManager(int * l)
849 return genEventVars(l,
850 &scpdConnectionManager,
851 "urn:schemas-upnp-org:service:ConnectionManager:1");
854 char *
855 getVarsX_MS_MediaReceiverRegistrar(int * l)
857 return genEventVars(l,
858 &scpdX_MS_MediaReceiverRegistrar,
859 "urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1");