dnscrypto-proxy: Update to release 1.3.0
[tomato.git] / release / src / router / minidlna / upnpdescgen.c
blobc3b94e03beafb4405992bc74fa9387a47bc210aa
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 static const struct argument AddPortMappingArgs[] =
202 {NULL, 1, 11},
203 {NULL, 1, 12},
204 {NULL, 1, 14},
205 {NULL, 1, 13},
206 {NULL, 1, 15},
207 {NULL, 1, 9},
208 {NULL, 1, 16},
209 {NULL, 1, 10},
210 {NULL, 0, 0}
213 static const struct argument DeletePortMappingArgs[] =
215 {NULL, 1, 11},
216 {NULL, 1, 12},
217 {NULL, 1, 14},
218 {NULL, 0, 0}
221 static const struct argument SetConnectionTypeArgs[] =
223 {NULL, 1, 0},
224 {NULL, 0, 0}
227 static const struct argument GetConnectionTypeInfoArgs[] =
229 {NULL, 2, 0},
230 {NULL, 2, 1},
231 {NULL, 0, 0}
234 static const struct argument GetNATRSIPStatusArgs[] =
236 {NULL, 2, 5},
237 {NULL, 2, 6},
238 {NULL, 0, 0}
241 static const struct argument GetGenericPortMappingEntryArgs[] =
243 {NULL, 1, 8},
244 {NULL, 2, 11},
245 {NULL, 2, 12},
246 {NULL, 2, 14},
247 {NULL, 2, 13},
248 {NULL, 2, 15},
249 {NULL, 2, 9},
250 {NULL, 2, 16},
251 {NULL, 2, 10},
252 {NULL, 0, 0}
255 static const struct argument GetSpecificPortMappingEntryArgs[] =
257 {NULL, 1, 11},
258 {NULL, 1, 12},
259 {NULL, 1, 14},
260 {NULL, 2, 13},
261 {NULL, 2, 15},
262 {NULL, 2, 9},
263 {NULL, 2, 16},
264 {NULL, 2, 10},
265 {NULL, 0, 0}
268 /* For ConnectionManager */
269 static const struct argument GetProtocolInfoArgs[] =
271 {"Source", 2, 0},
272 {"Sink", 2, 1},
273 {NULL, 0, 0}
276 static const struct argument PrepareForConnectionArgs[] =
278 {"RemoteProtocolInfo", 1, 6},
279 {"PeerConnectionManager", 1, 4},
280 {"PeerConnectionID", 1, 7},
281 {"Direction", 1, 5},
282 {"ConnectionID", 2, 7},
283 {"AVTransportID", 2, 8},
284 {"RcsID", 2, 9},
285 {NULL, 0, 0}
288 static const struct argument ConnectionCompleteArgs[] =
290 {"ConnectionID", 1, 7},
291 {NULL, 0, 0}
294 static const struct argument GetCurrentConnectionIDsArgs[] =
296 {"ConnectionIDs", 2, 2},
297 {NULL, 0, 0}
300 static const struct argument GetCurrentConnectionInfoArgs[] =
302 {"ConnectionID", 1, 7},
303 {"RcsID", 2, 9},
304 {"AVTransportID", 2, 8},
305 {"ProtocolInfo", 2, 6},
306 {"PeerConnectionManager", 2, 4},
307 {"PeerConnectionID", 2, 7},
308 {"Direction", 2, 5},
309 {"Status", 2, 3},
310 {NULL, 0, 0}
313 static const struct action ConnectionManagerActions[] =
315 {"GetProtocolInfo", GetProtocolInfoArgs}, /* R */
316 //OPTIONAL {"PrepareForConnection", PrepareForConnectionArgs}, /* R */
317 //OPTIONAL {"ConnectionComplete", ConnectionCompleteArgs}, /* R */
318 {"GetCurrentConnectionIDs", GetCurrentConnectionIDsArgs}, /* R */
319 {"GetCurrentConnectionInfo", GetCurrentConnectionInfoArgs}, /* R */
320 {0, 0}
323 static const struct stateVar ConnectionManagerVars[] =
325 {"SourceProtocolInfo", 1<<7, 0, 0, 44}, /* required */
326 {"SinkProtocolInfo", 1<<7, 0, 0, 48}, /* required */
327 {"CurrentConnectionIDs", 1<<7, 0, 0, 46}, /* required */
328 {"A_ARG_TYPE_ConnectionStatus", 0, 0, 27}, /* required */
329 {"A_ARG_TYPE_ConnectionManager", 0, 0}, /* required */
330 {"A_ARG_TYPE_Direction", 0, 0, 33}, /* required */
331 {"A_ARG_TYPE_ProtocolInfo", 0, 0}, /* required */
332 {"A_ARG_TYPE_ConnectionID", 4, 0}, /* required */
333 {"A_ARG_TYPE_AVTransportID", 4, 0}, /* required */
334 {"A_ARG_TYPE_RcsID", 4, 0}, /* required */
335 {0, 0}
338 static const struct argument GetSearchCapabilitiesArgs[] =
340 {"SearchCaps", 2, 10},
341 {0, 0}
344 static const struct argument GetSortCapabilitiesArgs[] =
346 {"SortCaps", 2, 11},
347 {0, 0}
350 static const struct argument GetSystemUpdateIDArgs[] =
352 {"Id", 2, 12},
353 {0, 0}
356 static const struct argument BrowseArgs[] =
358 {"ObjectID", 1, 1},
359 {"BrowseFlag", 1, 4},
360 {"Filter", 1, 5},
361 {"StartingIndex", 1, 7},
362 {"RequestedCount", 1, 8},
363 {"SortCriteria", 1, 6},
364 {"Result", 2, 2},
365 {"NumberReturned", 2, 8},
366 {"TotalMatches", 2, 8},
367 {"UpdateID", 2, 9},
368 {0, 0}
371 static const struct argument SearchArgs[] =
373 {"ContainerID", 1, 1},
374 {"SearchCriteria", 1, 3},
375 {"Filter", 1, 5},
376 {"StartingIndex", 1, 7},
377 {"RequestedCount", 1, 8},
378 {"SortCriteria", 1, 6},
379 {"Result", 2, 2},
380 {"NumberReturned", 2, 8},
381 {"TotalMatches", 2, 8},
382 {"UpdateID", 2, 9},
383 {0, 0}
386 static const struct action ContentDirectoryActions[] =
388 {"GetSearchCapabilities", GetSearchCapabilitiesArgs}, /* R */
389 {"GetSortCapabilities", GetSortCapabilitiesArgs}, /* R */
390 {"GetSystemUpdateID", GetSystemUpdateIDArgs}, /* R */
391 {"Browse", BrowseArgs}, /* R */
392 {"Search", SearchArgs}, /* O */
393 #if 0 // Not implementing optional features yet...
394 {"CreateObject", CreateObjectArgs}, /* O */
395 {"DestroyObject", DestroyObjectArgs}, /* O */
396 {"UpdateObject", UpdateObjectArgs}, /* O */
397 {"ImportResource", ImportResourceArgs}, /* O */
398 {"ExportResource", ExportResourceArgs}, /* O */
399 {"StopTransferResource", StopTransferResourceArgs}, /* O */
400 {"GetTransferProgress", GetTransferProgressArgs}, /* O */
401 {"DeleteResource", DeleteResourceArgs}, /* O */
402 {"CreateReference", CreateReferenceArgs}, /* O */
403 #endif
404 {0, 0}
407 static const struct stateVar ContentDirectoryVars[] =
409 {"TransferIDs", 1<<7, 0, 0, 48}, /* 0 */
410 {"A_ARG_TYPE_ObjectID", 0, 0},
411 {"A_ARG_TYPE_Result", 0, 0},
412 {"A_ARG_TYPE_SearchCriteria", 0, 0},
413 {"A_ARG_TYPE_BrowseFlag", 0, 0, 36},
414 /* Allowed Values : BrowseMetadata / BrowseDirectChildren */
415 {"A_ARG_TYPE_Filter", 0, 0}, /* 5 */
416 {"A_ARG_TYPE_SortCriteria", 0, 0},
417 {"A_ARG_TYPE_Index", 3, 0},
418 {"A_ARG_TYPE_Count", 3, 0},
419 {"A_ARG_TYPE_UpdateID", 3, 0},
420 //JM{"A_ARG_TYPE_TransferID", 3, 0}, /* 10 */
421 //JM{"A_ARG_TYPE_TransferStatus", 0, 0, 39},
422 /* Allowed Values : COMPLETED / ERROR / IN_PROGRESS / STOPPED */
423 //JM{"A_ARG_TYPE_TransferLength", 0, 0},
424 //JM{"A_ARG_TYPE_TransferTotal", 0, 0},
425 //JM{"A_ARG_TYPE_TagValueList", 0, 0},
426 //JM{"A_ARG_TYPE_URI", 5, 0}, /* 15 */
427 {"SearchCapabilities", 0, 0},
428 {"SortCapabilities", 0, 0},
429 {"SystemUpdateID", 3|0x80, 0, 0, 255},
430 //{"ContainerUpdateIDs", 0, 0},
431 {0, 0}
434 static const struct argument GetIsAuthorizedArgs[] =
436 {"DeviceID", 1, 0},
437 {"Result", 2, 3},
438 {NULL, 0, 0}
441 static const struct argument GetIsValidatedArgs[] =
443 {"DeviceID", 1, 0},
444 {"Result", 2, 3},
445 {NULL, 0, 0}
448 static const struct argument GetRegisterDeviceArgs[] =
450 {"RegistrationReqMsg", 1, 1},
451 {"RegistrationRespMsg", 2, 2},
452 {NULL, 0, 0}
455 static const struct action X_MS_MediaReceiverRegistrarActions[] =
457 {"IsAuthorized", GetIsAuthorizedArgs}, /* R */
458 {"IsValidated", GetIsValidatedArgs}, /* R */
459 #if 0 // Not needed? WMP12 still works. Need to check with 360 and WMP11.
460 {"RegisterDevice", GetRegisterDeviceArgs}, /* R */
461 #endif
462 {0, 0}
465 static const struct stateVar X_MS_MediaReceiverRegistrarVars[] =
467 {"A_ARG_TYPE_DeviceID", 0, 0},
468 {"A_ARG_TYPE_RegistrationReqMsg", 7, 0},
469 {"A_ARG_TYPE_RegistrationRespMsg", 7, 0},
470 {"A_ARG_TYPE_Result", 6, 0},
471 {"AuthorizationDeniedUpdateID", 3, 0},
472 {"AuthorizationGrantedUpdateID", 3, 0},
473 {"ValidationRevokedUpdateID", 3, 0},
474 {"ValidationSucceededUpdateID", 3, 0},
475 {0, 0}
478 /* WANCfg.xml */
479 /* See UPnP_IGD_WANCommonInterfaceConfig 1.0.pdf */
481 static const struct argument GetCommonLinkPropertiesArgs[] =
483 {NULL, 2, 0},
484 {NULL, 2, 1},
485 {NULL, 2, 2},
486 {NULL, 2, 3},
487 {NULL, 0, 0}
490 static const struct argument GetTotalBytesSentArgs[] =
492 {NULL, 2, 4},
493 {NULL, 0, 0}
496 static const struct argument GetTotalBytesReceivedArgs[] =
498 {NULL, 2, 5},
499 {NULL, 0, 0}
502 static const struct argument GetTotalPacketsSentArgs[] =
504 {NULL, 2, 6},
505 {NULL, 0, 0}
508 static const struct argument GetTotalPacketsReceivedArgs[] =
510 {NULL, 2, 7},
511 {NULL, 0, 0}
514 static const struct serviceDesc scpdContentDirectory =
515 { ContentDirectoryActions, ContentDirectoryVars };
517 static const struct serviceDesc scpdConnectionManager =
518 { ConnectionManagerActions, ConnectionManagerVars };
520 static const struct serviceDesc scpdX_MS_MediaReceiverRegistrar =
521 { X_MS_MediaReceiverRegistrarActions, X_MS_MediaReceiverRegistrarVars };
523 /* strcat_str()
524 * concatenate the string and use realloc to increase the
525 * memory buffer if needed. */
526 static char *
527 strcat_str(char * str, int * len, int * tmplen, const char * s2)
529 char *p;
530 int s2len;
531 s2len = (int)strlen(s2);
532 if(*tmplen <= (*len + s2len))
534 if(s2len < 256)
535 *tmplen += 256;
536 else
537 *tmplen += s2len + 1;
538 p = realloc(str, *tmplen);
539 if (!p)
541 if(s2len < 256)
542 *tmplen -= 256;
543 else
544 *tmplen -= s2len + 1;
545 return str;
547 else
548 str = p;
550 /*strcpy(str + *len, s2); */
551 memcpy(str + *len, s2, s2len + 1);
552 *len += s2len;
553 return str;
556 /* strcat_char() :
557 * concatenate a character and use realloc to increase the
558 * size of the memory buffer if needed */
559 static char *
560 strcat_char(char * str, int * len, int * tmplen, char c)
562 char *p;
563 if(*tmplen <= (*len + 1))
565 *tmplen += 256;
566 p = (char *)realloc(str, *tmplen);
567 if (!p)
569 *tmplen -= 256;
570 return str;
572 else
573 str = p;
575 str[*len] = c;
576 (*len)++;
577 return str;
580 /* iterative subroutine using a small stack
581 * This way, the progam stack usage is kept low */
582 static char *
583 genXML(char * str, int * len, int * tmplen,
584 const struct XMLElt * p)
586 u_int16_t i, j, k;
587 int top;
588 const char * eltname, *s;
589 char c;
590 char element[64];
591 struct {
592 unsigned short i;
593 unsigned short j;
594 const char * eltname;
595 } pile[16]; /* stack */
596 top = -1;
597 i = 0; /* current node */
598 j = 1; /* i + number of nodes*/
599 for(;;)
601 eltname = p[i].eltname;
602 if(!eltname)
603 return str;
604 if(eltname[0] == '/')
606 #ifdef DESC_DEBUG
607 printf("DBG: <%s>%s<%s>\n", eltname+1, p[i].data, eltname);
608 #endif
609 str = strcat_char(str, len, tmplen, '<');
610 str = strcat_str(str, len, tmplen, eltname+1);
611 str = strcat_char(str, len, tmplen, '>');
612 str = strcat_str(str, len, tmplen, p[i].data);
613 str = strcat_char(str, len, tmplen, '<');
614 sscanf(eltname, "%s", element);
615 str = strcat_str(str, len, tmplen, element);
616 str = strcat_char(str, len, tmplen, '>');
617 for(;;)
619 if(top < 0)
620 return str;
621 i = ++(pile[top].i);
622 j = pile[top].j;
623 #ifdef DESC_DEBUG
624 printf("DBG: pile[%d]\t%d %d\n", top, i, j);
625 #endif
626 if(i==j)
628 #ifdef DESC_DEBUG
629 printf("DBG: i==j, </%s>\n", pile[top].eltname);
630 #endif
631 str = strcat_char(str, len, tmplen, '<');
632 str = strcat_char(str, len, tmplen, '/');
633 s = pile[top].eltname;
634 for(c = *s; c > ' '; c = *(++s))
635 str = strcat_char(str, len, tmplen, c);
636 str = strcat_char(str, len, tmplen, '>');
637 top--;
639 else
640 break;
643 else
645 #ifdef DESC_DEBUG
646 printf("DBG: [%d] <%s>\n", i, eltname);
647 #endif
648 str = strcat_char(str, len, tmplen, '<');
649 str = strcat_str(str, len, tmplen, eltname);
650 str = strcat_char(str, len, tmplen, '>');
651 k = i;
652 /*i = p[k].index; */
653 /*j = i + p[k].nchild; */
654 i = (unsigned long)p[k].data & 0xffff;
655 j = i + ((unsigned long)p[k].data >> 16);
656 top++;
657 #ifdef DESC_DEBUG
658 printf("DBG: +pile[%d]\t%d %d\n", top, i, j);
659 #endif
660 pile[top].i = i;
661 pile[top].j = j;
662 pile[top].eltname = eltname;
667 /* genRootDesc() :
668 * - Generate the root description of the UPnP device.
669 * - the len argument is used to return the length of
670 * the returned string.
671 * - tmp_uuid argument is used to build the uuid string */
672 char *
673 genRootDesc(int * len)
675 char * str;
676 int tmplen;
677 tmplen = 2560;
678 str = (char *)malloc(tmplen);
679 if(str == NULL)
680 return NULL;
681 * len = strlen(xmlver);
682 memcpy(str, xmlver, *len + 1);
683 str = genXML(str, len, &tmplen, rootDesc);
684 str[*len] = '\0';
685 return str;
688 char *
689 genRootDescSamsung(int * len)
691 char * str;
692 int tmplen;
693 struct XMLElt samsungRootDesc[sizeof(rootDesc)/sizeof(struct XMLElt)];
694 tmplen = 2560;
695 str = (char *)malloc(tmplen);
696 if(str == NULL)
697 return NULL;
698 * len = strlen(xmlver);
699 memcpy(str, xmlver, *len + 1);
700 /* Replace the optional modelURL and manufacturerURL fields with Samsung foo */
701 memcpy(&samsungRootDesc, &rootDesc, sizeof(rootDesc));
702 samsungRootDesc[8+PNPX].eltname = "/sec:ProductCap";
703 samsungRootDesc[8+PNPX].data = "smi,DCM10,getMediaInfo.sec,getCaptionInfo.sec";
704 samsungRootDesc[12+PNPX].eltname = "/sec:X_ProductCap";
705 samsungRootDesc[12+PNPX].data = "smi,DCM10,getMediaInfo.sec,getCaptionInfo.sec";
706 str = genXML(str, len, &tmplen, samsungRootDesc);
707 str[*len] = '\0';
708 return str;
711 /* genServiceDesc() :
712 * Generate service description with allowed methods and
713 * related variables. */
714 static char *
715 genServiceDesc(int * len, const struct serviceDesc * s)
717 int i, j;
718 const struct action * acts;
719 const struct stateVar * vars;
720 const struct argument * args;
721 const char * p;
722 char * str;
723 int tmplen;
724 tmplen = 2048;
725 str = (char *)malloc(tmplen);
726 if(str == NULL)
727 return NULL;
728 /*strcpy(str, xmlver); */
729 *len = strlen(xmlver);
730 memcpy(str, xmlver, *len + 1);
732 acts = s->actionList;
733 vars = s->serviceStateTable;
735 str = strcat_char(str, len, &tmplen, '<');
736 str = strcat_str(str, len, &tmplen, root_service);
737 str = strcat_char(str, len, &tmplen, '>');
739 str = strcat_str(str, len, &tmplen,
740 "<specVersion><major>1</major><minor>0</minor></specVersion>");
742 i = 0;
743 str = strcat_str(str, len, &tmplen, "<actionList>");
744 while(acts[i].name)
746 str = strcat_str(str, len, &tmplen, "<action><name>");
747 str = strcat_str(str, len, &tmplen, acts[i].name);
748 str = strcat_str(str, len, &tmplen, "</name>");
749 /* argument List */
750 args = acts[i].args;
751 if(args)
753 str = strcat_str(str, len, &tmplen, "<argumentList>");
754 j = 0;
755 while(args[j].dir)
757 str = strcat_str(str, len, &tmplen, "<argument><name>");
758 p = vars[args[j].relatedVar].name;
759 str = strcat_str(str, len, &tmplen, (args[j].name ? args[j].name : p));
760 str = strcat_str(str, len, &tmplen, "</name><direction>");
761 str = strcat_str(str, len, &tmplen, args[j].dir==1?"in":"out");
762 str = strcat_str(str, len, &tmplen,
763 "</direction><relatedStateVariable>");
764 str = strcat_str(str, len, &tmplen, p);
765 str = strcat_str(str, len, &tmplen,
766 "</relatedStateVariable></argument>");
767 j++;
769 str = strcat_str(str, len, &tmplen,"</argumentList>");
771 str = strcat_str(str, len, &tmplen, "</action>");
772 /*str = strcat_char(str, len, &tmplen, '\n'); // TEMP ! */
773 i++;
775 str = strcat_str(str, len, &tmplen, "</actionList><serviceStateTable>");
776 i = 0;
777 while(vars[i].name)
779 str = strcat_str(str, len, &tmplen,
780 "<stateVariable sendEvents=\"");
781 str = strcat_str(str, len, &tmplen, (vars[i].itype & 0x80)?"yes":"no");
782 str = strcat_str(str, len, &tmplen, "\"><name>");
783 str = strcat_str(str, len, &tmplen, vars[i].name);
784 str = strcat_str(str, len, &tmplen, "</name><dataType>");
785 str = strcat_str(str, len, &tmplen, upnptypes[vars[i].itype & 0x0f]);
786 str = strcat_str(str, len, &tmplen, "</dataType>");
787 if(vars[i].iallowedlist)
789 str = strcat_str(str, len, &tmplen, "<allowedValueList>");
790 for(j=vars[i].iallowedlist; upnpallowedvalues[j]; j++)
792 str = strcat_str(str, len, &tmplen, "<allowedValue>");
793 str = strcat_str(str, len, &tmplen, upnpallowedvalues[j]);
794 str = strcat_str(str, len, &tmplen, "</allowedValue>");
796 str = strcat_str(str, len, &tmplen, "</allowedValueList>");
798 /*if(vars[i].defaultValue) */
799 if(vars[i].idefault)
801 str = strcat_str(str, len, &tmplen, "<defaultValue>");
802 /*str = strcat_str(str, len, &tmplen, vars[i].defaultValue); */
803 str = strcat_str(str, len, &tmplen, upnpdefaultvalues[vars[i].idefault]);
804 str = strcat_str(str, len, &tmplen, "</defaultValue>");
806 str = strcat_str(str, len, &tmplen, "</stateVariable>");
807 /*str = strcat_char(str, len, &tmplen, '\n'); // TEMP ! */
808 i++;
810 str = strcat_str(str, len, &tmplen, "</serviceStateTable></scpd>");
811 str[*len] = '\0';
812 return str;
815 /* genContentDirectory() :
816 * Generate the ContentDirectory xml description */
817 char *
818 genContentDirectory(int * len)
820 return genServiceDesc(len, &scpdContentDirectory);
823 /* genConnectionManager() :
824 * Generate the ConnectionManager xml description */
825 char *
826 genConnectionManager(int * len)
828 return genServiceDesc(len, &scpdConnectionManager);
831 /* genX_MS_MediaReceiverRegistrar() :
832 * Generate the X_MS_MediaReceiverRegistrar xml description */
833 char *
834 genX_MS_MediaReceiverRegistrar(int * len)
836 return genServiceDesc(len, &scpdX_MS_MediaReceiverRegistrar);
839 static char *
840 genEventVars(int * len, const struct serviceDesc * s, const char * servns)
842 const struct stateVar * v;
843 char * str;
844 int tmplen;
845 char buf[512];
846 tmplen = 512;
847 str = (char *)malloc(tmplen);
848 if(str == NULL)
849 return NULL;
850 *len = 0;
851 v = s->serviceStateTable;
852 snprintf(buf, sizeof(buf), "<e:propertyset xmlns:e=\"urn:schemas-upnp-org:event-1-0\" xmlns:s=\"%s\">", servns);
853 str = strcat_str(str, len, &tmplen, buf);
854 while(v->name) {
855 if(v->itype & 0x80) {
856 snprintf(buf, sizeof(buf), "<e:property><%s>", v->name);
857 str = strcat_str(str, len, &tmplen, buf);
858 //printf("<e:property><s:%s>", v->name);
859 switch(v->ieventvalue) {
860 case 0:
861 break;
862 case 255: /* Magical values should go around here */
863 if( strcmp(v->name, "SystemUpdateID") == 0 )
865 snprintf(buf, sizeof(buf), "%d", updateID);
866 str = strcat_str(str, len, &tmplen, buf);
868 break;
869 default:
870 str = strcat_str(str, len, &tmplen, upnpallowedvalues[v->ieventvalue]);
871 //printf("%s", upnpallowedvalues[v->ieventvalue]);
873 snprintf(buf, sizeof(buf), "</%s></e:property>", v->name);
874 str = strcat_str(str, len, &tmplen, buf);
875 //printf("</s:%s></e:property>\n", v->name);
877 v++;
879 str = strcat_str(str, len, &tmplen, "</e:propertyset>");
880 //printf("</e:propertyset>\n");
881 //printf("\n");
882 //printf("%d\n", tmplen);
883 str[*len] = '\0';
884 return str;
887 char *
888 getVarsContentDirectory(int * l)
890 return genEventVars(l,
891 &scpdContentDirectory,
892 "urn:schemas-upnp-org:service:ContentDirectory:1");
895 char *
896 getVarsConnectionManager(int * l)
898 return genEventVars(l,
899 &scpdConnectionManager,
900 "urn:schemas-upnp-org:service:ConnectionManager:1");
903 char *
904 getVarsX_MS_MediaReceiverRegistrar(int * l)
906 return genEventVars(l,
907 &scpdX_MS_MediaReceiverRegistrar,
908 "urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1");