dnsmasq: stay close as possible to master branch
[tomato.git] / release / src-rt-6.x.4708 / router / minidlna / upnpdescgen.c
blob46b07f38cda9b32a1a2a0d8793440aa3b89d082f
1 /* MiniUPnP project
2 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
4 * Copyright (c) 2006-2008, Thomas Bernard
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * * The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
33 #include "config.h"
34 #include "getifaddr.h"
35 #include "upnpdescgen.h"
36 #include "minidlnapath.h"
37 #include "upnpglobalvars.h"
38 #include "upnpdescstrings.h"
40 #undef DESC_DEBUG
42 static const char * const upnptypes[] =
44 "string",
45 "boolean",
46 "ui2",
47 "ui4",
48 "i4",
49 "uri",
50 "int",
51 "bin.base64"
54 static const char * const upnpdefaultvalues[] =
57 "Unconfigured"
60 static const char * const upnpallowedvalues[] =
62 0, /* 0 */
63 "DSL", /* 1 */
64 "POTS",
65 "Cable",
66 "Ethernet",
68 "Up", /* 6 */
69 "Down",
70 "Initializing",
71 "Unavailable",
73 "TCP", /* 11 */
74 "UDP",
76 "Unconfigured", /* 14 */
77 "IP_Routed",
78 "IP_Bridged",
80 "Unconfigured", /* 18 */
81 "Connecting",
82 "Connected",
83 "PendingDisconnect",
84 "Disconnecting",
85 "Disconnected",
87 "ERROR_NONE", /* 25 */
89 "OK", /* 27 */
90 "ContentFormatMismatch",
91 "InsufficientBandwidth",
92 "UnreliableChannel",
93 "Unknown",
95 "Input", /* 33 */
96 "Output",
98 "BrowseMetadata", /* 36 */
99 "BrowseDirectChildren",
101 "COMPLETED", /* 39 */
102 "ERROR",
103 "IN_PROGRESS",
104 "STOPPED",
106 RESOURCE_PROTOCOL_INFO_VALUES, /* 44 */
108 "0", /* 46 */
110 "", /* 48 */
114 static const char xmlver[] =
115 "<?xml version=\"1.0\"?>\r\n";
116 static const char root_service[] =
117 "scpd xmlns=\"urn:schemas-upnp-org:service-1-0\"";
118 static const char root_device[] =
119 "root xmlns=\"urn:schemas-upnp-org:device-1-0\""
120 #if PNPX
121 " xmlns:pnpx=\"http://schemas.microsoft.com/windows/pnpx/2005/11\""
122 " xmlns:df=\"http://schemas.microsoft.com/windows/2008/09/devicefoundation\""
123 #endif
126 /* root Description of the UPnP Device */
127 static const struct XMLElt rootDesc[] =
129 {root_device, INITHELPER(1,2)},
130 {"specVersion", INITHELPER(3,2)},
131 {"device", INITHELPER(5,(14+PNPX))},
132 {"/major", "1"},
133 {"/minor", "0"},
134 {"/deviceType", "urn:schemas-upnp-org:device:MediaServer:1"},
135 #if PNPX == 5
136 {"/pnpx:X_hardwareId", pnpx_hwid},
137 {"/pnpx:X_compatibleId", "MS_DigitalMediaDeviceClass_DMS_V001"},
138 {"/pnpx:X_deviceCategory", "MediaDevices"},
139 {"/df:X_deviceCategory", "Multimedia.DMS"},
140 {"/microsoft:magicPacketWakeSupported xmlns:microsoft=\"urn:schemas-microsoft-com:WMPNSS-1-0\"", "0"},
141 #endif
142 {"/friendlyName", friendly_name}, /* required */
143 {"/manufacturer", ROOTDEV_MANUFACTURER}, /* required */
144 {"/manufacturerURL", ROOTDEV_MANUFACTURERURL}, /* optional */
145 {"/modelDescription", ROOTDEV_MODELDESCRIPTION}, /* recommended */
146 {"/modelName", modelname}, /* required */
147 {"/modelNumber", modelnumber},
148 {"/modelURL", ROOTDEV_MODELURL},
149 {"/serialNumber", serialnumber},
150 {"/UDN", uuidvalue}, /* required */
151 {"/dlna:X_DLNADOC xmlns:dlna=\"urn:schemas-dlna-org:device-1-0\"", "DMS-1.50"},
152 {"/presentationURL", presentationurl}, /* recommended */
153 {"iconList", INITHELPER((19+PNPX),4)},
154 {"serviceList", INITHELPER((43+PNPX),3)},
155 {"icon", INITHELPER((23+PNPX),5)},
156 {"icon", INITHELPER((28+PNPX),5)},
157 {"icon", INITHELPER((33+PNPX),5)},
158 {"icon", INITHELPER((38+PNPX),5)},
159 {"/mimetype", "image/png"},
160 {"/width", "48"},
161 {"/height", "48"},
162 {"/depth", "24"},
163 {"/url", "/icons/sm.png"},
164 {"/mimetype", "image/png"},
165 {"/width", "120"},
166 {"/height", "120"},
167 {"/depth", "24"},
168 {"/url", "/icons/lrg.png"},
169 {"/mimetype", "image/jpeg"},
170 {"/width", "48"},
171 {"/height", "48"},
172 {"/depth", "24"},
173 {"/url", "/icons/sm.jpg"},
174 {"/mimetype", "image/jpeg"},
175 {"/width", "120"},
176 {"/height", "120"},
177 {"/depth", "24"},
178 {"/url", "/icons/lrg.jpg"},
179 {"service", INITHELPER((46+PNPX),5)},
180 {"service", INITHELPER((51+PNPX),5)},
181 {"service", INITHELPER((56+PNPX),5)},
182 {"/serviceType", "urn:schemas-upnp-org:service:ContentDirectory:1"},
183 {"/serviceId", "urn:upnp-org:serviceId:ContentDirectory"},
184 {"/controlURL", CONTENTDIRECTORY_CONTROLURL},
185 {"/eventSubURL", CONTENTDIRECTORY_EVENTURL},
186 {"/SCPDURL", CONTENTDIRECTORY_PATH},
187 {"/serviceType", "urn:schemas-upnp-org:service:ConnectionManager:1"},
188 {"/serviceId", "urn:upnp-org:serviceId:ConnectionManager"},
189 {"/controlURL", CONNECTIONMGR_CONTROLURL},
190 {"/eventSubURL", CONNECTIONMGR_EVENTURL},
191 {"/SCPDURL", CONNECTIONMGR_PATH},
192 {"/serviceType", "urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1"},
193 {"/serviceId", "urn:microsoft.com:serviceId:X_MS_MediaReceiverRegistrar"},
194 {"/controlURL", X_MS_MEDIARECEIVERREGISTRAR_CONTROLURL},
195 {"/eventSubURL", X_MS_MEDIARECEIVERREGISTRAR_EVENTURL},
196 {"/SCPDURL", X_MS_MEDIARECEIVERREGISTRAR_PATH},
197 {0, 0}
200 /* For ConnectionManager */
201 static const struct argument GetProtocolInfoArgs[] =
203 {"Source", 2, 0},
204 {"Sink", 2, 1},
205 {NULL, 0, 0}
208 static const struct argument PrepareForConnectionArgs[] =
210 {"RemoteProtocolInfo", 1, 6},
211 {"PeerConnectionManager", 1, 4},
212 {"PeerConnectionID", 1, 7},
213 {"Direction", 1, 5},
214 {"ConnectionID", 2, 7},
215 {"AVTransportID", 2, 8},
216 {"RcsID", 2, 9},
217 {NULL, 0, 0}
220 static const struct argument ConnectionCompleteArgs[] =
222 {"ConnectionID", 1, 7},
223 {NULL, 0, 0}
226 static const struct argument GetCurrentConnectionIDsArgs[] =
228 {"ConnectionIDs", 2, 2},
229 {NULL, 0, 0}
232 static const struct argument GetCurrentConnectionInfoArgs[] =
234 {"ConnectionID", 1, 7},
235 {"RcsID", 2, 9},
236 {"AVTransportID", 2, 8},
237 {"ProtocolInfo", 2, 6},
238 {"PeerConnectionManager", 2, 4},
239 {"PeerConnectionID", 2, 7},
240 {"Direction", 2, 5},
241 {"Status", 2, 3},
242 {NULL, 0, 0}
245 static const struct action ConnectionManagerActions[] =
247 {"GetProtocolInfo", GetProtocolInfoArgs}, /* R */
248 //OPTIONAL {"PrepareForConnection", PrepareForConnectionArgs}, /* R */
249 //OPTIONAL {"ConnectionComplete", ConnectionCompleteArgs}, /* R */
250 {"GetCurrentConnectionIDs", GetCurrentConnectionIDsArgs}, /* R */
251 {"GetCurrentConnectionInfo", GetCurrentConnectionInfoArgs}, /* R */
252 {0, 0}
255 static const struct stateVar ConnectionManagerVars[] =
257 {"SourceProtocolInfo", 0|EVENTED, 0, 0, 44}, /* required */
258 {"SinkProtocolInfo", 0|EVENTED, 0, 0, 48}, /* required */
259 {"CurrentConnectionIDs", 0|EVENTED, 0, 0, 46}, /* required */
260 {"A_ARG_TYPE_ConnectionStatus", 0, 0, 27}, /* required */
261 {"A_ARG_TYPE_ConnectionManager", 0, 0}, /* required */
262 {"A_ARG_TYPE_Direction", 0, 0, 33}, /* required */
263 {"A_ARG_TYPE_ProtocolInfo", 0, 0}, /* required */
264 {"A_ARG_TYPE_ConnectionID", 4, 0}, /* required */
265 {"A_ARG_TYPE_AVTransportID", 4, 0}, /* required */
266 {"A_ARG_TYPE_RcsID", 4, 0}, /* required */
267 {0, 0}
270 static const struct argument GetSearchCapabilitiesArgs[] =
272 {"SearchCaps", 2, 10},
273 {0, 0}
276 static const struct argument GetSortCapabilitiesArgs[] =
278 {"SortCaps", 2, 11},
279 {0, 0}
282 static const struct argument GetSystemUpdateIDArgs[] =
284 {"Id", 2, 12},
285 {0, 0}
288 static const struct argument BrowseArgs[] =
290 {"ObjectID", 1, 1},
291 {"BrowseFlag", 1, 4},
292 {"Filter", 1, 5},
293 {"StartingIndex", 1, 7},
294 {"RequestedCount", 1, 8},
295 {"SortCriteria", 1, 6},
296 {"Result", 2, 2},
297 {"NumberReturned", 2, 8},
298 {"TotalMatches", 2, 8},
299 {"UpdateID", 2, 9},
300 {0, 0}
303 static const struct argument SearchArgs[] =
305 {"ContainerID", 1, 1},
306 {"SearchCriteria", 1, 3},
307 {"Filter", 1, 5},
308 {"StartingIndex", 1, 7},
309 {"RequestedCount", 1, 8},
310 {"SortCriteria", 1, 6},
311 {"Result", 2, 2},
312 {"NumberReturned", 2, 8},
313 {"TotalMatches", 2, 8},
314 {"UpdateID", 2, 9},
315 {0, 0}
318 static const struct action ContentDirectoryActions[] =
320 {"GetSearchCapabilities", GetSearchCapabilitiesArgs}, /* R */
321 {"GetSortCapabilities", GetSortCapabilitiesArgs}, /* R */
322 {"GetSystemUpdateID", GetSystemUpdateIDArgs}, /* R */
323 {"Browse", BrowseArgs}, /* R */
324 {"Search", SearchArgs}, /* O */
325 #if 0 // Not implementing optional features yet...
326 {"CreateObject", CreateObjectArgs}, /* O */
327 {"DestroyObject", DestroyObjectArgs}, /* O */
328 {"UpdateObject", UpdateObjectArgs}, /* O */
329 {"ImportResource", ImportResourceArgs}, /* O */
330 {"ExportResource", ExportResourceArgs}, /* O */
331 {"StopTransferResource", StopTransferResourceArgs}, /* O */
332 {"GetTransferProgress", GetTransferProgressArgs}, /* O */
333 {"DeleteResource", DeleteResourceArgs}, /* O */
334 {"CreateReference", CreateReferenceArgs}, /* O */
335 #endif
336 {0, 0}
339 static const struct stateVar ContentDirectoryVars[] =
341 {"TransferIDs", 0|EVENTED, 0, 0, 48}, /* 0 */
342 {"A_ARG_TYPE_ObjectID", 0, 0},
343 {"A_ARG_TYPE_Result", 0, 0},
344 {"A_ARG_TYPE_SearchCriteria", 0, 0},
345 {"A_ARG_TYPE_BrowseFlag", 0, 0, 36},
346 /* Allowed Values : BrowseMetadata / BrowseDirectChildren */
347 {"A_ARG_TYPE_Filter", 0, 0}, /* 5 */
348 {"A_ARG_TYPE_SortCriteria", 0, 0},
349 {"A_ARG_TYPE_Index", 3, 0},
350 {"A_ARG_TYPE_Count", 3, 0},
351 {"A_ARG_TYPE_UpdateID", 3, 0},
352 {"SearchCapabilities", 0, 0},
353 {"SortCapabilities", 0, 0},
354 {"SystemUpdateID", 3|EVENTED, 0, 0, 255},
355 {0, 0}
358 static const struct argument GetIsAuthorizedArgs[] =
360 {"DeviceID", 1, 0},
361 {"Result", 2, 3},
362 {NULL, 0, 0}
365 static const struct argument GetIsValidatedArgs[] =
367 {"DeviceID", 1, 0},
368 {"Result", 2, 3},
369 {NULL, 0, 0}
372 static const struct argument GetRegisterDeviceArgs[] =
374 {"RegistrationReqMsg", 1, 1},
375 {"RegistrationRespMsg", 2, 2},
376 {NULL, 0, 0}
379 static const struct action X_MS_MediaReceiverRegistrarActions[] =
381 {"IsAuthorized", GetIsAuthorizedArgs}, /* R */
382 {"IsValidated", GetIsValidatedArgs}, /* R */
383 {"RegisterDevice", GetRegisterDeviceArgs},
384 {0, 0}
387 static const struct stateVar X_MS_MediaReceiverRegistrarVars[] =
389 {"A_ARG_TYPE_DeviceID", 0, 0},
390 {"A_ARG_TYPE_RegistrationReqMsg", 7, 0},
391 {"A_ARG_TYPE_RegistrationRespMsg", 7, 0},
392 {"A_ARG_TYPE_Result", 6, 0},
393 {"AuthorizationDeniedUpdateID", 3|EVENTED, 0},
394 {"AuthorizationGrantedUpdateID", 3|EVENTED, 0},
395 {"ValidationRevokedUpdateID", 3|EVENTED, 0},
396 {"ValidationSucceededUpdateID", 3|EVENTED, 0},
397 {0, 0}
400 static const struct serviceDesc scpdContentDirectory =
401 { ContentDirectoryActions, ContentDirectoryVars };
403 static const struct serviceDesc scpdConnectionManager =
404 { ConnectionManagerActions, ConnectionManagerVars };
406 static const struct serviceDesc scpdX_MS_MediaReceiverRegistrar =
407 { X_MS_MediaReceiverRegistrarActions, X_MS_MediaReceiverRegistrarVars };
409 /* strcat_str()
410 * concatenate the string and use realloc to increase the
411 * memory buffer if needed. */
412 static char *
413 strcat_str(char * str, int * len, int * tmplen, const char * s2)
415 char *p;
416 int s2len;
417 s2len = (int)strlen(s2);
418 if(*tmplen <= (*len + s2len))
420 if(s2len < 256)
421 *tmplen += 256;
422 else
423 *tmplen += s2len + 1;
424 p = realloc(str, *tmplen);
425 if (!p)
427 if(s2len < 256)
428 *tmplen -= 256;
429 else
430 *tmplen -= s2len + 1;
431 return str;
433 else
434 str = p;
436 /*strcpy(str + *len, s2); */
437 memcpy(str + *len, s2, s2len + 1);
438 *len += s2len;
439 return str;
442 /* strcat_char() :
443 * concatenate a character and use realloc to increase the
444 * size of the memory buffer if needed */
445 static char *
446 strcat_char(char * str, int * len, int * tmplen, char c)
448 char *p;
449 if(*tmplen <= (*len + 1))
451 *tmplen += 256;
452 p = (char *)realloc(str, *tmplen);
453 if (!p)
455 *tmplen -= 256;
456 return str;
458 else
459 str = p;
461 str[*len] = c;
462 (*len)++;
463 return str;
466 /* iterative subroutine using a small stack
467 * This way, the progam stack usage is kept low */
468 static char *
469 genXML(char * str, int * len, int * tmplen,
470 const struct XMLElt * p)
472 uint16_t i, j, k;
473 int top;
474 const char * eltname, *s;
475 char c;
476 char element[64];
477 struct {
478 unsigned short i;
479 unsigned short j;
480 const char * eltname;
481 } pile[16]; /* stack */
482 top = -1;
483 i = 0; /* current node */
484 j = 1; /* i + number of nodes*/
485 for(;;)
487 eltname = p[i].eltname;
488 if(!eltname)
489 return str;
490 if(eltname[0] == '/')
492 #ifdef DESC_DEBUG
493 printf("DBG: <%s>%s<%s>\n", eltname+1, p[i].data, eltname);
494 #endif
495 str = strcat_char(str, len, tmplen, '<');
496 str = strcat_str(str, len, tmplen, eltname+1);
497 str = strcat_char(str, len, tmplen, '>');
498 str = strcat_str(str, len, tmplen, p[i].data);
499 str = strcat_char(str, len, tmplen, '<');
500 sscanf(eltname, "%s", element);
501 str = strcat_str(str, len, tmplen, element);
502 str = strcat_char(str, len, tmplen, '>');
503 for(;;)
505 if(top < 0)
506 return str;
507 i = ++(pile[top].i);
508 j = pile[top].j;
509 #ifdef DESC_DEBUG
510 printf("DBG: pile[%d]\t%d %d\n", top, i, j);
511 #endif
512 if(i==j)
514 #ifdef DESC_DEBUG
515 printf("DBG: i==j, </%s>\n", pile[top].eltname);
516 #endif
517 str = strcat_char(str, len, tmplen, '<');
518 str = strcat_char(str, len, tmplen, '/');
519 s = pile[top].eltname;
520 for(c = *s; c > ' '; c = *(++s))
521 str = strcat_char(str, len, tmplen, c);
522 str = strcat_char(str, len, tmplen, '>');
523 top--;
525 else
526 break;
529 else
531 #ifdef DESC_DEBUG
532 printf("DBG: [%d] <%s>\n", i, eltname);
533 #endif
534 str = strcat_char(str, len, tmplen, '<');
535 str = strcat_str(str, len, tmplen, eltname);
536 str = strcat_char(str, len, tmplen, '>');
537 k = i;
538 /*i = p[k].index; */
539 /*j = i + p[k].nchild; */
540 i = (unsigned long)p[k].data & 0xffff;
541 j = i + ((unsigned long)p[k].data >> 16);
542 top++;
543 #ifdef DESC_DEBUG
544 printf("DBG: +pile[%d]\t%d %d\n", top, i, j);
545 #endif
546 pile[top].i = i;
547 pile[top].j = j;
548 pile[top].eltname = eltname;
553 /* genRootDesc() :
554 * - Generate the root description of the UPnP device.
555 * - the len argument is used to return the length of
556 * the returned string.
557 * - tmp_uuid argument is used to build the uuid string */
558 char *
559 genRootDesc(int * len)
561 char * str;
562 int tmplen;
563 tmplen = 2560;
564 str = (char *)malloc(tmplen);
565 if(str == NULL)
566 return NULL;
567 * len = strlen(xmlver);
568 memcpy(str, xmlver, *len + 1);
569 str = genXML(str, len, &tmplen, rootDesc);
570 str[*len] = '\0';
571 return str;
574 char *
575 genRootDescSamsung(int * len)
577 char * str;
578 int tmplen;
579 struct XMLElt samsungRootDesc[sizeof(rootDesc)/sizeof(struct XMLElt)];
580 tmplen = 2560;
581 str = (char *)malloc(tmplen);
582 if(str == NULL)
583 return NULL;
584 * len = strlen(xmlver);
585 memcpy(str, xmlver, *len + 1);
586 /* Replace the optional modelURL and manufacturerURL fields with Samsung foo */
587 memcpy(&samsungRootDesc, &rootDesc, sizeof(rootDesc));
588 samsungRootDesc[8+PNPX].eltname = "/sec:ProductCap";
589 samsungRootDesc[8+PNPX].data = "smi,DCM10,getMediaInfo.sec,getCaptionInfo.sec";
590 samsungRootDesc[12+PNPX].eltname = "/sec:X_ProductCap";
591 samsungRootDesc[12+PNPX].data = "smi,DCM10,getMediaInfo.sec,getCaptionInfo.sec";
592 str = genXML(str, len, &tmplen, samsungRootDesc);
593 str[*len] = '\0';
594 return str;
597 /* genServiceDesc() :
598 * Generate service description with allowed methods and
599 * related variables. */
600 static char *
601 genServiceDesc(int * len, const struct serviceDesc * s)
603 int i, j;
604 const struct action * acts;
605 const struct stateVar * vars;
606 const struct argument * args;
607 const char * p;
608 char * str;
609 int tmplen;
610 tmplen = 2048;
611 str = (char *)malloc(tmplen);
612 if(str == NULL)
613 return NULL;
614 /*strcpy(str, xmlver); */
615 *len = strlen(xmlver);
616 memcpy(str, xmlver, *len + 1);
618 acts = s->actionList;
619 vars = s->serviceStateTable;
621 str = strcat_char(str, len, &tmplen, '<');
622 str = strcat_str(str, len, &tmplen, root_service);
623 str = strcat_char(str, len, &tmplen, '>');
625 str = strcat_str(str, len, &tmplen,
626 "<specVersion><major>1</major><minor>0</minor></specVersion>");
628 i = 0;
629 str = strcat_str(str, len, &tmplen, "<actionList>");
630 while(acts[i].name)
632 str = strcat_str(str, len, &tmplen, "<action><name>");
633 str = strcat_str(str, len, &tmplen, acts[i].name);
634 str = strcat_str(str, len, &tmplen, "</name>");
635 /* argument List */
636 args = acts[i].args;
637 if(args)
639 str = strcat_str(str, len, &tmplen, "<argumentList>");
640 j = 0;
641 while(args[j].dir)
643 str = strcat_str(str, len, &tmplen, "<argument><name>");
644 p = vars[args[j].relatedVar].name;
645 str = strcat_str(str, len, &tmplen, (args[j].name ? args[j].name : p));
646 str = strcat_str(str, len, &tmplen, "</name><direction>");
647 str = strcat_str(str, len, &tmplen, args[j].dir==1?"in":"out");
648 str = strcat_str(str, len, &tmplen,
649 "</direction><relatedStateVariable>");
650 str = strcat_str(str, len, &tmplen, p);
651 str = strcat_str(str, len, &tmplen,
652 "</relatedStateVariable></argument>");
653 j++;
655 str = strcat_str(str, len, &tmplen,"</argumentList>");
657 str = strcat_str(str, len, &tmplen, "</action>");
658 /*str = strcat_char(str, len, &tmplen, '\n'); // TEMP ! */
659 i++;
661 str = strcat_str(str, len, &tmplen, "</actionList><serviceStateTable>");
662 i = 0;
663 while(vars[i].name)
665 str = strcat_str(str, len, &tmplen,
666 "<stateVariable sendEvents=\"");
667 str = strcat_str(str, len, &tmplen, (vars[i].itype & EVENTED)?"yes":"no");
668 str = strcat_str(str, len, &tmplen, "\"><name>");
669 str = strcat_str(str, len, &tmplen, vars[i].name);
670 str = strcat_str(str, len, &tmplen, "</name><dataType>");
671 str = strcat_str(str, len, &tmplen, upnptypes[vars[i].itype & 0x0f]);
672 str = strcat_str(str, len, &tmplen, "</dataType>");
673 if(vars[i].iallowedlist)
675 str = strcat_str(str, len, &tmplen, "<allowedValueList>");
676 for(j=vars[i].iallowedlist; upnpallowedvalues[j]; j++)
678 str = strcat_str(str, len, &tmplen, "<allowedValue>");
679 str = strcat_str(str, len, &tmplen, upnpallowedvalues[j]);
680 str = strcat_str(str, len, &tmplen, "</allowedValue>");
682 str = strcat_str(str, len, &tmplen, "</allowedValueList>");
684 /*if(vars[i].defaultValue) */
685 if(vars[i].idefault)
687 str = strcat_str(str, len, &tmplen, "<defaultValue>");
688 /*str = strcat_str(str, len, &tmplen, vars[i].defaultValue); */
689 str = strcat_str(str, len, &tmplen, upnpdefaultvalues[vars[i].idefault]);
690 str = strcat_str(str, len, &tmplen, "</defaultValue>");
692 str = strcat_str(str, len, &tmplen, "</stateVariable>");
693 /*str = strcat_char(str, len, &tmplen, '\n'); // TEMP ! */
694 i++;
696 str = strcat_str(str, len, &tmplen, "</serviceStateTable></scpd>");
697 str[*len] = '\0';
698 return str;
701 /* genContentDirectory() :
702 * Generate the ContentDirectory xml description */
703 char *
704 genContentDirectory(int * len)
706 return genServiceDesc(len, &scpdContentDirectory);
709 /* genConnectionManager() :
710 * Generate the ConnectionManager xml description */
711 char *
712 genConnectionManager(int * len)
714 return genServiceDesc(len, &scpdConnectionManager);
717 /* genX_MS_MediaReceiverRegistrar() :
718 * Generate the X_MS_MediaReceiverRegistrar xml description */
719 char *
720 genX_MS_MediaReceiverRegistrar(int * len)
722 return genServiceDesc(len, &scpdX_MS_MediaReceiverRegistrar);
725 static char *
726 genEventVars(int * len, const struct serviceDesc * s, const char * servns)
728 const struct stateVar * v;
729 char * str;
730 int tmplen;
731 char buf[512];
732 tmplen = 512;
733 str = (char *)malloc(tmplen);
734 if(str == NULL)
735 return NULL;
736 *len = 0;
737 v = s->serviceStateTable;
738 snprintf(buf, sizeof(buf), "<e:propertyset xmlns:e=\"urn:schemas-upnp-org:event-1-0\" xmlns:s=\"%s\">", servns);
739 str = strcat_str(str, len, &tmplen, buf);
740 while(v->name) {
741 if(v->itype & EVENTED) {
742 snprintf(buf, sizeof(buf), "<e:property><%s>", v->name);
743 str = strcat_str(str, len, &tmplen, buf);
744 //printf("<e:property><s:%s>", v->name);
745 switch(v->ieventvalue) {
746 case 0:
747 break;
748 case 255: /* Magical values should go around here */
749 if( strcmp(v->name, "SystemUpdateID") == 0 )
751 snprintf(buf, sizeof(buf), "%d", updateID);
752 str = strcat_str(str, len, &tmplen, buf);
754 break;
755 default:
756 str = strcat_str(str, len, &tmplen, upnpallowedvalues[v->ieventvalue]);
757 //printf("%s", upnpallowedvalues[v->ieventvalue]);
759 snprintf(buf, sizeof(buf), "</%s></e:property>", v->name);
760 str = strcat_str(str, len, &tmplen, buf);
761 //printf("</s:%s></e:property>\n", v->name);
763 v++;
765 str = strcat_str(str, len, &tmplen, "</e:propertyset>");
766 //printf("</e:propertyset>\n");
767 //printf("\n");
768 //printf("%d\n", tmplen);
769 str[*len] = '\0';
770 return str;
773 char *
774 getVarsContentDirectory(int * l)
776 return genEventVars(l,
777 &scpdContentDirectory,
778 "urn:schemas-upnp-org:service:ContentDirectory:1");
781 char *
782 getVarsConnectionManager(int * l)
784 return genEventVars(l,
785 &scpdConnectionManager,
786 "urn:schemas-upnp-org:service:ConnectionManager:1");
789 char *
790 getVarsX_MS_MediaReceiverRegistrar(int * l)
792 return genEventVars(l,
793 &scpdX_MS_MediaReceiverRegistrar,
794 "urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1");