1/* $Id: portlistingparse.c,v 1.7 2014/11/01 10:37:32 nanard Exp $ */
2/* MiniUPnP project
3 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
4 * (c) 2011 Thomas Bernard
5 * This software is subject to the conditions detailed
6 * in the LICENCE file provided within the distribution */
7#include <string.h>
8#include <stdlib.h>
9#include "portlistingparse.h"
10#include "minixml.h"
11
12/* list of the elements */
13static const struct {
14	const portMappingElt code;
15	const char * const str;
16} elements[] = {
17	{ PortMappingEntry, "PortMappingEntry"},
18	{ NewRemoteHost, "NewRemoteHost"},
19	{ NewExternalPort, "NewExternalPort"},
20	{ NewProtocol, "NewProtocol"},
21	{ NewInternalPort, "NewInternalPort"},
22	{ NewInternalClient, "NewInternalClient"},
23	{ NewEnabled, "NewEnabled"},
24	{ NewDescription, "NewDescription"},
25	{ NewLeaseTime, "NewLeaseTime"},
26	{ PortMappingEltNone, NULL}
27};
28
29/* Helper function */
30static UNSIGNED_INTEGER
31atoui(const char * p, int l)
32{
33	UNSIGNED_INTEGER r = 0;
34	while(l > 0 && *p)
35	{
36		if(*p >= '0' && *p <= '9')
37			r = r*10 + (*p - '0');
38		else
39			break;
40		p++;
41		l--;
42	}
43	return r;
44}
45
46/* Start element handler */
47static void
48startelt(void * d, const char * name, int l)
49{
50	int i;
51	struct PortMappingParserData * pdata = (struct PortMappingParserData *)d;
52	pdata->curelt = PortMappingEltNone;
53	for(i = 0; elements[i].str; i++)
54	{
55		if(memcmp(name, elements[i].str, l) == 0)
56		{
57			pdata->curelt = elements[i].code;
58			break;
59		}
60	}
61	if(pdata->curelt == PortMappingEntry)
62	{
63		struct PortMapping * pm;
64		pm = calloc(1, sizeof(struct PortMapping));
65		pm->l_next = pdata->l_head;	/* insert in list */
66		pdata->l_head = pm;
67	}
68}
69
70/* End element handler */
71static void
72endelt(void * d, const char * name, int l)
73{
74	struct PortMappingParserData * pdata = (struct PortMappingParserData *)d;
75	(void)name;
76	(void)l;
77	pdata->curelt = PortMappingEltNone;
78}
79
80/* Data handler */
81static void
82data(void * d, const char * data, int l)
83{
84	struct PortMapping * pm;
85	struct PortMappingParserData * pdata = (struct PortMappingParserData *)d;
86	pm = pdata->l_head;
87	if(!pm)
88		return;
89	if(l > 63)
90		l = 63;
91	switch(pdata->curelt)
92	{
93	case NewRemoteHost:
94		memcpy(pm->remoteHost, data, l);
95		pm->remoteHost[l] = '\0';
96		break;
97	case NewExternalPort:
98		pm->externalPort = (unsigned short)atoui(data, l);
99		break;
100	case NewProtocol:
101		if(l > 3)
102			l = 3;
103		memcpy(pm->protocol, data, l);
104		pm->protocol[l] = '\0';
105		break;
106	case NewInternalPort:
107		pm->internalPort = (unsigned short)atoui(data, l);
108		break;
109	case NewInternalClient:
110		memcpy(pm->internalClient, data, l);
111		pm->internalClient[l] = '\0';
112		break;
113	case NewEnabled:
114		pm->enabled = (unsigned char)atoui(data, l);
115		break;
116	case NewDescription:
117		memcpy(pm->description, data, l);
118		pm->description[l] = '\0';
119		break;
120	case NewLeaseTime:
121		pm->leaseTime = atoui(data, l);
122		break;
123	default:
124		break;
125	}
126}
127
128
129/* Parse the PortMappingList XML document for IGD version 2
130 */
131void
132ParsePortListing(const char * buffer, int bufsize,
133                 struct PortMappingParserData * pdata)
134{
135	struct xmlparser parser;
136
137	memset(pdata, 0, sizeof(struct PortMappingParserData));
138	/* init xmlparser */
139	parser.xmlstart = buffer;
140	parser.xmlsize = bufsize;
141	parser.data = pdata;
142	parser.starteltfunc = startelt;
143	parser.endeltfunc = endelt;
144	parser.datafunc = data;
145	parser.attfunc = 0;
146	parsexml(&parser);
147}
148
149void
150FreePortListing(struct PortMappingParserData * pdata)
151{
152	struct PortMapping * pm;
153	while((pm = pdata->l_head) != NULL)
154	{
155		/* remove from list */
156		pdata->l_head = pm->l_next;
157		free(pm);
158	}
159}
160
161