1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2014 Kannel Group
5  * Copyright (c) 1998-2001 WapIT Ltd.
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
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in
17  *    the documentation and/or other materials provided with the
18  *    distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  *    if any, must include the following acknowledgment:
22  *       "This product includes software developed by the
23  *        Kannel Group (http://www.kannel.org/)."
24  *    Alternately, this acknowledgment may appear in the software itself,
25  *    if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Kannel" and "Kannel Group" must not be used to
28  *    endorse or promote products derived from this software without
29  *    prior written permission. For written permission, please
30  *    contact org@kannel.org.
31  *
32  * 5. Products derived from this software may not be called "Kannel",
33  *    nor may "Kannel" appear in their name, without prior written
34  *    permission of the Kannel Group.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED.  IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
40  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
41  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
42  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
46  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Kannel Group.  For more information on
51  * the Kannel Group, please see <http://www.kannel.org/>.
52  *
53  * Portions of this software are based upon software originally written at
54  * WapIT Ltd., Helsinki, Finland for the Kannel project.
55  */
56 
57 /*
58  * ota_compiler.c: Tokenizes OTA provisioning documents
59  *
60  * This compiler handles the following OTA config formats:
61  *
62  *   - Nokia/Ericsson OTA settings specificaion. DTD is defined in
63  *     Over The Air Settings Specification (hereafter called OTA), chapter 6.
64  *     (See http://www.americas.nokia.com/messaging/default.asp)
65  *
66  *   - OMA OTA client provisionig content specification, as defined in
67  *     document OMA-WAP-ProvCont-V1.1-20050428-C.pdf. (hereafter called OMA)
68  *     (See http://www.openmobilealliance.com/release_program/cp_v1_1.htm)
69  *
70  * Histrorically the Nokia/Ericsson OTA config format was the first scratch
71  * in allowing remote WAP profile configuration via SMS bearer. While the WAP
72  * Forum transfered into the Open Mobile Alliance (OMA), the technical working
73  * groups addopted the provisioning concept to a more generic OTA provisioning
74  * concept. The OMA client provisioning specs v1.1 are part of the WAP 2.0
75  * protocol stack.
76  *
77  * Aarno Syv�nen for Wiral Ltd
78  * Stipe Tolj <stolj@kannel.org> for Wapme Systems AG
79  * Paul Bagyenda for digital solutions Ltd.
80  */
81 
82 #include <ctype.h>
83 #include <libxml/xmlmemory.h>
84 #include <libxml/tree.h>
85 #include <libxml/debugXML.h>
86 #include <libxml/encoding.h>
87 
88 #include "shared.h"
89 #include "xml_shared.h"
90 #include "ota_compiler.h"
91 
92 /****************************************************************************
93  *
94  * Global variables
95  *
96  * Two token table types, one and two token fields
97  */
98 
99 struct ota_2table_t {
100     char *name;
101     unsigned char token;
102 };
103 
104 typedef struct ota_2table_t ota_2table_t;
105 
106 /*
107  * Ota tokenizes whole of attribute value, or uses an inline string. See ota,
108  * chapter 8.2.
109  */
110 struct ota_3table_t {
111     char *name;
112     char *value;
113     unsigned char token;
114     unsigned char code_page;
115 };
116 
117 typedef struct ota_3table_t ota_3table_t;
118 
119 /*
120  * Elements from tag code page zero. These are defined in OTA, chapter 8.1
121  * and OMA, chapter 7.1.
122  */
123 
124 static ota_2table_t ota_elements[] = {
125     { "SYNCSETTINGS", 0x15 },
126     { "WAP-PROVISIONINGDOC", 0x05 },
127     { "CHARACTERISTIC-LIST", 0x05 },
128     { "CHARACTERISTIC", 0x06 },
129     { "PARM", 0x07 }
130 };
131 
132 #define NUMBER_OF_ELEMENTS sizeof(ota_elements)/sizeof(ota_elements[0])
133 
134 /*
135  * SYNCSETTINGS tags are defined in OTA specs 7.0, chapter 11.1
136  */
137 
138 static ota_2table_t ota_syncsettings_elements[] = {
139     { "Addr", 0x45 },
140     { "AddrType", 0x46 },
141     { "Auth", 0x47 },
142     { "AuthLevel", 0x48 },
143     { "AuthScheme", 0x49 },
144     { "Bearer", 0x4A },
145     { "ConRef", 0x4B },
146     { "ConType", 0x4C },
147     { "Cred", 0x4D },
148     { "CTType", 0x4E },
149     { "CTVer", 0x4F },
150     { "HostAddr", 0x50 },
151     { "Name", 0x51 },
152     { "Port", 0x52 },
153     { "RefID", 0x53 },
154     { "RemoteDB", 0x54 },
155     { "URI", 0x56 },
156     { "Username", 0x57 },
157     { "Version", 0x58 }
158 };
159 
160 #define NUMBER_OF_SYNCSETTINGS_ELEMENTS sizeof(ota_syncsettings_elements)/sizeof(ota_syncsettings_elements[0])
161 
162 /*
163  * Attribute names and values from code page zero. These are defined in ota,
164  * chapter 8.2. Some values are presented as inline strings; in this case
165  * value "INLINE" is used. (Note a quirk: there is an attribute with name
166  * "VALUE".)
167  *
168  * For a documentation of the single attributes see gw/ota_prov_attr.h.
169  */
170 
171 static ota_3table_t ota_attributes[] = {
172     { "TYPE", "ADDRESS", 0x06 },
173     { "TYPE", "URL", 0x07 },
174     { "TYPE", "MMSURL", 0x7c },
175     { "TYPE", "NAME", 0x08 },
176     { "TYPE", "ID", 0x7d },
177     { "TYPE", "BOOKMARK", 0x7f },
178     { "NAME", "BEARER", 0x12 },
179     { "NAME", "PROXY", 0x13 },
180     { "NAME", "PORT", 0x14 },
181     { "NAME", "NAME", 0x15 },
182     { "NAME", "PROXY_TYPE", 0x16 },
183     { "NAME", "URL", 0x17 },
184     { "NAME", "PROXY_AUTHNAME", 0x18 },
185     { "NAME", "PROXY_AUTHSECRET", 0x19 },
186     { "NAME", "SMS_SMSC_ADDRESS", 0x1a },
187     { "NAME", "USSD_SERVICE_CODE", 0x1b },
188     { "NAME", "GPRS_ACCESSPOINTNAME", 0x1c },
189     { "NAME", "PPP_LOGINTYPE", 0x1d },
190     { "NAME", "PROXY_LOGINTYPE", 0x1e },
191     { "NAME", "CSD_DIALSTRING", 0x21 },
192     { "NAME", "CSD_CALLTYPE", 0x28 },
193     { "NAME", "CSD_CALLSPEED", 0x29 },
194     { "NAME", "PPP_AUTHTYPE", 0x22 },
195     { "NAME", "PPP_AUTHNAME", 0x23 },
196     { "NAME", "PPP_AUTHSECRET", 0x24 },
197     { "NAME", "ISP_NAME", 0x7e },
198     { "NAME", "INLINE", 0x10 },
199     { "VALUE", "GSM/CSD", 0x45 },
200     { "VALUE", "GSM/SMS", 0x46 },
201     { "VALUE", "GSM/USSD", 0x47 },
202     { "VALUE", "IS-136/CSD", 0x48 },
203     { "VALUE", "GPRS", 0x49 },
204     { "VALUE", "9200", 0x60 },
205     { "VALUE", "9201", 0x61 },
206     { "VALUE", "9202", 0x62 },
207     { "VALUE", "9203", 0x63 },
208     { "VALUE", "AUTOMATIC", 0x64 },
209     { "VALUE", "MANUAL", 0x65 },
210     { "VALUE", "AUTO", 0x6a },
211     { "VALUE", "9600", 0x6b },
212     { "VALUE", "14400", 0x6c },
213     { "VALUE", "19200", 0x6d },
214     { "VALUE", "28800", 0x6e },
215     { "VALUE", "38400", 0x6f },
216     { "VALUE", "PAP", 0x70 },
217     { "VALUE", "CHAP", 0x71 },
218     { "VALUE", "ANALOGUE", 0x72 },
219     { "VALUE", "ISDN", 0x73 },
220     { "VALUE", "43200", 0x74 },
221     { "VALUE", "57600", 0x75 },
222     { "VALUE", "MSISDN_NO", 0x76 },
223     { "VALUE", "IPV4", 0x77 },
224     { "VALUE", "MS_CHAP", 0x78 },
225     { "VALUE", "INLINE", 0x11 }
226 };
227 
228 #define NUMBER_OF_ATTRIBUTES sizeof(ota_attributes)/sizeof(ota_attributes[0])
229 
230 /*
231  * Defines OMA ProvCont WBXML tokens, see chapter 7.
232  * Value 'INLINE' has to be always last in attribute group, since this
233  * is a break condition within a while loop.
234  */
235 
236 static ota_3table_t oma_ota_attributes[] = {
237     { "VERSION", "1.0", 0x46 },
238     { "VERSION", "INLINE", 0x45 },
239     { "TYPE", "PXLOGICAL", 0x51 },
240     { "TYPE", "PXPHYSICAL", 0x52 },
241     { "TYPE", "PORT", 0x53 },
242     { "TYPE", "VALIDITY", 0x54 },
243     { "TYPE", "NAPDEF", 0x55 },
244     { "TYPE", "BOOTSTRAP", 0x56 },
245     { "TYPE", "VENDORCONFIG", 0x57 },
246     { "TYPE", "PXAUTHINFO", 0x59 },
247     { "TYPE", "NAPAUTHINFO", 0x5A },
248     { "TYPE", "ACCESS", 0x5B },
249     { "TYPE", "BEARERINFO", 0x5C },
250     { "TYPE", "DNS-ADDRINFO", 0x5D },
251     { "TYPE", "CLIENTIDENTITY", 0x58 },
252     { "TYPE", "APPLICATION", 0x55, 1 },
253     { "TYPE", "APPADDR", 0x56, 1 },
254     { "TYPE", "APPAUTH", 0x57, 1 },
255     { "TYPE", "RESOURCE", 0x59, 1 },
256     { "TYPE", "WLAN", 0x5A, 1 },
257     { "TYPE", "SEC-SSID", 0x5B, 1 },
258     { "TYPE", "EAP", 0x5C, 1 },
259     { "TYPE", "CERT", 0x5D, 1 },
260     { "TYPE", "WEPKEY", 0x5E, 1 },
261     { "TYPE", "INLINE", 0x50 },
262     { "NAME", "NAME", 0x7 },
263     { "NAME", "NAP-ADDRESS", 0x8 },
264     { "NAME", "NAP-ADDRTYPE", 0x9 },
265     { "NAME", "CALLTYPE", 0xA },
266     { "NAME", "VALIDUNTIL", 0xB },
267     { "NAME", "AUTHTYPE", 0xC },
268     { "NAME", "AUTHNAME", 0xD },
269     { "NAME", "AUTHSECRET", 0xE },
270     { "NAME", "LINGER", 0xF },
271     { "NAME", "BEARER", 0x10 },
272     { "NAME", "NAPID", 0x11 },
273     { "NAME", "COUNTRY", 0x12 },
274     { "NAME", "NETWORK", 0x13 },
275     { "NAME", "INTERNET", 0x14 },
276     { "NAME", "PROXY-ID", 0x15 },
277     { "NAME", "PROXY-PROVIDER-ID", 0x16 },
278     { "NAME", "DOMAIN", 0x17 },
279     { "NAME", "PROVURL", 0x18 },
280     { "NAME", "PXAUTH-TYPE", 0x19 },
281     { "NAME", "PXAUTH-ID", 0x1A },
282     { "NAME", "PXAUTH-PW", 0x1B },
283     { "NAME", "STARTPAGE", 0x1C },
284     { "NAME", "BASAUTH-ID", 0x1D },
285     { "NAME", "BASAUTH-PW", 0x1E },
286     { "NAME", "PUSHENABLED", 0x1F },
287     { "NAME", "PXADDR", 0x20 },
288     { "NAME", "PXADDRTYPE", 0x21 },
289     { "NAME", "TO-NAPID", 0x22 },
290     { "NAME", "PORTNBR", 0x23 },
291     { "NAME", "SERVICE", 0x24 },
292     { "NAME", "LINKSPEED", 0x25 },
293     { "NAME", "DNLINKSPEED", 0x26 },
294     { "NAME", "LOCAL-ADDR", 0x27 },
295     { "NAME", "LOCAL-ADDRTYPE", 0x28 },
296     { "NAME", "CONTEXT-ALLOW", 0x29 },
297     { "NAME", "TRUST", 0x2A },
298     { "NAME", "MASTER", 0x2B },
299     { "NAME", "SID", 0x2C },
300     { "NAME", "SOC", 0x2D },
301     { "NAME", "WSP-VERSION", 0x2E },
302     { "NAME", "PHYSICAL-PROXY-ID", 0x2F },
303     { "NAME", "CLIENT-ID", 0x30 },
304     { "NAME", "DELIVERY-ERR-SDU", 0x31 },
305     { "NAME", "DELIVERY-ORDER", 0x32 },
306     { "NAME", "TRAFFIC-CLASS", 0x33 },
307     { "NAME", "MAX-SDU-SIZE", 0x34 },
308     { "NAME", "MAX-BITRATE-UPLINK", 0x35 },
309     { "NAME", "MAX-BITRATE-DNLINK", 0x36 },
310     { "NAME", "RESIDUAL-BER", 0x37 },
311     { "NAME", "SDU-ERROR-RATIO", 0x38 },
312     { "NAME", "TRAFFIC-HANDL-PRIO", 0x39 },
313     { "NAME", "TRANSFER-DELAY", 0x3A },
314     { "NAME", "GUARANTEED-BITRATE-UPLINK", 0x3B },
315     { "NAME", "GUARANTEED-BITRATE-DNLINK", 0x3C },
316     { "NAME", "PXADDR-FQDN", 0x3D },
317     { "NAME", "PROXY-PW", 0x3E },
318     { "NAME", "PPGAUTH-TYPE", 0x3F },
319     { "NAME", "PULLENABLED", 0x47 },
320     { "NAME", "DNS-ADDR", 0x48 },
321     { "NAME", "MAX-NUM-RETRY", 0x49 },
322     { "NAME", "FIRST-RETRY-TIMEOUT", 0x4A },
323     { "NAME", "REREG-THRESHOLD", 0x4B },
324     { "NAME", "T-BIT", 0x4C },
325     { "NAME", "AUTH-ENTITY", 0x4E },
326     { "NAME", "SPI", 0x4F },
327     { "NAME", "AACCEPT", 0x2E, 1 },
328     { "NAME", "AAUTHDATA", 0x2F, 1 },
329     { "NAME", "AAUTHLEVEL", 0x30, 1 },
330     { "NAME", "AAUTHNAME", 0x31, 1 },
331     { "NAME", "AAUTHSECRET", 0x32, 1 },
332     { "NAME", "AAUTHTYPE", 0x33, 1 },
333     { "NAME", "ADDR", 0x34, 1 },
334     { "NAME", "ADDRTYPE", 0x35, 1 },
335     { "NAME", "APPID", 0x36, 1 },
336     { "NAME", "APROTOCOL", 0x37, 1 },
337     { "NAME", "PROVIDER-ID", 0x38, 1 },
338     { "NAME", "TO-PROXY", 0x39, 1 },
339     { "NAME", "URI", 0x3A, 1 },
340     { "NAME", "RULE", 0x3B, 1 },
341     { "NAME", "APPREF", 0x3C, 1 },
342     { "NAME", "TO-APPREF", 0x3D, 1 },
343     { "NAME", "PRI-SSID", 0x3E, 1 },
344     { "NAME", "PRI-U-SSID", 0x3F, 1 },
345     { "NAME", "PRI-H-SSID", 0x40, 1 },
346     { "NAME", "S-SSID", 0x41, 1 },
347     { "NAME", "S-U-SSID", 0x42, 1 },
348     { "NAME", "NETMODE", 0x43, 1 },
349     { "NAME", "SECMODE", 0x44, 1 },
350     { "NAME", "EAPTYPE", 0x45, 1 },
351     { "NAME", "USERNAME", 0x46, 1 },
352     { "NAME", "PASSWORD", 0x47, 1 },
353     { "NAME", "REALM", 0x48, 1 },
354     { "NAME", "USE-PSEUD", 0x49, 1 },
355     { "NAME", "ENCAPS", 0x5B, 1 },
356     { "NAME", "VER-SER-REALM", 0x4C, 1 },
357     { "NAME", "CLIENT-AUTH", 0x4D, 1 },
358     { "NAME", "SES-VAL-TIME", 0x4E, 1 },
359     { "NAME", "CIP-SUIT", 0x4F, 1 },
360     { "NAME", "PEAP-V0", 0x60, 1 },
361     { "NAME", "PEAP-V1", 0x61, 1 },
362     { "NAME", "PEAP-V2", 0x62, 1 },
363     { "NAME", "ISS-NAME", 0x63, 1 },
364     { "NAME", "SUB-NAME", 0x64, 1 },
365     { "NAME", "CERT-TYPE", 0x65, 1 },
366     { "NAME", "SER-NUM", 0x66, 1 },
367     { "NAME", "SUB-KEY-ID", 0x67, 1 },
368     { "NAME", "THUMBPRINT", 0x68, 1 },
369     { "NAME", "WPA-PRES-KEY-ASC", 0x69, 1 },
370     { "NAME", "WPA-PRES-KEY-HEX", 0x6A, 1 },
371     { "NAME", "WEPKEYIND", 0x6B, 1 },
372     { "NAME", "WEPAUTHMODE", 0x6C, 1 },
373     { "NAME", "LENGTH", 0x6D, 1 },
374     { "NAME", "INDEX", 0x6E, 1 },
375     { "NAME", "DATA", 0x6F, 1 },
376     { "NAME", "WLANHAND", 0x70, 1 },
377     { "NAME", "EDIT-SET", 0x71, 1 },
378     { "NAME", "VIEW-SET", 0x72, 1 },
379     { "NAME", "FORW-SET", 0x73, 1 },
380     { "NAME", "INLINE", 0x5 },
381     { "VALUE", "IPV4", 0x85 },
382     { "VALUE", "IPV6", 0x86 },
383     { "VALUE", "E164", 0x87 },
384     { "VALUE", "ALPHA", 0x88 },
385     { "VALUE", "APN", 0x89 },
386     { "VALUE", "SCODE", 0x8A },
387     { "VALUE", "TETRA-ITSI", 0x8B },
388     { "VALUE", "MAN", 0x8C },
389     { "VALUE", "APPSRV", 0x8D, 1 },
390     { "VALUE", "OBEX", 0x8E, 1 },
391     { "VALUE", "ANALOG-MODEM", 0x90 },
392     { "VALUE", "V.120", 0x91 },
393     { "VALUE", "V.110", 0x92 },
394     { "VALUE", "X.31", 0x93 },
395     { "VALUE", "BIT-TRANSPARENT", 0x94 },
396     { "VALUE", "DIRECT-ASYNCHRONOUS-DATA-SERVICE", 0x95 },
397     { "VALUE", "PAP", 0x9A },
398     { "VALUE", "CHAP", 0x9B },
399     { "VALUE", "HTTP-BASIC", 0x9C },
400     { "VALUE", "HTTP-DIGEST", 0x9D },
401     { "VALUE", "WTLS-SS", 0x9E },
402     { "VALUE", "MD5", 0x9F },
403     { "VALUE", "GSM-USSD", 0xA2 },
404     { "VALUE", "GSM-SMS", 0xA3 },
405     { "VALUE", "ANSI-136-GUTS", 0xA4 },
406     { "VALUE", "IS-95-CDMA-SMS", 0xA5 },
407     { "VALUE", "IS-95-CDMA-CSD", 0xA6 },
408     { "VALUE", "IS-95-CDMA-PACKET", 0xA7 },
409     { "VALUE", "ANSI-136-CSD", 0xA8 },
410     { "VALUE", "ANSI-136-GPRS", 0xA9 },
411     { "VALUE", "GSM-CSD", 0xAA },
412     { "VALUE", "GSM-GPRS", 0xAB },
413     { "VALUE", "AMPS-CDPD", 0xAC },
414     { "VALUE", "PDC-CSD", 0xAD },
415     { "VALUE", "PDC-PACKET", 0xAE },
416     { "VALUE", "IDEN-SMS", 0xAF },
417     { "VALUE", "IDEN-CSD", 0xB0 },
418     { "VALUE", "IDEN-PACKET", 0xB1 },
419     { "VALUE", "FLEX/REFLEX", 0xB2 },
420     { "VALUE", "PHS-SMS", 0xB3 },
421     { "VALUE", "PHS-CSD", 0xB4 },
422     { "VALUE", "TETRA-SDS", 0xB5 },
423     { "VALUE", "TETRA-PACKET", 0xB6 },
424     { "VALUE", "ANSI-136-GHOST", 0xB7 },
425     { "VALUE", "MOBITEX-MPAK", 0xB8 },
426     { "VALUE", "CDMA2000-1X-SIMPLE-IP", 0xB9 },
427     { "VALUE", "CDMA2000-1X-MOBILE-IP", 0xBA },
428     { "VALUE", "3G-GSM", 0xBB },
429     { "VALUE", "WLAN", 0xBC },
430     { "VALUE", "AUTOBAUDING", 0xC5 },
431     { "VALUE", "CL-WSP", 0xCA },
432     { "VALUE", "CO-WSP", 0xCB },
433     { "VALUE", "CL-SEC-WSP", 0xCC },
434     { "VALUE", "CO-SEC-WSP", 0xCD },
435     { "VALUE", "CL-SEC-WTA", 0xCE },
436     { "VALUE", "CO-SEC-WTA", 0xCF },
437     { "VALUE", "OTA-HTTP-TO", 0xD0 },
438     { "VALUE", "OTA-HTTP-TLS-TO", 0xD1 },
439     { "VALUE", "OTA-HTTP-PO", 0xD2 },
440     { "VALUE", "OTA-HTTP-TLS-PO", 0xD3 },
441     { "VALUE", ",", 0x90, 1 },
442     { "VALUE", "HTTP-", 0x91, 1 },
443     { "VALUE", "BASIC", 0x92, 1 },
444     { "VALUE", "DIGEST", 0x93, 1 },
445     { "VALUE", "AAA", 0xE0 },
446     { "VALUE", "HA", 0xE1 },
447     { "VALUE", "INLINE", 0x6 },
448 };
449 
450 #define OMA_VALUE_TAG 0x06
451 
452 #define NUMBER_OF_OMA_ATTRIBUTES sizeof(oma_ota_attributes)/sizeof(oma_ota_attributes[0])
453 
454 #include "xml_definitions.h"
455 
456 /****************************************************************************
457  *
458  * Prototypes of internal functions. Note that 'Ptr' means here '*'.
459  */
460 
461 static int parse_document(xmlDocPtr document, Octstr *charset,
462                           simple_binary_t **ota_binary);
463 static int parse_node(xmlNodePtr node, simple_binary_t **otabxml);
464 static int parse_element(xmlNodePtr node, simple_binary_t **otabxml);
465 static int parse_attribute(xmlAttrPtr attr, simple_binary_t **otabxml);
466 
467 /***************************************************************************
468  *
469  * Implementation of the external function
470  */
471 
ota_compile(Octstr * ota_doc,Octstr * charset,Octstr ** ota_binary)472 int ota_compile(Octstr *ota_doc, Octstr *charset, Octstr **ota_binary)
473 {
474     simple_binary_t *otabxml;
475     int ret;
476     xmlDocPtr pDoc;
477     size_t size;
478     char *ota_c_text;
479 
480     *ota_binary = octstr_create("");
481     otabxml = simple_binary_create();
482 
483     octstr_strip_blanks(ota_doc);
484     octstr_shrink_blanks(ota_doc);
485     set_charset(ota_doc, charset);
486     size = octstr_len(ota_doc);
487     ota_c_text = octstr_get_cstr(ota_doc);
488     pDoc = xmlParseMemory(ota_c_text, size);
489 
490     ret = 0;
491     if (pDoc) {
492         ret = parse_document(pDoc, charset, &otabxml);
493         simple_binary_output(*ota_binary, otabxml);
494         xmlFreeDoc(pDoc);
495     } else {
496         xmlFreeDoc(pDoc);
497         octstr_destroy(*ota_binary);
498         simple_binary_destroy(otabxml);
499         error(0, "OTA: No document to parse. Probably an error in OTA source");
500         return -1;
501     }
502 
503     simple_binary_destroy(otabxml);
504 
505     return ret;
506 }
507 
508 /*****************************************************************************
509  *
510  * Implementation of internal functions
511  *
512  * Parse document node. Store wbmxl version number and character set into the
513  * start of the document. There are no wapforum public identifier for ota.
514  * FIXME: Add parse_prologue!
515  */
516 
parse_document(xmlDocPtr document,Octstr * charset,simple_binary_t ** otabxml)517 static int parse_document(xmlDocPtr document, Octstr *charset,
518                           simple_binary_t **otabxml)
519 {
520     xmlNodePtr node;
521 
522     if (document->intSubset && document->intSubset->ExternalID
523         && strcmp((char *)document->intSubset->ExternalID, "-//WAPFORUM//DTD PROV 1.0//EN") == 0) {
524         /* OMA ProvCont */
525         (*otabxml)->wbxml_version = 0x03; /* WBXML Version number 1.3  */
526         (*otabxml)->public_id = 0x0B; /* Public id for this kind of doc */
527     } else {
528         /* OTA */
529         (*otabxml)->wbxml_version = 0x01; /* WBXML Version number 1.1  */
530         (*otabxml)->public_id = 0x01; /* Public id for an unknown document type */
531     }
532     (*otabxml)->code_page = 0;
533 
534     charset = octstr_create("UTF-8");
535     (*otabxml)->charset = parse_charset(charset);
536     octstr_destroy(charset);
537 
538     node = xmlDocGetRootElement(document);
539     return parse_node(node, otabxml);
540 }
541 
542 /*
543  * The recursive parsing function for the parsing tree. Function checks the
544  * type of the node, calls for the right parse function for the type, then
545  * calls itself for the first child of the current node if there's one and
546  * after that calls itself for the next child on the list.
547  */
548 
parse_node(xmlNodePtr node,simple_binary_t ** otabxml)549 static int parse_node(xmlNodePtr node, simple_binary_t **otabxml)
550 {
551     int status = 0;
552 
553     /* Call for the parser function of the node type. */
554     switch (node->type) {
555         case XML_ELEMENT_NODE:
556             status = parse_element(node, otabxml);
557             break;
558         case XML_TEXT_NODE:
559         case XML_COMMENT_NODE:
560         case XML_PI_NODE:
561             /* Text nodes, comments and PIs are ignored. */
562             break;
563         /*
564          * XML has also many other node types, these are not needed with
565          * OTA. Therefore they are assumed to be an error.
566          */
567         default:
568             error(0, "OTA compiler: Unknown XML node in the OTA source.");
569             return -1;
570             break;
571     }
572 
573     /*
574      * If node is an element with content, it will need an end tag after it's
575      * children. The status for it is returned by parse_element.
576      */
577     switch (status) {
578         case 0:
579             if (node->children != NULL && parse_node(node->children, otabxml) == -1)
580                 return -1;
581             break;
582         case 1:
583             if (node->children != NULL && parse_node(node->children, otabxml) == -1)
584                 return -1;
585             parse_end(otabxml);
586             break;
587         case -1: /* Something went wrong in the parsing. */
588             return -1;
589             break;
590         default:
591             warning(0,"OTA compiler: Undefined return value in a parse function.");
592             return -1;
593             break;
594     }
595 
596     if (node->next != NULL && parse_node(node->next, otabxml) == -1)
597         return -1;
598 
599     return 0;
600 }
601 
602 /*
603  * Parse only valid syncsettings tags. Output element tags as binary
604  *  tokens. If the element has CDATA content, output it.
605  * Returns:      1, add an end tag (element node has no children)
606  *               0, do not add an end tag (it has children)
607  *              -1, an error occurred
608  */
parse_ota_syncsettings(xmlNodePtr node,simple_binary_t ** otabxml)609 static int parse_ota_syncsettings(xmlNodePtr node, simple_binary_t **otabxml)
610 {
611     Octstr *name, *content;
612     unsigned char status_bits, ota_hex;
613     int add_end_tag;
614     size_t i;
615 
616     name = NULL;
617     content = NULL;
618     name = octstr_create((char *)node->name);
619     if (octstr_len(name) == 0) {
620         goto error;
621     }
622 
623     i = 0;
624     while (i < NUMBER_OF_SYNCSETTINGS_ELEMENTS) {
625         if (octstr_case_compare(name, octstr_imm(ota_syncsettings_elements[i].name)) == 0)
626             break;
627         ++i;
628     }
629 
630     if (i == NUMBER_OF_SYNCSETTINGS_ELEMENTS) {
631         goto error;
632     }
633 
634     ota_hex = ota_syncsettings_elements[i].token;
635     output_char(ota_syncsettings_elements[i].token, otabxml);
636 
637     /* if the node has CDATA content output it.
638      * Else expect child tags */
639     if (!only_blanks((char *)node->children->content)) {
640         content = octstr_create((char *)node->children->content);
641         parse_inline_string(content, otabxml);
642     }
643 
644     add_end_tag = 0;
645     if ((status_bits = element_check_content(node)) > 0) {
646         ota_hex = ota_hex | status_bits;
647         /* If this node has children, the end tag must be added after them. */
648         if ((status_bits & WBXML_CONTENT_BIT) == WBXML_CONTENT_BIT) {
649             add_end_tag = 1;
650         }
651     }
652 
653     octstr_destroy(content);
654     octstr_destroy(name);
655     return add_end_tag;
656 
657     error:
658         warning(0, "OTA compiler: Unknown tag '%s' in OTA SyncSettings source",
659                 octstr_get_cstr(name));
660         octstr_destroy(content);
661         octstr_destroy(name);
662         return -1;
663 }
664 
665 /*
666  * Parse an element node. Check if there is a token for an element tag; if not
667  * output the element as a string, else output the token. After that, call
668  * attribute parsing functions
669  * Returns:      1, add an end tag (element node has no children)
670  *               0, do not add an end tag (it has children)
671  *              -1, an error occurred
672  */
parse_element(xmlNodePtr node,simple_binary_t ** otabxml)673 static int parse_element(xmlNodePtr node, simple_binary_t **otabxml)
674 {
675     Octstr *name;
676     size_t i;
677     unsigned char status_bits, ota_hex;
678     int add_end_tag, syncstat;
679     xmlAttrPtr attribute;
680 
681     /* if compiling a syncsettings document there's no need to
682        continue with the parsing of ota or oma tags. */
683     syncstat = -1;
684     if (octstr_search_char((**otabxml).binary, 0x55, 0) == 0) {
685         syncstat = parse_ota_syncsettings(node, otabxml);
686         if (syncstat >= 0) {
687             return syncstat;
688         }
689     }
690 
691     name = octstr_create((char *)node->name);
692     if (octstr_len(name) == 0) {
693         octstr_destroy(name);
694         return -1;
695     }
696 
697     i = 0;
698     while (i < NUMBER_OF_ELEMENTS) {
699         if (octstr_case_compare(name, octstr_imm(ota_elements[i].name)) == 0)
700             break;
701         ++i;
702     }
703 
704     status_bits = 0x00;
705     ota_hex = 0x00;
706     add_end_tag = 0;
707 
708     if (i != NUMBER_OF_ELEMENTS) {
709         ota_hex = ota_elements[i].token;
710         if ((status_bits = element_check_content(node)) > 0) {
711             ota_hex = ota_hex | status_bits;
712             if ((status_bits & WBXML_CONTENT_BIT) == WBXML_CONTENT_BIT)
713                 add_end_tag = 1;
714         }
715         output_char(ota_hex, otabxml);
716     } else {
717         warning(0, "OTA compiler: Unknown tag '%s' in OTA source", octstr_get_cstr(name));
718         ota_hex = WBXML_LITERAL;
719         if ((status_bits = element_check_content(node)) > 0) {
720             ota_hex = ota_hex | status_bits;
721             /* If this node has children, the end tag must be added after them. */
722             if ((status_bits & WBXML_CONTENT_BIT) == WBXML_CONTENT_BIT)
723                 add_end_tag = 1;
724         }
725         output_char(ota_hex, otabxml);
726         output_octet_string(octstr_duplicate(name), otabxml);
727     }
728 
729     if (node->properties != NULL) {
730         attribute = node->properties;
731         while (attribute != NULL) {
732             parse_attribute(attribute, otabxml);
733             attribute = attribute->next;
734         }
735         parse_end(otabxml);
736     }
737 
738     octstr_destroy(name);
739     return add_end_tag;
740 }
741 
742 /*
743  * Tokenises an attribute, and in most cases, its value. (Some values are re-
744  * presented as an inline string). Tokenisation is based on tables in ota,
745  * chapters 8.1 and 8.2.
746  * Returns 0 when success, -1 when error.
747  */
parse_attribute(xmlAttrPtr attr,simple_binary_t ** otabxml)748 static int parse_attribute(xmlAttrPtr attr, simple_binary_t **otabxml)
749 {
750     Octstr *name, *value, *valueos, *nameos;
751     unsigned char ota_hex;
752     size_t i, limit;
753     ota_3table_t *alist;
754 
755     name = octstr_create((char *)attr->name);
756 
757     if (attr->children != NULL)
758         value = create_octstr_from_node((char *)attr->children);
759     else
760         value = NULL;
761 
762     if (value == NULL)
763         goto error;
764 
765     /* OMA has it's own dedicated public ID, so use this */
766     if ((*otabxml)->public_id == 0x0B) {
767         alist = oma_ota_attributes;
768         limit = NUMBER_OF_OMA_ATTRIBUTES;
769     } else {
770         alist = ota_attributes;
771         limit = NUMBER_OF_ATTRIBUTES;
772     }
773 
774     i = 0;
775     valueos = NULL;
776     nameos = NULL;
777     while (i < limit) {
778         nameos = octstr_imm(alist[i].name);
779         if (octstr_case_compare(name, nameos) == 0) {
780             if (alist[i].value != NULL) {
781                 valueos = octstr_imm(alist[i].value);
782             }
783             if (octstr_case_compare(value, valueos) == 0) {
784                 break;
785             }
786             if (octstr_compare(valueos, octstr_imm("INLINE")) == 0) {
787                 break;
788             }
789         }
790        ++i;
791     }
792 
793     if (i == limit) {
794         warning(0, "OTA compiler: Unknown attribute '%s' in OTA source, "
795                    "with value '%s'.",
796                 octstr_get_cstr(name), octstr_get_cstr(value));
797         goto error;
798     }
799 
800     ota_hex = alist[i].token;
801     /* if not inline used */
802     if (octstr_compare(valueos, octstr_imm("INLINE")) != 0) {
803         /* Switch code page. */
804         if (alist[i].code_page != (*otabxml)->code_page) {
805             output_char(0, otabxml);
806             output_char(alist[i].code_page, otabxml);
807             (*otabxml)->code_page = alist[i].code_page;
808         }
809         /* if OMA add value tag */
810         if ((*otabxml)->public_id == 0x0B && name
811             && octstr_case_compare(name, octstr_imm("value")) == 0)
812             output_char(OMA_VALUE_TAG, otabxml);
813         output_char(ota_hex, otabxml);
814     } else {
815         /* Switch code page. */
816         if (alist[i].code_page != (*otabxml)->code_page) {
817             output_char(0, otabxml);
818             output_char(alist[i].code_page, otabxml);
819             (*otabxml)->code_page = alist[i].code_page;
820         }
821         output_char(ota_hex, otabxml);
822         parse_inline_string(value, otabxml);
823     }
824 
825     octstr_destroy(name);
826     octstr_destroy(value);
827     return 0;
828 
829 error:
830     octstr_destroy(name);
831     octstr_destroy(value);
832     return -1;
833 }
834