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