source: titan/minidlna-1.0.22/upnpdescgen.c @ 13567

Last change on this file since 13567 was 13567, checked in by obi, 11 years ago

[titan] add minidlna-1.0.22 first step

File size: 22.8 KB
Line 
1/* $Id: upnpdescgen.c,v 1.18 2011/05/02 23:50:52 jmaggard Exp $ */
2/* MiniUPnP project
3 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
4 *
5 * Copyright (c) 2006-2008, Thomas Bernard
6 * All rights reserved.
7 *
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.
17 *
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.
29 */
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33
34#include "config.h"
35#include "getifaddr.h"
36#include "upnpdescgen.h"
37#include "minidlnapath.h"
38#include "upnpglobalvars.h"
39#include "upnpdescstrings.h"
40
41#undef DESC_DEBUG
42
43static const char * const upnptypes[] =
44{
45        "string",
46        "boolean",
47        "ui2",
48        "ui4",
49        "i4",
50        "uri",
51        "int",
52        "bin.base64"
53};
54
55static const char * const upnpdefaultvalues[] =
56{
57        0,
58        "Unconfigured"
59};
60
61static const char * const upnpallowedvalues[] =
62{
63        0,                      /* 0 */
64        "DSL",                  /* 1 */
65        "POTS",
66        "Cable",
67        "Ethernet",
68        0,
69        "Up",                   /* 6 */
70        "Down",
71        "Initializing",
72        "Unavailable",
73        0,
74        "TCP",                  /* 11 */
75        "UDP",
76        0,
77        "Unconfigured",         /* 14 */
78        "IP_Routed",
79        "IP_Bridged",
80        0,
81        "Unconfigured",         /* 18 */
82        "Connecting",
83        "Connected",
84        "PendingDisconnect",
85        "Disconnecting",
86        "Disconnected",
87        0,
88        "ERROR_NONE",           /* 25 */
89        0,
90        "OK",                   /* 27 */
91        "ContentFormatMismatch",
92        "InsufficientBandwidth",
93        "UnreliableChannel",
94        "Unknown",
95        0,
96        "Input",                /* 33 */
97        "Output",
98        0,
99        "BrowseMetadata",       /* 36 */
100        "BrowseDirectChildren",
101        0,
102        "COMPLETED",            /* 39 */
103        "ERROR",
104        "IN_PROGRESS",
105        "STOPPED",
106        0,
107        RESOURCE_PROTOCOL_INFO_VALUES,          /* 44 */
108        0,
109        "0",                    /* 46 */
110        0,
111        "",                     /* 48 */
112        0
113};
114
115static const char xmlver[] =
116        "<?xml version=\"1.0\"?>\r\n";
117static const char root_service[] =
118        "scpd xmlns=\"urn:schemas-upnp-org:service-1-0\"";
119static const char root_device[] =
120        "root xmlns=\"urn:schemas-upnp-org:device-1-0\""
121#if PNPX
122        " xmlns:pnpx=\"http://schemas.microsoft.com/windows/pnpx/2005/11\""
123        " xmlns:df=\"http://schemas.microsoft.com/windows/2008/09/devicefoundation\""
124#endif
125        ;
126
127/* root Description of the UPnP Device */
128static const struct XMLElt rootDesc[] =
129{
130        {root_device, INITHELPER(1,2)},
131        {"specVersion", INITHELPER(3,2)},
132        {"device", INITHELPER(5,(14+PNPX))},
133        {"/major", "1"},
134        {"/minor", "0"},
135        {"/deviceType", "urn:schemas-upnp-org:device:MediaServer:1"},
136#if PNPX == 5
137        {"/pnpx:X_hardwareId", pnpx_hwid},
138        {"/pnpx:X_compatibleId", "MS_DigitalMediaDeviceClass_DMS_V001"},
139        {"/pnpx:X_deviceCategory", "MediaDevices"},
140        {"/df:X_deviceCategory", "Multimedia.DMS"},
141        {"/microsoft:magicPacketWakeSupported xmlns:microsoft=\"urn:schemas-microsoft-com:WMPNSS-1-0\"", "0"},
142#endif
143        {"/friendlyName", friendly_name},       /* required */
144        {"/manufacturer", ROOTDEV_MANUFACTURER},                /* required */
145        {"/manufacturerURL", ROOTDEV_MANUFACTURERURL},  /* optional */
146        {"/modelDescription", ROOTDEV_MODELDESCRIPTION}, /* recommended */
147        {"/modelName", modelname},      /* required */
148        {"/modelNumber", modelnumber},
149        {"/modelURL", ROOTDEV_MODELURL},
150        {"/serialNumber", serialnumber},
151        {"/UDN", uuidvalue},    /* required */
152        {"/dlna:X_DLNADOC xmlns:dlna=\"urn:schemas-dlna-org:device-1-0\"", "DMS-1.50"},
153        {"/presentationURL", presentationurl},  /* recommended */
154        {"iconList", INITHELPER((19+PNPX),4)},
155        {"serviceList", INITHELPER((43+PNPX),3)},
156        {"icon", INITHELPER((23+PNPX),5)},
157        {"icon", INITHELPER((28+PNPX),5)},
158        {"icon", INITHELPER((33+PNPX),5)},
159        {"icon", INITHELPER((38+PNPX),5)},
160        {"/mimetype", "image/png"},
161        {"/width", "48"},
162        {"/height", "48"},
163        {"/depth", "24"},
164        {"/url", "/icons/sm.png"},
165        {"/mimetype", "image/png"},
166        {"/width", "120"},
167        {"/height", "120"},
168        {"/depth", "24"},
169        {"/url", "/icons/lrg.png"},
170        {"/mimetype", "image/jpeg"},
171        {"/width", "48"},
172        {"/height", "48"},
173        {"/depth", "24"},
174        {"/url", "/icons/sm.jpg"},
175        {"/mimetype", "image/jpeg"},
176        {"/width", "120"},
177        {"/height", "120"},
178        {"/depth", "24"},
179        {"/url", "/icons/lrg.jpg"},
180        {"service", INITHELPER((46+PNPX),5)},
181        {"service", INITHELPER((51+PNPX),5)},
182        {"service", INITHELPER((56+PNPX),5)},
183        {"/serviceType", "urn:schemas-upnp-org:service:ContentDirectory:1"},
184        {"/serviceId", "urn:upnp-org:serviceId:ContentDirectory"},
185        {"/controlURL", CONTENTDIRECTORY_CONTROLURL},
186        {"/eventSubURL", CONTENTDIRECTORY_EVENTURL},
187        {"/SCPDURL", CONTENTDIRECTORY_PATH},
188        {"/serviceType", "urn:schemas-upnp-org:service:ConnectionManager:1"},
189        {"/serviceId", "urn:upnp-org:serviceId:ConnectionManager"},
190        {"/controlURL", CONNECTIONMGR_CONTROLURL},
191        {"/eventSubURL", CONNECTIONMGR_EVENTURL},
192        {"/SCPDURL", CONNECTIONMGR_PATH},
193        {"/serviceType", "urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1"},
194        {"/serviceId", "urn:microsoft.com:serviceId:X_MS_MediaReceiverRegistrar"},
195        {"/controlURL", X_MS_MEDIARECEIVERREGISTRAR_CONTROLURL},
196        {"/eventSubURL", X_MS_MEDIARECEIVERREGISTRAR_EVENTURL},
197        {"/SCPDURL", X_MS_MEDIARECEIVERREGISTRAR_PATH},
198        {0, 0}
199};
200
201static const struct argument AddPortMappingArgs[] =
202{
203        {NULL, 1, 11},
204        {NULL, 1, 12},
205        {NULL, 1, 14},
206        {NULL, 1, 13},
207        {NULL, 1, 15},
208        {NULL, 1, 9},
209        {NULL, 1, 16},
210        {NULL, 1, 10},
211        {NULL, 0, 0}
212};
213
214static const struct argument DeletePortMappingArgs[] =
215{
216        {NULL, 1, 11},
217        {NULL, 1, 12},
218        {NULL, 1, 14},
219        {NULL, 0, 0}
220};
221
222static const struct argument SetConnectionTypeArgs[] =
223{
224        {NULL, 1, 0},
225        {NULL, 0, 0}
226};
227
228static const struct argument GetConnectionTypeInfoArgs[] =
229{
230        {NULL, 2, 0},
231        {NULL, 2, 1},
232        {NULL, 0, 0}
233};
234
235static const struct argument GetNATRSIPStatusArgs[] =
236{
237        {NULL, 2, 5},
238        {NULL, 2, 6},
239        {NULL, 0, 0}
240};
241
242static const struct argument GetGenericPortMappingEntryArgs[] =
243{
244        {NULL, 1, 8},
245        {NULL, 2, 11},
246        {NULL, 2, 12},
247        {NULL, 2, 14},
248        {NULL, 2, 13},
249        {NULL, 2, 15},
250        {NULL, 2, 9},
251        {NULL, 2, 16},
252        {NULL, 2, 10},
253        {NULL, 0, 0}
254};
255
256static const struct argument GetSpecificPortMappingEntryArgs[] =
257{
258        {NULL, 1, 11},
259        {NULL, 1, 12},
260        {NULL, 1, 14},
261        {NULL, 2, 13},
262        {NULL, 2, 15},
263        {NULL, 2, 9},
264        {NULL, 2, 16},
265        {NULL, 2, 10},
266        {NULL, 0, 0}
267};
268
269/* For ConnectionManager */
270static const struct argument GetProtocolInfoArgs[] =
271{
272        {"Source", 2, 0},
273        {"Sink", 2, 1},
274        {NULL, 0, 0}
275};
276
277static const struct argument PrepareForConnectionArgs[] =
278{
279        {"RemoteProtocolInfo", 1, 6},
280        {"PeerConnectionManager", 1, 4},
281        {"PeerConnectionID", 1, 7},
282        {"Direction", 1, 5},
283        {"ConnectionID", 2, 7},
284        {"AVTransportID", 2, 8},
285        {"RcsID", 2, 9},
286        {NULL, 0, 0}
287};
288
289static const struct argument ConnectionCompleteArgs[] =
290{
291        {"ConnectionID", 1, 7},
292        {NULL, 0, 0}
293};
294
295static const struct argument GetCurrentConnectionIDsArgs[] =
296{
297        {"ConnectionIDs", 2, 2},
298        {NULL, 0, 0}
299};
300
301static const struct argument GetCurrentConnectionInfoArgs[] =
302{
303        {"ConnectionID", 1, 7},
304        {"RcsID", 2, 9},
305        {"AVTransportID", 2, 8},
306        {"ProtocolInfo", 2, 6},
307        {"PeerConnectionManager", 2, 4},
308        {"PeerConnectionID", 2, 7},
309        {"Direction", 2, 5},
310        {"Status", 2, 3},
311        {NULL, 0, 0}
312};
313
314static const struct action ConnectionManagerActions[] =
315{
316        {"GetProtocolInfo", GetProtocolInfoArgs}, /* R */
317        //OPTIONAL {"PrepareForConnection", PrepareForConnectionArgs}, /* R */
318        //OPTIONAL {"ConnectionComplete", ConnectionCompleteArgs}, /* R */
319        {"GetCurrentConnectionIDs", GetCurrentConnectionIDsArgs}, /* R */
320        {"GetCurrentConnectionInfo", GetCurrentConnectionInfoArgs}, /* R */
321        {0, 0}
322};
323
324static const struct stateVar ConnectionManagerVars[] =
325{
326        {"SourceProtocolInfo", 1<<7, 0, 0, 44}, /* required */
327        {"SinkProtocolInfo", 1<<7, 0, 0, 48}, /* required */
328        {"CurrentConnectionIDs", 1<<7, 0, 0, 46}, /* required */
329        {"A_ARG_TYPE_ConnectionStatus", 0, 0, 27}, /* required */
330        {"A_ARG_TYPE_ConnectionManager", 0, 0}, /* required */
331        {"A_ARG_TYPE_Direction", 0, 0, 33}, /* required */
332        {"A_ARG_TYPE_ProtocolInfo", 0, 0}, /* required */
333        {"A_ARG_TYPE_ConnectionID", 4, 0}, /* required */
334        {"A_ARG_TYPE_AVTransportID", 4, 0}, /* required */
335        {"A_ARG_TYPE_RcsID", 4, 0}, /* required */
336        {0, 0}
337};
338
339static const struct argument GetSearchCapabilitiesArgs[] =
340{
341        {"SearchCaps", 2, 10},
342        {0, 0}
343};
344
345static const struct argument GetSortCapabilitiesArgs[] =
346{
347        {"SortCaps", 2, 11},
348        {0, 0}
349};
350
351static const struct argument GetSystemUpdateIDArgs[] =
352{
353        {"Id", 2, 12},
354        {0, 0}
355};
356
357static const struct argument BrowseArgs[] =
358{
359        {"ObjectID", 1, 1},
360        {"BrowseFlag", 1, 4},
361        {"Filter", 1, 5},
362        {"StartingIndex", 1, 7},
363        {"RequestedCount", 1, 8},
364        {"SortCriteria", 1, 6},
365        {"Result", 2, 2},
366        {"NumberReturned", 2, 8},
367        {"TotalMatches", 2, 8},
368        {"UpdateID", 2, 9},
369        {0, 0}
370};
371
372static const struct argument SearchArgs[] =
373{
374        {"ContainerID", 1, 1},
375        {"SearchCriteria", 1, 3},
376        {"Filter", 1, 5},
377        {"StartingIndex", 1, 7},
378        {"RequestedCount", 1, 8},
379        {"SortCriteria", 1, 6},
380        {"Result", 2, 2},
381        {"NumberReturned", 2, 8},
382        {"TotalMatches", 2, 8},
383        {"UpdateID", 2, 9},
384        {0, 0}
385};
386
387static const struct action ContentDirectoryActions[] =
388{
389        {"GetSearchCapabilities", GetSearchCapabilitiesArgs}, /* R */
390        {"GetSortCapabilities", GetSortCapabilitiesArgs}, /* R */
391        {"GetSystemUpdateID", GetSystemUpdateIDArgs}, /* R */
392        {"Browse", BrowseArgs}, /* R */
393        {"Search", SearchArgs}, /* O */
394#if 0 // Not implementing optional features yet...
395        {"CreateObject", CreateObjectArgs}, /* O */
396        {"DestroyObject", DestroyObjectArgs}, /* O */
397        {"UpdateObject", UpdateObjectArgs}, /* O */
398        {"ImportResource", ImportResourceArgs}, /* O */
399        {"ExportResource", ExportResourceArgs}, /* O */
400        {"StopTransferResource", StopTransferResourceArgs}, /* O */
401        {"GetTransferProgress", GetTransferProgressArgs}, /* O */
402        {"DeleteResource", DeleteResourceArgs}, /* O */
403        {"CreateReference", CreateReferenceArgs}, /* O */
404#endif
405        {0, 0}
406};
407
408static const struct stateVar ContentDirectoryVars[] =
409{
410        {"TransferIDs", 1<<7, 0, 0, 48}, /* 0 */
411        {"A_ARG_TYPE_ObjectID", 0, 0},
412        {"A_ARG_TYPE_Result", 0, 0},
413        {"A_ARG_TYPE_SearchCriteria", 0, 0},
414        {"A_ARG_TYPE_BrowseFlag", 0, 0, 36},
415        /* Allowed Values : BrowseMetadata / BrowseDirectChildren */
416        {"A_ARG_TYPE_Filter", 0, 0}, /* 5 */
417        {"A_ARG_TYPE_SortCriteria", 0, 0},
418        {"A_ARG_TYPE_Index", 3, 0},
419        {"A_ARG_TYPE_Count", 3, 0},
420        {"A_ARG_TYPE_UpdateID", 3, 0},
421        //JM{"A_ARG_TYPE_TransferID", 3, 0}, /* 10 */
422        //JM{"A_ARG_TYPE_TransferStatus", 0, 0, 39},
423        /* Allowed Values : COMPLETED / ERROR / IN_PROGRESS / STOPPED */
424        //JM{"A_ARG_TYPE_TransferLength", 0, 0},
425        //JM{"A_ARG_TYPE_TransferTotal", 0, 0},
426        //JM{"A_ARG_TYPE_TagValueList", 0, 0},
427        //JM{"A_ARG_TYPE_URI", 5, 0}, /* 15 */
428        {"SearchCapabilities", 0, 0},
429        {"SortCapabilities", 0, 0},
430        {"SystemUpdateID", 3|0x80, 0, 0, 255},
431        //{"ContainerUpdateIDs", 0, 0},
432        {0, 0}
433};
434
435static const struct argument GetIsAuthorizedArgs[] =
436{
437        {"DeviceID", 1, 0},
438        {"Result", 2, 3},
439        {NULL, 0, 0}
440};
441
442static const struct argument GetIsValidatedArgs[] =
443{
444        {"DeviceID", 1, 0},
445        {"Result", 2, 3},
446        {NULL, 0, 0}
447};
448
449static const struct argument GetRegisterDeviceArgs[] =
450{
451        {"RegistrationReqMsg", 1, 1},
452        {"RegistrationRespMsg", 2, 2},
453        {NULL, 0, 0}
454};
455
456static const struct action X_MS_MediaReceiverRegistrarActions[] =
457{
458        {"IsAuthorized", GetIsAuthorizedArgs}, /* R */
459        {"IsValidated", GetIsValidatedArgs}, /* R */
460#if 0 // Not needed?  WMP12 still works.  Need to check with 360 and WMP11.
461        {"RegisterDevice", GetRegisterDeviceArgs}, /* R */
462#endif
463        {0, 0}
464};
465
466static const struct stateVar X_MS_MediaReceiverRegistrarVars[] =
467{
468        {"A_ARG_TYPE_DeviceID", 0, 0},
469        {"A_ARG_TYPE_RegistrationReqMsg", 7, 0},
470        {"A_ARG_TYPE_RegistrationRespMsg", 7, 0},
471        {"A_ARG_TYPE_Result", 6, 0},
472        {"AuthorizationDeniedUpdateID", 3, 0},
473        {"AuthorizationGrantedUpdateID", 3, 0},
474        {"ValidationRevokedUpdateID", 3, 0},
475        {"ValidationSucceededUpdateID", 3, 0},
476        {0, 0}
477};
478
479/* WANCfg.xml */
480/* See UPnP_IGD_WANCommonInterfaceConfig 1.0.pdf */
481
482static const struct argument GetCommonLinkPropertiesArgs[] =
483{
484        {NULL, 2, 0},
485        {NULL, 2, 1},
486        {NULL, 2, 2},
487        {NULL, 2, 3},
488        {NULL, 0, 0}
489};
490
491static const struct argument GetTotalBytesSentArgs[] =
492{
493        {NULL, 2, 4},
494        {NULL, 0, 0}
495};
496
497static const struct argument GetTotalBytesReceivedArgs[] =
498{
499        {NULL, 2, 5},
500        {NULL, 0, 0}
501};
502
503static const struct argument GetTotalPacketsSentArgs[] =
504{
505        {NULL, 2, 6},
506        {NULL, 0, 0}
507};
508
509static const struct argument GetTotalPacketsReceivedArgs[] =
510{
511        {NULL, 2, 7},
512        {NULL, 0, 0}
513};
514
515static const struct serviceDesc scpdContentDirectory =
516{ ContentDirectoryActions, ContentDirectoryVars };
517
518static const struct serviceDesc scpdConnectionManager =
519{ ConnectionManagerActions, ConnectionManagerVars };
520
521static const struct serviceDesc scpdX_MS_MediaReceiverRegistrar =
522{ X_MS_MediaReceiverRegistrarActions, X_MS_MediaReceiverRegistrarVars };
523
524/* strcat_str()
525 * concatenate the string and use realloc to increase the
526 * memory buffer if needed. */
527static char *
528strcat_str(char * str, int * len, int * tmplen, const char * s2)
529{
530        char *p;
531        int s2len;
532        s2len = (int)strlen(s2);
533        if(*tmplen <= (*len + s2len))
534        {
535                if(s2len < 256)
536                        *tmplen += 256;
537                else
538                        *tmplen += s2len + 1;
539                p = realloc(str, *tmplen);
540                if (!p)
541                {
542                        if(s2len < 256)
543                                *tmplen -= 256;
544                        else
545                                *tmplen -= s2len + 1;
546                        return str;
547                }
548                else
549                        str = p;
550        }
551        /*strcpy(str + *len, s2); */
552        memcpy(str + *len, s2, s2len + 1);
553        *len += s2len;
554        return str;
555}
556
557/* strcat_char() :
558 * concatenate a character and use realloc to increase the
559 * size of the memory buffer if needed */
560static char *
561strcat_char(char * str, int * len, int * tmplen, char c)
562{
563        char *p;
564        if(*tmplen <= (*len + 1))
565        {
566                *tmplen += 256;
567                p = (char *)realloc(str, *tmplen);
568                if (!p)
569                {
570                        *tmplen -= 256;
571                        return str;
572                }
573                else
574                        str = p;
575        }
576        str[*len] = c;
577        (*len)++;
578        return str;
579}
580
581/* iterative subroutine using a small stack
582 * This way, the progam stack usage is kept low */
583static char *
584genXML(char * str, int * len, int * tmplen,
585                   const struct XMLElt * p)
586{
587        u_int16_t i, j, k;
588        int top;
589        const char * eltname, *s;
590        char c;
591        char element[64];
592        struct {
593                unsigned short i;
594                unsigned short j;
595                const char * eltname;
596        } pile[16]; /* stack */
597        top = -1;
598        i = 0;  /* current node */
599        j = 1;  /* i + number of nodes*/
600        for(;;)
601        {
602                eltname = p[i].eltname;
603                if(!eltname)
604                        return str;
605                if(eltname[0] == '/')
606                {
607                        #ifdef DESC_DEBUG
608                        printf("DBG: <%s>%s<%s>\n", eltname+1, p[i].data, eltname);
609                        #endif
610                        str = strcat_char(str, len, tmplen, '<');
611                        str = strcat_str(str, len, tmplen, eltname+1);
612                        str = strcat_char(str, len, tmplen, '>');
613                        str = strcat_str(str, len, tmplen, p[i].data);
614                        str = strcat_char(str, len, tmplen, '<');
615                        sscanf(eltname, "%s", element);
616                        str = strcat_str(str, len, tmplen, element);
617                        str = strcat_char(str, len, tmplen, '>');
618                        for(;;)
619                        {
620                                if(top < 0)
621                                        return str;
622                                i = ++(pile[top].i);
623                                j = pile[top].j;
624                                #ifdef DESC_DEBUG
625                                printf("DBG:  pile[%d]\t%d %d\n", top, i, j);
626                                #endif
627                                if(i==j)
628                                {
629                                        #ifdef DESC_DEBUG
630                                        printf("DBG: i==j, </%s>\n", pile[top].eltname);
631                                        #endif
632                                        str = strcat_char(str, len, tmplen, '<');
633                                        str = strcat_char(str, len, tmplen, '/');
634                                        s = pile[top].eltname;
635                                        for(c = *s; c > ' '; c = *(++s))
636                                                str = strcat_char(str, len, tmplen, c);
637                                        str = strcat_char(str, len, tmplen, '>');
638                                        top--;
639                                }
640                                else
641                                        break;
642                        }
643                }
644                else
645                {
646                        #ifdef DESC_DEBUG
647                        printf("DBG: [%d] <%s>\n", i, eltname);
648                        #endif
649                        str = strcat_char(str, len, tmplen, '<');
650                        str = strcat_str(str, len, tmplen, eltname);
651                        str = strcat_char(str, len, tmplen, '>');
652                        k = i;
653                        /*i = p[k].index; */
654                        /*j = i + p[k].nchild; */
655                        i = (unsigned long)p[k].data & 0xffff;
656                        j = i + ((unsigned long)p[k].data >> 16);
657                        top++;
658                        #ifdef DESC_DEBUG
659                        printf("DBG: +pile[%d]\t%d %d\n", top, i, j);
660                        #endif
661                        pile[top].i = i;
662                        pile[top].j = j;
663                        pile[top].eltname = eltname;
664                }
665        }
666}
667
668/* genRootDesc() :
669 * - Generate the root description of the UPnP device.
670 * - the len argument is used to return the length of
671 *   the returned string.
672 * - tmp_uuid argument is used to build the uuid string */
673char *
674genRootDesc(int * len)
675{
676        char * str;
677        int tmplen;
678        tmplen = 2048;
679        str = (char *)malloc(tmplen);
680        if(str == NULL)
681                return NULL;
682        * len = strlen(xmlver);
683        /*strcpy(str, xmlver); */
684        memcpy(str, xmlver, *len + 1);
685        str = genXML(str, len, &tmplen, rootDesc);
686        str[*len] = '\0';
687        return str;
688}
689
690/* genServiceDesc() :
691 * Generate service description with allowed methods and
692 * related variables. */
693static char *
694genServiceDesc(int * len, const struct serviceDesc * s)
695{
696        int i, j;
697        const struct action * acts;
698        const struct stateVar * vars;
699        const struct argument * args;
700        const char * p;
701        char * str;
702        int tmplen;
703        tmplen = 2048;
704        str = (char *)malloc(tmplen);
705        if(str == NULL)
706                return NULL;
707        /*strcpy(str, xmlver); */
708        *len = strlen(xmlver);
709        memcpy(str, xmlver, *len + 1);
710       
711        acts = s->actionList;
712        vars = s->serviceStateTable;
713
714        str = strcat_char(str, len, &tmplen, '<');
715        str = strcat_str(str, len, &tmplen, root_service);
716        str = strcat_char(str, len, &tmplen, '>');
717
718        str = strcat_str(str, len, &tmplen,
719                "<specVersion><major>1</major><minor>0</minor></specVersion>");
720
721        i = 0;
722        str = strcat_str(str, len, &tmplen, "<actionList>");
723        while(acts[i].name)
724        {
725                str = strcat_str(str, len, &tmplen, "<action><name>");
726                str = strcat_str(str, len, &tmplen, acts[i].name);
727                str = strcat_str(str, len, &tmplen, "</name>");
728                /* argument List */
729                args = acts[i].args;
730                if(args)
731                {
732                        str = strcat_str(str, len, &tmplen, "<argumentList>");
733                        j = 0;
734                        while(args[j].dir)
735                        {
736                                str = strcat_str(str, len, &tmplen, "<argument><name>");
737                                p = vars[args[j].relatedVar].name;
738                                str = strcat_str(str, len, &tmplen, (args[j].name ? args[j].name : p));
739                                str = strcat_str(str, len, &tmplen, "</name><direction>");
740                                str = strcat_str(str, len, &tmplen, args[j].dir==1?"in":"out");
741                                str = strcat_str(str, len, &tmplen,
742                                                "</direction><relatedStateVariable>");
743                                str = strcat_str(str, len, &tmplen, p);
744                                str = strcat_str(str, len, &tmplen,
745                                                "</relatedStateVariable></argument>");
746                                j++;
747                        }
748                        str = strcat_str(str, len, &tmplen,"</argumentList>");
749                }
750                str = strcat_str(str, len, &tmplen, "</action>");
751                /*str = strcat_char(str, len, &tmplen, '\n'); // TEMP ! */
752                i++;
753        }
754        str = strcat_str(str, len, &tmplen, "</actionList><serviceStateTable>");
755        i = 0;
756        while(vars[i].name)
757        {
758                str = strcat_str(str, len, &tmplen,
759                                "<stateVariable sendEvents=\"");
760                str = strcat_str(str, len, &tmplen, (vars[i].itype & 0x80)?"yes":"no");
761                str = strcat_str(str, len, &tmplen, "\"><name>");
762                str = strcat_str(str, len, &tmplen, vars[i].name);
763                str = strcat_str(str, len, &tmplen, "</name><dataType>");
764                str = strcat_str(str, len, &tmplen, upnptypes[vars[i].itype & 0x0f]);
765                str = strcat_str(str, len, &tmplen, "</dataType>");
766                if(vars[i].iallowedlist)
767                {
768                  str = strcat_str(str, len, &tmplen, "<allowedValueList>");
769                  for(j=vars[i].iallowedlist; upnpallowedvalues[j]; j++)
770                  {
771                    str = strcat_str(str, len, &tmplen, "<allowedValue>");
772                    str = strcat_str(str, len, &tmplen, upnpallowedvalues[j]);
773                    str = strcat_str(str, len, &tmplen, "</allowedValue>");
774                  }
775                  str = strcat_str(str, len, &tmplen, "</allowedValueList>");
776                }
777                /*if(vars[i].defaultValue) */
778                if(vars[i].idefault)
779                {
780                  str = strcat_str(str, len, &tmplen, "<defaultValue>");
781                  /*str = strcat_str(str, len, &tmplen, vars[i].defaultValue); */
782                  str = strcat_str(str, len, &tmplen, upnpdefaultvalues[vars[i].idefault]);
783                  str = strcat_str(str, len, &tmplen, "</defaultValue>");
784                }
785                str = strcat_str(str, len, &tmplen, "</stateVariable>");
786                /*str = strcat_char(str, len, &tmplen, '\n'); // TEMP ! */
787                i++;
788        }
789        str = strcat_str(str, len, &tmplen, "</serviceStateTable></scpd>");
790        str[*len] = '\0';
791        return str;
792}
793
794/* genContentDirectory() :
795 * Generate the ContentDirectory xml description */
796char *
797genContentDirectory(int * len)
798{
799        return genServiceDesc(len, &scpdContentDirectory);
800}
801
802/* genConnectionManager() :
803 * Generate the ConnectionManager xml description */
804char *
805genConnectionManager(int * len)
806{
807        return genServiceDesc(len, &scpdConnectionManager);
808}
809
810/* genX_MS_MediaReceiverRegistrar() :
811 * Generate the X_MS_MediaReceiverRegistrar xml description */
812char *
813genX_MS_MediaReceiverRegistrar(int * len)
814{
815        return genServiceDesc(len, &scpdX_MS_MediaReceiverRegistrar);
816}
817
818static char *
819genEventVars(int * len, const struct serviceDesc * s, const char * servns)
820{
821        const struct stateVar * v;
822        char * str;
823        int tmplen;
824        char buf[512];
825        tmplen = 512;
826        str = (char *)malloc(tmplen);
827        if(str == NULL)
828                return NULL;
829        *len = 0;
830        v = s->serviceStateTable;
831        snprintf(buf, sizeof(buf), "<e:propertyset xmlns:e=\"urn:schemas-upnp-org:event-1-0\" xmlns:s=\"%s\">", servns);
832        str = strcat_str(str, len, &tmplen, buf);
833        while(v->name) {
834                if(v->itype & 0x80) {
835                        snprintf(buf, sizeof(buf), "<e:property><%s>", v->name);
836                        str = strcat_str(str, len, &tmplen, buf);
837                        //printf("<e:property><s:%s>", v->name);
838                        switch(v->ieventvalue) {
839                        case 0:
840                                break;
841                        case 255:       /* Magical values should go around here */
842                                if( strcmp(v->name, "SystemUpdateID") == 0 )
843                                {
844                                        snprintf(buf, sizeof(buf), "%d", updateID);
845                                        str = strcat_str(str, len, &tmplen, buf);
846                                }
847                                break;
848                        default:
849                                str = strcat_str(str, len, &tmplen, upnpallowedvalues[v->ieventvalue]);
850                                //printf("%s", upnpallowedvalues[v->ieventvalue]);
851                        }
852                        snprintf(buf, sizeof(buf), "</%s></e:property>", v->name);
853                        str = strcat_str(str, len, &tmplen, buf);
854                        //printf("</s:%s></e:property>\n", v->name);
855                }
856                v++;
857        }
858        str = strcat_str(str, len, &tmplen, "</e:propertyset>");
859        //printf("</e:propertyset>\n");
860        //printf("\n");
861        //printf("%d\n", tmplen);
862        str[*len] = '\0';
863        return str;
864}
865
866char *
867getVarsContentDirectory(int * l)
868{
869        return genEventVars(l,
870                        &scpdContentDirectory,
871                            "urn:schemas-upnp-org:service:ContentDirectory:1");
872}
873
874char *
875getVarsConnectionManager(int * l)
876{
877        return genEventVars(l,
878                        &scpdConnectionManager,
879                            "urn:schemas-upnp-org:service:ConnectionManager:1");
880}
881
882char *
883getVarsX_MS_MediaReceiverRegistrar(int * l)
884{
885        return genEventVars(l,
886                        &scpdX_MS_MediaReceiverRegistrar,
887                            "urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1");
888}
889
Note: See TracBrowser for help on using the repository browser.