Wrap up version 1.3.3.
[minidlna.git] / upnpdescgen.c
blob3311cefa5a119ddac760acd667834eb8ff8a7d84
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 "event.h"
35 #include "getifaddr.h"
36 #include "upnpdescgen.h"
37 #include "minidlnapath.h"
38 #include "upnpglobalvars.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\"";
121 /* root Description of the UPnP Device */
122 static const struct XMLElt rootDesc[] =
124 {root_device, INITHELPER(1,2)},
125 {"specVersion", INITHELPER(3,2)},
126 {"device", INITHELPER(5,(14))},
127 {"/major", "1"},
128 {"/minor", "0"},
129 {"/deviceType", "urn:schemas-upnp-org:device:MediaServer:1"},
130 {"/friendlyName", friendly_name}, /* required */
131 {"/manufacturer", ROOTDEV_MANUFACTURER}, /* required */
132 {"/manufacturerURL", ROOTDEV_MANUFACTURERURL}, /* optional */
133 {"/modelDescription", ROOTDEV_MODELDESCRIPTION}, /* recommended */
134 {"/modelName", modelname}, /* required */
135 {"/modelNumber", modelnumber},
136 {"/modelURL", ROOTDEV_MODELURL},
137 {"/serialNumber", serialnumber},
138 {"/UDN", uuidvalue}, /* required */
139 {"/dlna:X_DLNADOC xmlns:dlna=\"urn:schemas-dlna-org:device-1-0\"", "DMS-1.50"},
140 {"/presentationURL", presentationurl}, /* recommended */
141 {"iconList", INITHELPER((19),4)},
142 {"serviceList", INITHELPER((43),3)},
143 {"icon", INITHELPER((23),5)},
144 {"icon", INITHELPER((28),5)},
145 {"icon", INITHELPER((33),5)},
146 {"icon", INITHELPER((38),5)},
147 {"/mimetype", "image/png"},
148 {"/width", "48"},
149 {"/height", "48"},
150 {"/depth", "24"},
151 {"/url", "/icons/sm.png"},
152 {"/mimetype", "image/png"},
153 {"/width", "120"},
154 {"/height", "120"},
155 {"/depth", "24"},
156 {"/url", "/icons/lrg.png"},
157 {"/mimetype", "image/jpeg"},
158 {"/width", "48"},
159 {"/height", "48"},
160 {"/depth", "24"},
161 {"/url", "/icons/sm.jpg"},
162 {"/mimetype", "image/jpeg"},
163 {"/width", "120"},
164 {"/height", "120"},
165 {"/depth", "24"},
166 {"/url", "/icons/lrg.jpg"},
167 {"service", INITHELPER((46),5)},
168 {"service", INITHELPER((51),5)},
169 {"service", INITHELPER((56),5)},
170 {"/serviceType", "urn:schemas-upnp-org:service:ContentDirectory:1"},
171 {"/serviceId", "urn:upnp-org:serviceId:ContentDirectory"},
172 {"/controlURL", CONTENTDIRECTORY_CONTROLURL},
173 {"/eventSubURL", CONTENTDIRECTORY_EVENTURL},
174 {"/SCPDURL", CONTENTDIRECTORY_PATH},
175 {"/serviceType", "urn:schemas-upnp-org:service:ConnectionManager:1"},
176 {"/serviceId", "urn:upnp-org:serviceId:ConnectionManager"},
177 {"/controlURL", CONNECTIONMGR_CONTROLURL},
178 {"/eventSubURL", CONNECTIONMGR_EVENTURL},
179 {"/SCPDURL", CONNECTIONMGR_PATH},
180 {"/serviceType", "urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1"},
181 {"/serviceId", "urn:microsoft.com:serviceId:X_MS_MediaReceiverRegistrar"},
182 {"/controlURL", X_MS_MEDIARECEIVERREGISTRAR_CONTROLURL},
183 {"/eventSubURL", X_MS_MEDIARECEIVERREGISTRAR_EVENTURL},
184 {"/SCPDURL", X_MS_MEDIARECEIVERREGISTRAR_PATH},
185 {0, 0}
188 /* For ConnectionManager */
189 static const struct argument GetProtocolInfoArgs[] =
191 {"Source", 2, 0},
192 {"Sink", 2, 1},
193 {NULL, 0, 0}
196 static const struct argument GetCurrentConnectionIDsArgs[] =
198 {"ConnectionIDs", 2, 2},
199 {NULL, 0, 0}
202 static const struct argument GetCurrentConnectionInfoArgs[] =
204 {"ConnectionID", 1, 7},
205 {"RcsID", 2, 9},
206 {"AVTransportID", 2, 8},
207 {"ProtocolInfo", 2, 6},
208 {"PeerConnectionManager", 2, 4},
209 {"PeerConnectionID", 2, 7},
210 {"Direction", 2, 5},
211 {"Status", 2, 3},
212 {NULL, 0, 0}
215 static const struct action ConnectionManagerActions[] =
217 {"GetProtocolInfo", GetProtocolInfoArgs}, /* R */
218 {"GetCurrentConnectionIDs", GetCurrentConnectionIDsArgs}, /* R */
219 {"GetCurrentConnectionInfo", GetCurrentConnectionInfoArgs}, /* R */
220 {0, 0}
223 static const struct stateVar ConnectionManagerVars[] =
225 {"SourceProtocolInfo", 0|EVENTED, 0, 0, 44}, /* required */
226 {"SinkProtocolInfo", 0|EVENTED, 0, 0, 48}, /* required */
227 {"CurrentConnectionIDs", 0|EVENTED, 0, 0, 46}, /* required */
228 {"A_ARG_TYPE_ConnectionStatus", 0, 0, 27}, /* required */
229 {"A_ARG_TYPE_ConnectionManager", 0, 0}, /* required */
230 {"A_ARG_TYPE_Direction", 0, 0, 33}, /* required */
231 {"A_ARG_TYPE_ProtocolInfo", 0, 0}, /* required */
232 {"A_ARG_TYPE_ConnectionID", 4, 0}, /* required */
233 {"A_ARG_TYPE_AVTransportID", 4, 0}, /* required */
234 {"A_ARG_TYPE_RcsID", 4, 0}, /* required */
235 {0, 0}
238 static const struct argument GetSearchCapabilitiesArgs[] =
240 {"SearchCaps", 2, 11},
241 {0, 0}
244 static const struct argument GetSortCapabilitiesArgs[] =
246 {"SortCaps", 2, 12},
247 {0, 0}
250 static const struct argument GetSystemUpdateIDArgs[] =
252 {"Id", 2, 13},
253 {0, 0}
256 static const struct argument UpdateObjectArgs[] =
258 {"ObjectID", 1, 1},
259 {"CurrentTagValue", 1, 10},
260 {"NewTagValue", 1, 10},
261 {0, 0}
264 static const struct argument BrowseArgs[] =
266 {"ObjectID", 1, 1},
267 {"BrowseFlag", 1, 4},
268 {"Filter", 1, 5},
269 {"StartingIndex", 1, 7},
270 {"RequestedCount", 1, 8},
271 {"SortCriteria", 1, 6},
272 {"Result", 2, 2},
273 {"NumberReturned", 2, 8},
274 {"TotalMatches", 2, 8},
275 {"UpdateID", 2, 9},
276 {0, 0}
279 static const struct argument SearchArgs[] =
281 {"ContainerID", 1, 1},
282 {"SearchCriteria", 1, 3},
283 {"Filter", 1, 5},
284 {"StartingIndex", 1, 7},
285 {"RequestedCount", 1, 8},
286 {"SortCriteria", 1, 6},
287 {"Result", 2, 2},
288 {"NumberReturned", 2, 8},
289 {"TotalMatches", 2, 8},
290 {"UpdateID", 2, 9},
291 {0, 0}
294 static const struct action ContentDirectoryActions[] =
296 {"GetSearchCapabilities", GetSearchCapabilitiesArgs}, /* R */
297 {"GetSortCapabilities", GetSortCapabilitiesArgs}, /* R */
298 {"GetSystemUpdateID", GetSystemUpdateIDArgs}, /* R */
299 {"Browse", BrowseArgs}, /* R */
300 {"Search", SearchArgs}, /* O */
301 {"UpdateObject", UpdateObjectArgs}, /* O */
302 #if 0 // Not implementing optional features yet...
303 {"CreateObject", CreateObjectArgs}, /* O */
304 {"DestroyObject", DestroyObjectArgs}, /* O */
305 {"ImportResource", ImportResourceArgs}, /* O */
306 {"ExportResource", ExportResourceArgs}, /* O */
307 {"StopTransferResource", StopTransferResourceArgs}, /* O */
308 {"GetTransferProgress", GetTransferProgressArgs}, /* O */
309 {"DeleteResource", DeleteResourceArgs}, /* O */
310 {"CreateReference", CreateReferenceArgs}, /* O */
311 #endif
312 {0, 0}
315 static const struct stateVar ContentDirectoryVars[] =
317 {"TransferIDs", 0|EVENTED, 0, 0, 48}, /* 0 */
318 {"A_ARG_TYPE_ObjectID", 0, 0},
319 {"A_ARG_TYPE_Result", 0, 0},
320 {"A_ARG_TYPE_SearchCriteria", 0, 0},
321 {"A_ARG_TYPE_BrowseFlag", 0, 0, 36},
322 /* Allowed Values : BrowseMetadata / BrowseDirectChildren */
323 {"A_ARG_TYPE_Filter", 0, 0}, /* 5 */
324 {"A_ARG_TYPE_SortCriteria", 0, 0},
325 {"A_ARG_TYPE_Index", 3, 0},
326 {"A_ARG_TYPE_Count", 3, 0},
327 {"A_ARG_TYPE_UpdateID", 3, 0},
328 {"A_ARG_TYPE_TagValueList", 0, 0},
329 {"SearchCapabilities", 0, 0},
330 {"SortCapabilities", 0, 0},
331 {"SystemUpdateID", 3|EVENTED, 0, 0, 255},
332 {0, 0}
335 static const struct argument GetIsAuthorizedArgs[] =
337 {"DeviceID", 1, 0},
338 {"Result", 2, 3},
339 {NULL, 0, 0}
342 static const struct argument GetIsValidatedArgs[] =
344 {"DeviceID", 1, 0},
345 {"Result", 2, 3},
346 {NULL, 0, 0}
349 static const struct argument GetRegisterDeviceArgs[] =
351 {"RegistrationReqMsg", 1, 1},
352 {"RegistrationRespMsg", 2, 2},
353 {NULL, 0, 0}
356 static const struct action X_MS_MediaReceiverRegistrarActions[] =
358 {"IsAuthorized", GetIsAuthorizedArgs}, /* R */
359 {"IsValidated", GetIsValidatedArgs}, /* R */
360 {"RegisterDevice", GetRegisterDeviceArgs},
361 {0, 0}
364 static const struct stateVar X_MS_MediaReceiverRegistrarVars[] =
366 {"A_ARG_TYPE_DeviceID", 0, 0},
367 {"A_ARG_TYPE_RegistrationReqMsg", 7, 0},
368 {"A_ARG_TYPE_RegistrationRespMsg", 7, 0},
369 {"A_ARG_TYPE_Result", 6, 0},
370 {"AuthorizationDeniedUpdateID", 3|EVENTED, 0},
371 {"AuthorizationGrantedUpdateID", 3|EVENTED, 0},
372 {"ValidationRevokedUpdateID", 3|EVENTED, 0},
373 {"ValidationSucceededUpdateID", 3|EVENTED, 0},
374 {0, 0}
377 static const struct serviceDesc scpdContentDirectory =
378 { ContentDirectoryActions, ContentDirectoryVars };
380 static const struct serviceDesc scpdConnectionManager =
381 { ConnectionManagerActions, ConnectionManagerVars };
383 static const struct serviceDesc scpdX_MS_MediaReceiverRegistrar =
384 { X_MS_MediaReceiverRegistrarActions, X_MS_MediaReceiverRegistrarVars };
386 /* strcat_str()
387 * concatenate the string and use realloc to increase the
388 * memory buffer if needed. */
389 static char *
390 strcat_str(char * str, int * len, int * tmplen, const char * s2)
392 char *p;
393 int s2len;
394 s2len = (int)strlen(s2);
395 if(*tmplen <= (*len + s2len))
397 if(s2len < 256)
398 *tmplen += 256;
399 else
400 *tmplen += s2len + 1;
401 p = realloc(str, *tmplen);
402 if (!p)
404 if(s2len < 256)
405 *tmplen -= 256;
406 else
407 *tmplen -= s2len + 1;
408 return str;
410 else
411 str = p;
413 /*strcpy(str + *len, s2); */
414 memcpy(str + *len, s2, s2len + 1);
415 *len += s2len;
416 return str;
419 /* strcat_char() :
420 * concatenate a character and use realloc to increase the
421 * size of the memory buffer if needed */
422 static char *
423 strcat_char(char * str, int * len, int * tmplen, char c)
425 char *p;
426 if(*tmplen <= (*len + 1))
428 *tmplen += 256;
429 p = (char *)realloc(str, *tmplen);
430 if (!p)
432 *tmplen -= 256;
433 return str;
435 else
436 str = p;
438 str[*len] = c;
439 (*len)++;
440 return str;
443 /* iterative subroutine using a small stack
444 * This way, the progam stack usage is kept low */
445 static char *
446 genXML(char * str, int * len, int * tmplen,
447 const struct XMLElt * p)
449 uint16_t i, j, k;
450 int top;
451 const char * eltname, *s;
452 char c;
453 char element[64];
454 struct {
455 unsigned short i;
456 unsigned short j;
457 const char * eltname;
458 } pile[16]; /* stack */
459 top = -1;
460 i = 0; /* current node */
461 j = 1; /* i + number of nodes*/
462 for(;;)
464 eltname = p[i].eltname;
465 if(!eltname)
466 return str;
467 if(eltname[0] == '/')
469 #ifdef DESC_DEBUG
470 printf("DBG: <%s>%s<%s>\n", eltname+1, p[i].data, eltname);
471 #endif
472 str = strcat_char(str, len, tmplen, '<');
473 str = strcat_str(str, len, tmplen, eltname+1);
474 str = strcat_char(str, len, tmplen, '>');
475 str = strcat_str(str, len, tmplen, p[i].data);
476 str = strcat_char(str, len, tmplen, '<');
477 sscanf(eltname, "%s", element);
478 str = strcat_str(str, len, tmplen, element);
479 str = strcat_char(str, len, tmplen, '>');
480 for(;;)
482 if(top < 0)
483 return str;
484 i = ++(pile[top].i);
485 j = pile[top].j;
486 #ifdef DESC_DEBUG
487 printf("DBG: pile[%d]\t%d %d\n", top, i, j);
488 #endif
489 if(i==j)
491 #ifdef DESC_DEBUG
492 printf("DBG: i==j, </%s>\n", pile[top].eltname);
493 #endif
494 str = strcat_char(str, len, tmplen, '<');
495 str = strcat_char(str, len, tmplen, '/');
496 s = pile[top].eltname;
497 for(c = *s; c > ' '; c = *(++s))
498 str = strcat_char(str, len, tmplen, c);
499 str = strcat_char(str, len, tmplen, '>');
500 top--;
502 else
503 break;
506 else
508 #ifdef DESC_DEBUG
509 printf("DBG: [%d] <%s>\n", i, eltname);
510 #endif
511 str = strcat_char(str, len, tmplen, '<');
512 str = strcat_str(str, len, tmplen, eltname);
513 str = strcat_char(str, len, tmplen, '>');
514 k = i;
515 /*i = p[k].index; */
516 /*j = i + p[k].nchild; */
517 i = (unsigned long)p[k].data & 0xffff;
518 j = i + ((unsigned long)p[k].data >> 16);
519 top++;
520 #ifdef DESC_DEBUG
521 printf("DBG: +pile[%d]\t%d %d\n", top, i, j);
522 #endif
523 pile[top].i = i;
524 pile[top].j = j;
525 pile[top].eltname = eltname;
530 /* genRootDesc() :
531 * - Generate the root description of the UPnP device.
532 * - the len argument is used to return the length of
533 * the returned string.
534 * - tmp_uuid argument is used to build the uuid string */
535 char *
536 genRootDesc(int * len)
538 char * str;
539 int tmplen;
540 tmplen = 2560;
541 str = (char *)malloc(tmplen);
542 if(str == NULL)
543 return NULL;
544 * len = strlen(xmlver);
545 memcpy(str, xmlver, *len + 1);
546 str = genXML(str, len, &tmplen, rootDesc);
547 str[*len] = '\0';
548 return str;
551 char *
552 genRootDescSamsung(int * len)
554 char * str;
555 int tmplen;
556 struct XMLElt samsungRootDesc[sizeof(rootDesc)/sizeof(struct XMLElt)];
557 tmplen = 2560;
558 str = (char *)malloc(tmplen);
559 if(str == NULL)
560 return NULL;
561 * len = strlen(xmlver);
562 memcpy(str, xmlver, *len + 1);
563 /* Replace the optional modelURL and manufacturerURL fields with Samsung foo */
564 memcpy(&samsungRootDesc, &rootDesc, sizeof(rootDesc));
565 samsungRootDesc[8].eltname = "/sec:ProductCap";
566 samsungRootDesc[8].data = "smi,DCM10,getMediaInfo.sec,getCaptionInfo.sec";
567 samsungRootDesc[12].eltname = "/sec:X_ProductCap";
568 samsungRootDesc[12].data = "smi,DCM10,getMediaInfo.sec,getCaptionInfo.sec";
569 str = genXML(str, len, &tmplen, samsungRootDesc);
570 str[*len] = '\0';
571 return str;
574 /* genServiceDesc() :
575 * Generate service description with allowed methods and
576 * related variables. */
577 static char *
578 genServiceDesc(int * len, const struct serviceDesc * s)
580 int i, j;
581 const struct action * acts;
582 const struct stateVar * vars;
583 const struct argument * args;
584 const char * p;
585 char * str;
586 int tmplen;
587 tmplen = 2048;
588 str = (char *)malloc(tmplen);
589 if(str == NULL)
590 return NULL;
591 /*strcpy(str, xmlver); */
592 *len = strlen(xmlver);
593 memcpy(str, xmlver, *len + 1);
595 acts = s->actionList;
596 vars = s->serviceStateTable;
598 str = strcat_char(str, len, &tmplen, '<');
599 str = strcat_str(str, len, &tmplen, root_service);
600 str = strcat_char(str, len, &tmplen, '>');
602 str = strcat_str(str, len, &tmplen,
603 "<specVersion><major>1</major><minor>0</minor></specVersion>");
605 i = 0;
606 str = strcat_str(str, len, &tmplen, "<actionList>");
607 while(acts[i].name)
609 str = strcat_str(str, len, &tmplen, "<action><name>");
610 str = strcat_str(str, len, &tmplen, acts[i].name);
611 str = strcat_str(str, len, &tmplen, "</name>");
612 /* argument List */
613 args = acts[i].args;
614 if(args)
616 str = strcat_str(str, len, &tmplen, "<argumentList>");
617 j = 0;
618 while(args[j].dir)
620 str = strcat_str(str, len, &tmplen, "<argument><name>");
621 p = vars[args[j].relatedVar].name;
622 str = strcat_str(str, len, &tmplen, (args[j].name ? args[j].name : p));
623 str = strcat_str(str, len, &tmplen, "</name><direction>");
624 str = strcat_str(str, len, &tmplen, args[j].dir==1?"in":"out");
625 str = strcat_str(str, len, &tmplen,
626 "</direction><relatedStateVariable>");
627 str = strcat_str(str, len, &tmplen, p);
628 str = strcat_str(str, len, &tmplen,
629 "</relatedStateVariable></argument>");
630 j++;
632 str = strcat_str(str, len, &tmplen,"</argumentList>");
634 str = strcat_str(str, len, &tmplen, "</action>");
635 /*str = strcat_char(str, len, &tmplen, '\n'); // TEMP ! */
636 i++;
638 str = strcat_str(str, len, &tmplen, "</actionList><serviceStateTable>");
639 i = 0;
640 while(vars[i].name)
642 str = strcat_str(str, len, &tmplen,
643 "<stateVariable sendEvents=\"");
644 str = strcat_str(str, len, &tmplen, (vars[i].itype & EVENTED)?"yes":"no");
645 str = strcat_str(str, len, &tmplen, "\"><name>");
646 str = strcat_str(str, len, &tmplen, vars[i].name);
647 str = strcat_str(str, len, &tmplen, "</name><dataType>");
648 str = strcat_str(str, len, &tmplen, upnptypes[vars[i].itype & 0x0f]);
649 str = strcat_str(str, len, &tmplen, "</dataType>");
650 if(vars[i].iallowedlist)
652 str = strcat_str(str, len, &tmplen, "<allowedValueList>");
653 for(j=vars[i].iallowedlist; upnpallowedvalues[j]; j++)
655 str = strcat_str(str, len, &tmplen, "<allowedValue>");
656 str = strcat_str(str, len, &tmplen, upnpallowedvalues[j]);
657 str = strcat_str(str, len, &tmplen, "</allowedValue>");
659 str = strcat_str(str, len, &tmplen, "</allowedValueList>");
661 /*if(vars[i].defaultValue) */
662 if(vars[i].idefault)
664 str = strcat_str(str, len, &tmplen, "<defaultValue>");
665 /*str = strcat_str(str, len, &tmplen, vars[i].defaultValue); */
666 str = strcat_str(str, len, &tmplen, upnpdefaultvalues[vars[i].idefault]);
667 str = strcat_str(str, len, &tmplen, "</defaultValue>");
669 str = strcat_str(str, len, &tmplen, "</stateVariable>");
670 /*str = strcat_char(str, len, &tmplen, '\n'); // TEMP ! */
671 i++;
673 str = strcat_str(str, len, &tmplen, "</serviceStateTable></scpd>");
674 str[*len] = '\0';
675 return str;
678 /* genContentDirectory() :
679 * Generate the ContentDirectory xml description */
680 char *
681 genContentDirectory(int * len)
683 return genServiceDesc(len, &scpdContentDirectory);
686 /* genConnectionManager() :
687 * Generate the ConnectionManager xml description */
688 char *
689 genConnectionManager(int * len)
691 return genServiceDesc(len, &scpdConnectionManager);
694 /* genX_MS_MediaReceiverRegistrar() :
695 * Generate the X_MS_MediaReceiverRegistrar xml description */
696 char *
697 genX_MS_MediaReceiverRegistrar(int * len)
699 return genServiceDesc(len, &scpdX_MS_MediaReceiverRegistrar);
702 static char *
703 genEventVars(int * len, const struct serviceDesc * s, const char * servns)
705 const struct stateVar * v;
706 char * str;
707 int tmplen;
708 char buf[512];
709 tmplen = 512;
710 str = (char *)malloc(tmplen);
711 if(str == NULL)
712 return NULL;
713 *len = 0;
714 v = s->serviceStateTable;
715 snprintf(buf, sizeof(buf), "<e:propertyset xmlns:e=\"urn:schemas-upnp-org:event-1-0\" xmlns:s=\"%s\">", servns);
716 str = strcat_str(str, len, &tmplen, buf);
717 while(v->name) {
718 if(v->itype & EVENTED) {
719 snprintf(buf, sizeof(buf), "<e:property><%s>", v->name);
720 str = strcat_str(str, len, &tmplen, buf);
721 //printf("<e:property><s:%s>", v->name);
722 switch(v->ieventvalue) {
723 case 0:
724 break;
725 case 255: /* Magical values should go around here */
726 if( strcmp(v->name, "SystemUpdateID") == 0 )
728 snprintf(buf, sizeof(buf), "%d", updateID);
729 str = strcat_str(str, len, &tmplen, buf);
731 break;
732 default:
733 str = strcat_str(str, len, &tmplen, upnpallowedvalues[v->ieventvalue]);
734 //printf("%s", upnpallowedvalues[v->ieventvalue]);
736 snprintf(buf, sizeof(buf), "</%s></e:property>", v->name);
737 str = strcat_str(str, len, &tmplen, buf);
738 //printf("</s:%s></e:property>\n", v->name);
740 v++;
742 str = strcat_str(str, len, &tmplen, "</e:propertyset>");
743 //printf("</e:propertyset>\n");
744 //printf("\n");
745 //printf("%d\n", tmplen);
746 str[*len] = '\0';
747 return str;
750 char *
751 getVarsContentDirectory(int * l)
753 return genEventVars(l,
754 &scpdContentDirectory,
755 "urn:schemas-upnp-org:service:ContentDirectory:1");
758 char *
759 getVarsConnectionManager(int * l)
761 return genEventVars(l,
762 &scpdConnectionManager,
763 "urn:schemas-upnp-org:service:ConnectionManager:1");
766 char *
767 getVarsX_MS_MediaReceiverRegistrar(int * l)
769 return genEventVars(l,
770 &scpdX_MS_MediaReceiverRegistrar,
771 "urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1");