libsyncml 0.5.4

- Main Page
- Modules
- Data Structures
- Files

- File List

sml_xml_assm.c
1 /*
2 * libsyncml - A syncml protocol implementation
3 * Copyright (C) 2005 Armin Bauer <armin.bauer@opensync.org>
4 * Copyright (C) 2007-2009 Michael Bell <michael.bell@opensync.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22 #include <libsyncml/syncml.h>
23
24 #include <libsyncml/syncml_internals.h>
25 #include <libsyncml/sml_elements_internals.h>
26 #include <libsyncml/sml_command_internals.h>
27 #include <libsyncml/sml_devinf_internals.h>
28 #include <libsyncml/sml_session_internals.h>
29 #include "libsyncml/sml_error_internals.h"
30
31 #include "sml_xml_assm.h"
32 #include "sml_xml_assm_internals.h"
33
34 #define BUFFER_SIZE 500
35
43
44 static SmlBool _smlXmlAssemblerStartNodeNS(SmlXmlAssembler *assm, const char *name, const char *uri, SmlError **error)
45 {
46 CHECK_ERROR_REF
47 smlAssert(assm);
48 smlAssert(assm->writer);
49 smlAssert(name != NULL);
50 smlAssert(strlen(name) > 0);
51 smlTrace(TRACE_INTERNAL, "%s: Starting \"%s\"", __func__, VA_STRING(name));
52 int rc = xmlTextWriterStartElementNS(assm->writer, NULL, (xmlChar *)name, (xmlChar *)uri);
53 if (rc < 0) {
54 smlErrorSet(error, SML_ERROR_GENERIC, "Unable to start node");
55 return FALSE;
56 }
57 return TRUE;
58 }
59
60 static SmlBool _smlXmlAssemblerStartNode(SmlXmlAssembler *assm, const char *name, SmlError **error)
61 {
62 CHECK_ERROR_REF
63 return _smlXmlAssemblerStartNodeNS(assm, name, NULL, error);
64 }
65
66 static SmlBool _smlXmlAssemblerEndNode(SmlXmlAssembler *assm, SmlError **error)
67 {
68 CHECK_ERROR_REF
69 smlTrace(TRACE_INTERNAL, "%s: Ending node", __func__);
70 int rc = xmlTextWriterEndElement(assm->writer);
71 if (rc < 0) {
72 smlErrorSet(error, SML_ERROR_GENERIC, "Unable to end node (%d).", rc);
73 return FALSE;
74 }
75 return TRUE;
76 }
77
78 static SmlBool _smlXmlAssemblerAddStringNS(SmlXmlAssembler *assm, const char *name, const char *uri, const char *value, SmlError **error)
79 {
80 CHECK_ERROR_REF
81 int rc = xmlTextWriterWriteElementNS(assm->writer, NULL, (xmlChar *)name, (xmlChar *)uri, (xmlChar *)value);
82 if (rc < 0) {
83 smlErrorSet(error, SML_ERROR_GENERIC, "Unable to add string (%d - %s:%s -> %s).", rc, VA_STRING(uri), VA_STRING(name), VA_STRING(value));
84 return FALSE;
85 }
86 return TRUE;
87 }
88
89 static SmlBool _smlXmlAssemblerAddString(SmlXmlAssembler *assm, const char *name, const char *value, SmlError **error)
90 {
91 CHECK_ERROR_REF
92 int rc = xmlTextWriterWriteElement(assm->writer, (xmlChar *)name, (xmlChar *)value);
93 if (rc < 0) {
94 smlErrorSet(error, SML_ERROR_GENERIC, "Unable to add pure string (%d - %s -> %s).", rc, VA_STRING(name), VA_STRING(value));
95 return FALSE;
96 }
97 return TRUE;
98 }
99
100 static SmlBool _smlXmlAssemblerAddData(SmlXmlAssembler *assm, const char *name, const char *value, unsigned int size, SmlBool raw, SmlError **error)
101 {
102 CHECK_ERROR_REF
103 int rc = 0;
104 if (!_smlXmlAssemblerStartNode(assm, name, error))
105 return FALSE;
106
107 if (raw)
108 rc = xmlTextWriterWriteRawLen(assm->writer, (xmlChar *)value, size);
109 else
110 rc = xmlTextWriterWriteFormatCDATA(assm->writer, "%*s", size, (xmlChar *)value);
111
112 if (rc < 0) {
113 smlErrorSet(error, SML_ERROR_GENERIC, "Unable to add data (%d).", rc);
114 return FALSE;
115 }
116
117 if (!_smlXmlAssemblerEndNode(assm, error))
118 return FALSE;
119
120 return TRUE;
121 }
122
123 static SmlBool _smlXmlAssemblerAddID(SmlXmlAssembler *assm, const char *name, unsigned int id, SmlError **error)
124 {
125 CHECK_ERROR_REF
126 int rc = xmlTextWriterWriteFormatElement(assm->writer, (xmlChar *)name, "%i", id);
127 if (rc < 0) {
128 smlErrorSet(error, SML_ERROR_GENERIC, "Unable to add id");
129 return FALSE;
130 }
131 return TRUE;
132 }
133
134 static SmlBool _smlXmlAssemblerAddIDNS(SmlXmlAssembler *assm, const char *name, const char *uri, unsigned int id, SmlError **error)
135 {
136 CHECK_ERROR_REF
137 int rc = xmlTextWriterWriteFormatElementNS(assm->writer, NULL, (xmlChar *)name, (xmlChar *)uri, "%i", id);
138 if (rc < 0) {
139 smlErrorSet(error, SML_ERROR_GENERIC, "Unable to add id");
140 return FALSE;
141 }
142 return TRUE;
143 }
144
145 static SmlBool _smlAssembleUseMaxObjSize(SmlXmlAssembler *assm)
146 {
147 smlTrace(TRACE_ENTRY, "%s(%p)", __func__, assm);
148
149 /* check the configuration */
150 const char *opt = smlAssemblerGetOption(assm->assembler, "USE_LARGEOBJECTS");
151 SmlBool supportsLargeObjects = (opt && !atoi(opt)) ? FALSE : TRUE;
152
153 /* server should react only the client behavior */
154 if (assm->session->sessionType == SML_SESSION_TYPE_SERVER)
155 {
156 if (smlAssemblerGetRemoteMaxObjSize(assm->assembler) <= 0)
157 supportsLargeObjects = FALSE;
158 if (smlAssemblerGetRemoteMaxMsgSize(assm->assembler) <= 0)
159 supportsLargeObjects = FALSE;
160 }
161
162 /* SyncML 1.0 does not support large objects */
163 if (assm->session->version == SML_VERSION_10)
164 supportsLargeObjects = FALSE;
165
166 /* If MaxObjsize must really be sent
167 * then check if it is configured
168 */
169 if (smlSessionGetLocalMaxObjSize(assm->session) <= 0)
170 supportsLargeObjects = FALSE;
171
172 smlTrace(TRACE_EXIT, "%s - %d", __func__, supportsLargeObjects);
173 return supportsLargeObjects;
174 }
175
176 static SmlBool _smlAssembleMaxObjSize(SmlXmlAssembler *assm, SmlError **error)
177 {
178 smlTrace(TRACE_ENTRY, "%s(%p)", __func__, assm);
179 CHECK_ERROR_REF
180
181 /* It is allowed to add MaxObjSize to the Alert or Sync
182 * command and libsyncml adds the MaxObjSize to the Sync
183 * command. Explanation from OMA DS Protocol v1.2:
184 *
185 * 6 Protocol Fundamentals
186 * 6.10 Large Object Handling
187 * 6.10.1 Conformance statements
188 * Citation: If a device supports receiving Large
189 * Objects it MUST declare the maximum size of
190 * object (<MaxObjSize> tag) it is capable of
191 * receiving as Meta information within the
192 * Alert or Sync command, as specified in
193 * [META].
194 *
195 * SyncML 1.0 does not support large objects. Therefore
196 * MaxObjSize must not be sent because otherwise this
197 * could result in errors (bad request/message).
198 */
199 if (!_smlXmlAssemblerAddIDNS(assm, SML_ELEMENT_MAXOBJSIZE, SML_NAMESPACE_METINF, smlSessionGetLocalMaxObjSize(assm->session), error))
200 goto error;
201
202 smlTrace(TRACE_EXIT, "%s", __func__);
203 return TRUE;
204
205 error:
206 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
207 return FALSE;
208 }
209
210 SmlBool smlLocationAssemble(SmlLocation *location, SmlXmlAssembler *assm, const char *name, SmlError **error)
211 {
212 smlTrace(TRACE_ENTRY, "%s(%p, %p, %s, %p)", __func__, location, assm, VA_STRING(name), error);
213 CHECK_ERROR_REF
214 smlAssert(assm);
215 smlAssert(location);
216
217 if (name) {
218 if (!_smlXmlAssemblerStartNode(assm, name, error))
219 goto error;
220 }
221
222 if (!location->locURI) {
223 smlErrorSet(error, SML_ERROR_GENERIC, "No locURI set");
224 goto error;
225 }
226
227 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_LOCURI, location->locURI, error))
228 goto error;
229
230 if (location->locName) {
231 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_LOCNAME, location->locName, error))
232 goto error;
233 }
234
235 if (name) {
236 if (!_smlXmlAssemblerEndNode(assm, error))
237 goto error;
238 }
239
240 smlTrace(TRACE_EXIT, "%s", __func__);
241 return TRUE;
242
243 error:
244 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
245 return FALSE;
246 }
247
248
249
250 SmlBool smlAnchorAssemble(SmlAnchor *anchor, SmlXmlAssembler *assm, SmlError **error)
251 {
252 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, anchor, assm, error);
253 CHECK_ERROR_REF
254 smlAssert(assm);
255 smlAssert(anchor);
256
257 /* Start the anchor and switch to syncml:metinf namespace.
258 * It is not possible to remove the namespace from Last and
259 * Next because otherwise the Status commands could be longer
260 * then the Alert commands. If this would happen then the
261 * Status commands alone could be longer than MaxMsgSize.
262 *
263 * It is not sure how a mobile would react in this situation.
264 */
265 if (!_smlXmlAssemblerStartNodeNS(assm, SML_ELEMENT_ANCHOR, SML_NAMESPACE_METINF, error))
266 goto error;
267
268 if (!anchor->next) {
269 smlErrorSet(error, SML_ERROR_GENERIC, "No next set");
270 goto error;
271 }
272
273 /* SyncML Meta-Information DTD 1.1, Page 6, 5.1 Anchor - Content Model: (Last?, Next)
274 Last is optional, don't write a empty Last node.
275 */
276 if (anchor->last) {
277 if (!_smlXmlAssemblerAddStringNS(assm, SML_ELEMENT_LAST, SML_NAMESPACE_METINF, anchor->last, error))
278 goto error;
279
280 }
281
282 if (!_smlXmlAssemblerAddStringNS(assm, SML_ELEMENT_NEXT, SML_NAMESPACE_METINF, anchor->next, error))
283 goto error;
284
285 if (!_smlXmlAssemblerEndNode(assm, error))
286 goto error;
287
288 smlTrace(TRACE_EXIT, "%s", __func__);
289 return TRUE;
290
291 error:
292 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
293 return FALSE;
294 }
295
296 SmlBool smlItemAssemble(SmlItem *item, SmlXmlAssembler *assm, SmlError **error)
297 {
298 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, item, assm, error);
299 CHECK_ERROR_REF
300 smlAssert(assm);
301 smlAssert(item);
302
303 if (assm->moreDataSet) {
304 smlErrorSet(error, SML_ERROR_GENERIC, "Trying to start a new item while last item had more data");
305 goto error;
306 }
307
308 /* Begin of Item */
309 if (!_smlXmlAssemblerStartNode(assm, SML_ELEMENT_ITEM, error))
310 goto error;
311
312 /* Target */
313 if (smlItemGetTarget(item)) {
314 if (!smlLocationAssemble(smlItemGetTarget(item), assm, SML_ELEMENT_TARGET, error))
315 goto error;
316 }
317
318 /* Source */
319 if (smlItemGetSource(item)) {
320 if (!smlLocationAssemble(smlItemGetSource(item), assm, SML_ELEMENT_SOURCE, error))
321 goto error;
322 }
323
324 /* SourceParent */
325 if (smlItemGetSourceParent(item)) {
326 if (!smlLocationAssemble(smlItemGetSourceParent(item), assm, SML_ELEMENT_SOURCE_PARENT, error))
327 goto error;
328 }
329
330 /* TargetParent */
331 if (smlItemGetTargetParent(item)) {
332 if (!smlLocationAssemble(smlItemGetTargetParent(item), assm, SML_ELEMENT_TARGET_PARENT, error))
333 goto error;
334 }
335
336 /* Data */
337 if (smlItemHasData(item)) {
338 if (item->disabled) {
339 if (!_smlXmlAssemblerAddData(assm, SML_ELEMENT_DATA, "", 0, item->raw, error))
340 goto error;
341 } else {
342 char *data = NULL;
343 unsigned int size = 0;
344 if (!smlItemGetData(item, &data, &size, error))
345 goto error;
346
347 if (!_smlXmlAssemblerAddData(assm, SML_ELEMENT_DATA, data, size, item->raw, error))
348 goto error;
349 }
350 }
351
352 /* MoreData */
353 if (item->moreData) {
354 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_MOREDATA, "", error))
355 goto error;
356
357 assm->moreDataSet = TRUE;
358 }
359
360 /* End of Item */
361 if (!_smlXmlAssemblerEndNode(assm, error))
362 goto error;
363
364 smlTrace(TRACE_EXIT, "%s", __func__);
365 return TRUE;
366
367 error:
368 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
369 return FALSE;
370 }
371
372 SmlBool smlCredAssemble(SmlCred *cred, SmlXmlAssembler *assm, SmlError **error)
373 {
374 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, cred, assm, error);
375 CHECK_ERROR_REF
376 smlAssert(assm);
377 smlAssert(cred);
378
379 if (!_smlXmlAssemblerStartNode(assm, SML_ELEMENT_CRED, error))
380 goto error;
381
382 //Meta
383 if (!_smlXmlAssemblerStartNode(assm, SML_ELEMENT_META, error))
384 goto error;
385
386 switch (cred->format) {
387 case SML_FORMAT_TYPE_BASE64:
388 if (!_smlXmlAssemblerAddStringNS(assm, SML_ELEMENT_FORMAT, SML_NAMESPACE_METINF, SML_BASE64, error))
389 goto error;
390 break;
391 default:
392 smlErrorSet(error, SML_ERROR_GENERIC, "SyncML credential: Unknown format %d.", cred->format);
393 goto error;
394 }
395
396 switch (cred->type) {
397 case SML_AUTH_TYPE_BASIC:
398 if (!_smlXmlAssemblerAddStringNS(assm, SML_ELEMENT_TYPE, SML_NAMESPACE_METINF, SML_AUTH_BASIC, error))
399 goto error;
400 break;
401 case SML_AUTH_TYPE_MD5:
402 if (!_smlXmlAssemblerAddStringNS(assm, SML_ELEMENT_TYPE, SML_NAMESPACE_METINF, SML_AUTH_MD5, error))
403 goto error;
404 break;
405 default:
406 smlErrorSet(error, SML_ERROR_GENERIC, "Unknown format");
407 goto error;
408 }
409
410 //META
411 if (!_smlXmlAssemblerEndNode(assm, error))
412 goto error;
413
414 if (!_smlXmlAssemblerAddData(assm, SML_ELEMENT_DATA, cred->data, strlen(cred->data), TRUE, error))
415 goto error;
416
417 if (!_smlXmlAssemblerEndNode(assm, error))
418 goto error;
419
420 smlTrace(TRACE_EXIT, "%s", __func__);
421 return TRUE;
422
423 error:
424 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
425 return FALSE;
426 }
427
428 SmlBool smlAccessAssemble(SmlXmlAssembler *assm, SmlCommand *change, SmlError **error)
429 {
430 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, assm, change, error);
431 CHECK_ERROR_REF
432 smlAssert(change);
433 smlAssert(assm);
434
435 if (!change->private.access.item) {
436 smlErrorSet(error, SML_ERROR_GENERIC, "Missing item");
437 goto error;
438 }
439
440 if (!change->private.access.item->contenttype) {
441 smlErrorSet(error, SML_ERROR_GENERIC, "Missing contenttype");
442 goto error;
443 }
444
445 //Meta
446 if (!_smlXmlAssemblerStartNode(assm, SML_ELEMENT_META, error))
447 goto error;
448
449 if (!_smlXmlAssemblerAddStringNS(assm, SML_ELEMENT_TYPE, SML_NAMESPACE_METINF, change->private.access.item->contenttype, error))
450 goto error;
451
452 //META
453 if (!_smlXmlAssemblerEndNode(assm, error))
454 goto error;
455
456 if (!smlItemAssemble(change->private.access.item, assm, error))
457 goto error;
458
459 smlTrace(TRACE_EXIT, "%s", __func__);
460 return TRUE;
461
462 error:
463 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
464 return FALSE;
465 }
466
467 SmlBool smlChangeAssemble(SmlXmlAssembler *assm, SmlCommand *change, SmlError **error)
468 {
469 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, assm, change, error);
470 CHECK_ERROR_REF
471 smlAssert(change);
472 smlAssert(assm);
473
474 if (!change->private.change.items ||
475 !g_list_length(change->private.change.items)) {
476 smlErrorSet(error, SML_ERROR_GENERIC, "Missing items");
477 goto error;
478 }
479
480 /* libsyncml only supports one item per change command */
481 smlAssert(g_list_length(change->private.change.items) == 1);
482 SmlItem *item = g_list_nth_data(change->private.change.items, 0);
483
484 if (!item) {
485 smlErrorSet(error, SML_ERROR_GENERIC, "One item of the item list is NULL.");
486 goto error;
487 }
488 if (!item->contenttype) {
489 smlErrorSet(error, SML_ERROR_GENERIC, "Missing contenttype");
490 goto error;
491 }
492
493 //Meta
494 if (!_smlXmlAssemblerStartNode(assm, SML_ELEMENT_META, error))
495 goto error;
496
497 if (!_smlXmlAssemblerAddStringNS(assm, SML_ELEMENT_TYPE, SML_NAMESPACE_METINF, item->contenttype, error))
498 goto error;
499
500 /* We will add the max obj size node, if USE_LARGEOBJECTS is true or not set at all.
501 * And the remote side must have set a maxobjsize if we are a server */
502 const char *opt = smlAssemblerGetOption(assm->assembler, "USE_LARGEOBJECTS");
503 SmlBool supportsLargeObjects = (opt && !atoi(opt)) ? FALSE : TRUE;
504
505 smlTrace(TRACE_INTERNAL, "%s: Large object: use %i, server %i, requestedSize %i", __func__, supportsLargeObjects, assm->session->sessionType == SML_SESSION_TYPE_SERVER ? 1 : 0, smlAssemblerGetRemoteMaxObjSize(assm->assembler));
506
507 if (supportsLargeObjects && change->size) {
508 if (!_smlXmlAssemblerAddIDNS(assm, SML_ELEMENT_SIZE, SML_NAMESPACE_METINF, change->size, error))
509 goto error;
510 }
511
512 //META
513 if (!_smlXmlAssemblerEndNode(assm, error))
514 goto error;
515
516 //Item(s)
517
518 /* Item has to deal with four different situations:
519 * 1. If this is a new item but the remote peer only supports
520 * the Replace command and the local peer is an OMA DS
521 * server then the ID/location must be send as target.
522 * If the local peer is an OMA DS client then nothing
523 * changes. FYI an OMA DS server must support the Add
524 * command.
525 * => Target must be set (Target is the former Source)
526 * 2. If this is a new item then the local peer only knows
527 * the ID of the item.
528 * => Source must be set
529 * 3. If this is a changed or deleted item and the local peer
530 * is an OMA DS server then the item must reference the ID
531 * of the remote peer because of the submitted map. Please
532 * not that the remote peer as an OMA DS client must only
533 * know its own ID of the item. The mapping of locations
534 * (IDs) is the exclusive job of the OMA DS server.
535 * => Target must be set (Source is optional)
536 * 4. If this is a changed or deleted item and the local peer
537 * is an OMA DS client then the item must reference the ID
538 * of the local peer only because the mapping of locations
539 * (IDs) must be done by the OMA DS server.
540 * => Source must be set
541 */
542 SmlSessionType sessionType = assm->session->sessionType;
543 opt = smlAssemblerGetOption(assm->assembler, "ONLY_REPLACE");
544 if (change->type == SML_COMMAND_TYPE_ADD)
545 {
546 if (opt && atoi(opt) && /* remote peer supports ONLY_REPLACE */
547 sessionType == SML_SESSION_TYPE_SERVER) {
548 /* only Target must be set */
549 if (item->target)
550 smlLocationUnref(item->target);
551 item->target = item->source;
552 item->source = NULL;
553 } else {
554 /* only Source must be set */
555 if (item->target)
556 smlLocationUnref(item->target);
557 item->target = NULL;
558 }
559 } else {
560 if (sessionType == SML_SESSION_TYPE_SERVER) {
561 /* Target must be set */
562 if (item->source)
563 smlLocationUnref(item->source);
564 item->source = NULL;
565 } else {
566 /* only Source must be set */
567 if (item->target)
568 smlLocationUnref(item->target);
569 item->target = NULL;
570 }
571 }
572
573 if (!smlItemAssemble(item, assm, error))
574 goto error;
575
576 smlTrace(TRACE_EXIT, "%s", __func__);
577 return TRUE;
578
579 error:
580 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
581 return FALSE;
582 }
583
584 SmlBool smlSyncAssemble(SmlXmlAssembler *assm, SmlCommand *cmd, SmlError **error)
585 {
586 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, assm, cmd, error);
587 CHECK_ERROR_REF
588 smlAssert(cmd);
589 smlAssert(assm);
590
591 if (!cmd->target) {
592 smlErrorSet(error, SML_ERROR_GENERIC, "No target set");
593 goto error;
594 }
595
596 /* The specification OMA DS Protocol v1.2 allows to add
597 * MaxObjsize to Alert or Sync commands but all examples show
598 * it only in Alert commands. Therefore libsyncml adds it to
599 * Alert commands only.
600 */
601
602 if (!smlLocationAssemble(cmd->target, assm, SML_ELEMENT_TARGET, error))
603 goto error;
604
605 if (!cmd->source) {
606 smlErrorSet(error, SML_ERROR_GENERIC, "No source set");
607 goto error;
608 }
609
610 if (!smlLocationAssemble(cmd->source, assm, SML_ELEMENT_SOURCE, error))
611 goto error;
612
613 if (_smlAssembleUseMaxObjSize(assm))
614 {
615 if (!_smlXmlAssemblerStartNode(assm, SML_ELEMENT_META, error))
616 goto error;
617
618 if (!_smlAssembleMaxObjSize(assm, error))
619 goto error;
620
621 if (!_smlXmlAssemblerEndNode(assm, error))
622 goto error;
623 }
624
625 const char *opt = smlAssemblerGetOption(assm->assembler, "USE_NUMBEROFCHANGES");
626 SmlBool supportsNumberOfChanges = (opt && !atoi(opt)) ? FALSE : TRUE;
627 if (supportsNumberOfChanges && assm->session->version != SML_VERSION_10) {
628 if (!_smlXmlAssemblerAddID(assm, SML_ELEMENT_NUMBEROFCHANGES, cmd->private.sync.numChanged, error))
629 goto error;
630 }
631
632 smlTrace(TRACE_EXIT, "%s", __func__);
633 return TRUE;
634
635 error:
636 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
637 return FALSE;
638 }
639
640 SmlBool smlMapItemAssemble(SmlXmlAssembler *assm, SmlMapItem *item, SmlError **error)
641 {
642 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, assm, item, error);
643 CHECK_ERROR_REF
644 smlAssert(assm);
645 smlAssert(item);
646
647 if (!_smlXmlAssemblerStartNode(assm, SML_ELEMENT_MAPITEM, error))
648 goto error;
649
650 if (item->source) {
651 if (!smlLocationAssemble(item->source, assm, SML_ELEMENT_SOURCE, error))
652 goto error;
653 }
654
655 if (item->target) {
656 if (!smlLocationAssemble(item->target, assm, SML_ELEMENT_TARGET, error))
657 goto error;
658 }
659
660 //MapItem
661 if (!_smlXmlAssemblerEndNode(assm, error))
662 goto error;
663
664 smlTrace(TRACE_EXIT, "%s", __func__);
665 return TRUE;
666
667 error:
668 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
669 return FALSE;
670 }
671
672 SmlBool smlMapAssemble(SmlXmlAssembler *assm, SmlCommand *cmd, SmlError **error)
673 {
674 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, assm, cmd, error);
675 CHECK_ERROR_REF
676 smlAssert(cmd);
677 smlAssert(assm);
678
679 if (!cmd->target) {
680 smlErrorSet(error, SML_ERROR_GENERIC, "No target set");
681 goto error;
682 }
683
684 if (!smlLocationAssemble(cmd->target, assm, SML_ELEMENT_TARGET, error))
685 goto error;
686
687 if (!cmd->source) {
688 smlErrorSet(error, SML_ERROR_GENERIC, "No source set");
689 goto error;
690 }
691
692 if (!smlLocationAssemble(cmd->source, assm, SML_ELEMENT_SOURCE, error))
693 goto error;
694
695 GList *m = NULL;
696 for (m = cmd->private.map.items; m; m = m->next) {
697 SmlMapItem *item = m->data;
698 if (!smlMapItemAssemble(assm, item, error))
699 goto error;
700 }
701
702 smlTrace(TRACE_EXIT, "%s", __func__);
703 return TRUE;
704
705 error:
706 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
707 return FALSE;
708 }
709
710 SmlBool smlAlertAssemble(SmlXmlAssembler *assm, SmlCommand *cmd, SmlError **error)
711 {
712 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, assm, cmd, error);
713 CHECK_ERROR_REF
714 smlAssert(cmd);
715 smlAssert(assm);
716
717 /* Results itself and CmdID must be set by the caller.
718 * This function only add the Results specific content.
719 */
720
721 /* No Resp */
722
723 /* Cred */
724
725 /* Data */
726 if (!_smlXmlAssemblerAddID(assm, SML_ELEMENT_DATA, cmd->private.alert.type, error))
727 goto error;
728
729 /* Correlator */
730
731 /* Begin of Item */
732 if (!_smlXmlAssemblerStartNode(assm, SML_ELEMENT_ITEM, error))
733 goto error;
734
735 /* Target */
736 if (cmd->target) {
737 if (!smlLocationAssemble(cmd->target, assm, SML_ELEMENT_TARGET, error))
738 goto error;
739 }
740
741 /* Source */
742 if (cmd->source) {
743 if (!smlLocationAssemble(cmd->source, assm, SML_ELEMENT_SOURCE, error))
744 goto error;
745 } else {
746 // NEXT MESSAGE alerts does not need a source/target
747 if (cmd->private.alert.type != SML_ALERT_NEXT_MESSAGE) {
748 smlErrorSet(error, SML_ERROR_GENERIC, "No source set");
749 goto error;
750 }
751 }
752
753 /* SourceParent */
754
755 /* TargetParent */
756
757 /* Begin of META */
758
759 SmlBool meta = FALSE;
760 if (cmd->private.alert.contentType)
761 meta = TRUE;
762 if (cmd->private.alert.anchor)
763 meta = TRUE;
764 if (_smlAssembleUseMaxObjSize(assm))
765 meta = TRUE;
766
767 if (meta && !_smlXmlAssemblerStartNode(assm, SML_ELEMENT_META, error))
768 goto error;
769
770 if (cmd->private.alert.contentType &&
771 !_smlXmlAssemblerAddStringNS(assm, SML_ELEMENT_TYPE, SML_NAMESPACE_METINF,
772 cmd->private.alert.contentType, error))
773 goto error;
774
775 if (cmd->private.alert.anchor &&
776 !smlAnchorAssemble(cmd->private.alert.anchor, assm, error))
777 goto error;
778
779 if (_smlAssembleUseMaxObjSize(assm) &&
780 !_smlAssembleMaxObjSize(assm, error))
781 goto error;
782
783 if (meta && !_smlXmlAssemblerEndNode(assm, error))
784 goto error;
785
786 /* End of META */
787
788 /* End of Item */
789 if (!_smlXmlAssemblerEndNode(assm, error))
790 goto error;
791
792 smlTrace(TRACE_EXIT, "%s", __func__);
793 return TRUE;
794
795 error:
796 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
797 return FALSE;
798 }
799
800 SmlBool smlResultsAssemble(SmlXmlAssembler *assm, SmlCommand *cmd, SmlError **error)
801 {
802 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, assm, cmd, error);
803 CHECK_ERROR_REF
804 smlAssert(cmd);
805 smlAssert(assm);
806
807 /* Results itself and CmdID must be set by the caller.
808 * This function only add the Results specific content.
809 */
810
811 /* MsgRef */
812 if (!_smlXmlAssemblerAddID(assm, SML_ELEMENT_MSGREF, cmd->private.results.status->msgRef, error))
813 goto error;
814
815 /* CmdRef */
816 if (!_smlXmlAssemblerAddID(assm, SML_ELEMENT_CMDREF, cmd->private.results.status->cmdRef, error))
817 goto error;
818
819 /* Meta */
820 if (!_smlXmlAssemblerStartNode(assm, SML_ELEMENT_META, error))
821 goto error;
822 if (!_smlXmlAssemblerAddStringNS(assm, SML_ELEMENT_TYPE, SML_NAMESPACE_METINF, cmd->private.results.status->item->contenttype, error))
823 goto error;
824 if (!_smlXmlAssemblerEndNode(assm, error))
825 goto error;
826
827 /* TargetRef */
828 if (cmd->private.results.status->targetRef) {
829 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_TARGETREF, cmd->private.results.status->targetRef->locURI, error))
830 goto error;
831 }
832
833 /* SourceRef */
834 if (cmd->private.results.status->sourceRef) {
835 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_SOURCEREF, cmd->private.results.status->sourceRef->locURI, error))
836 goto error;
837 }
838
839 /* Item */
840 if (!smlItemAssemble(cmd->private.results.status->item, assm, error))
841 goto error;
842
843 smlTrace(TRACE_EXIT, "%s", __func__);
844 return TRUE;
845
846 error:
847 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
848 return FALSE;
849 }
850
851 SmlBool smlXmlAssemblerAddHeader(SmlXmlAssembler *assm, SmlSession *session, SmlError **error)
852 {
853 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, assm, session, error);
854 CHECK_ERROR_REF
855 smlAssert(assm);
856 smlAssert(g_mutex_trylock(assm->mutex));
857 smlAssert(session);
858
859 /* Lets see if there already was a header before */
860 if (assm->header_buffer) {
861 xmlBufferFree(assm->header_buffer);
862 assm->header_buffer = NULL;
863 }
864
865 /* We first start a new writer that will write our header into a buffer */
866 assm->header_buffer = xmlBufferCreateSize(BUFFER_SIZE);
867 if (!assm->header_buffer) {
868 smlErrorSet(error, SML_ERROR_GENERIC, "Unable to create new buffer");
869 goto error;
870 }
871
872 assm->writer = xmlNewTextWriterMemory(assm->header_buffer, 0);
873 if (!assm->writer) {
874 smlErrorSet(error, SML_ERROR_GENERIC, "Unable to create new writer");
875 goto error;
876 }
877
878 if (!_smlXmlAssemblerStartNode(assm, SML_ELEMENT_SYNCHDR, error))
879 goto error;
880
881 if (!session->protocol) {
882 smlErrorSet(error, SML_ERROR_GENERIC, "No version set");
883 goto error;
884 }
885
886 if (!session->version) {
887 smlErrorSet(error, SML_ERROR_GENERIC, "No dtd set");
888 goto error;
889 }
890
891 switch (session->protocol) {
892 case SML_PROTOCOL_SYNCML:
893 switch (session->version) {
894 case SML_VERSION_10:
895 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_VERDTD, "1.0", error))
896 goto error;
897
898 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_VERPROTO, SML_VERSION_STRING_10, error))
899 goto error;
900 break;
901 case SML_VERSION_11:
902 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_VERDTD, "1.1", error))
903 goto error;
904
905 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_VERPROTO, SML_VERSION_STRING_11, error))
906 goto error;
907 break;
908 case SML_VERSION_12:
909 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_VERDTD, "1.2", error))
910 goto error;
911
912 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_VERPROTO, SML_VERSION_STRING_12, error))
913 goto error;
914 break;
915 default:
916 smlErrorSet(error, SML_ERROR_GENERIC, "Unknown version");
917 goto error;
918 }
919 break;
920 default:
921 smlErrorSet(error, SML_ERROR_GENERIC, "Unknown protocol");
922 goto error;
923 }
924
925 if (session->sessionID) {
926 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_SESSIONID, session->sessionID, error))
927 goto error;
928 }
929
930 if (!_smlXmlAssemblerAddID(assm, SML_ELEMENT_MSGID, session->lastMessageID, error))
931 goto error;
932
933 if (!smlLocationAssemble(session->target, assm, SML_ELEMENT_TARGET, error))
934 goto error;
935
936 if (!smlLocationAssemble(session->source, assm, SML_ELEMENT_SOURCE, error))
937 goto error;
938
939 if (session->responseURI &&
940 !_smlXmlAssemblerAddString(assm, SML_ELEMENT_RESPURI, session->responseURI, error))
941 goto error;
942
943 /* The credentials must be present and calculated for the correct
944 * authentication schema (e.g. syncml:auth-basic or syncml:auth-md5).
945 */
946 if (session->cred != NULL && session->cred->data != NULL) {
947 if (!smlCredAssemble(session->cred, assm, error))
948 goto error;
949 }
950
951 /* What do we have to check here?
952 *
953 * SyncML 1.0 does not require any checks because large object
954 * handling was first specified for SyncML 1.1.
955 *
956 * SyncML 1.1 and 1.2 require some checks.
957 *
958 * 1. OMA DS server MUST support large objects.
959 * This means that a local MaxMsgSize and a local MaxObjSize
960 * MUST be specified.
961 * 2. If an OMA DS client suppors large objects then it MUST
962 * match the same requirements like the OMA DS server.
963 */
964 if (session->protocol == SML_PROTOCOL_SYNCML &&
965 session->version > SML_VERSION_10)
966 {
967 /* This is a SyncML protocol version which supports
968 * large objects.
969 */
970 if (session->sessionType == SML_SESSION_TYPE_SERVER ||
971 smlSessionGetLocalMaxObjSize(session) > 0)
972 {
973 /* Large object support is enabled. */
974 if (smlSessionGetLocalMaxMsgSize(session) < 1)
975 {
976 smlErrorSet(error, SML_ERROR_INTERNAL_MISCONFIGURATION,
977 "MaxMsgSize must be set.");
978 goto error;
979 }
980 if (smlSessionGetLocalMaxObjSize(session) < 1)
981 {
982 smlErrorSet(error, SML_ERROR_INTERNAL_MISCONFIGURATION,
983 "MaxObjSize must be set.");
984 goto error;
985 }
986 }
987 }
988
989 /* set MaxMsgSize if available */
990 unsigned int localMaxMsgSize = smlSessionGetLocalMaxMsgSize(session);
991 if (localMaxMsgSize) {
992 if (!_smlXmlAssemblerStartNode(assm, SML_ELEMENT_META, error))
993 goto error;
994
995 /* Do not add MaxObjSize here.
996 * Please see OMA DS Protocol v1.2 section 6.10.1
997 */
998 if (!_smlXmlAssemblerAddIDNS(assm, SML_ELEMENT_MAXMSGSIZE, SML_NAMESPACE_METINF, localMaxMsgSize, error))
999 goto error;
1000
1001 //META
1002 if (!_smlXmlAssemblerEndNode(assm, error))
1003 goto error;
1004 }
1005
1006 if (!_smlXmlAssemblerEndNode(assm, error))
1007 goto error;
1008
1009 /* Now close the buffer and get the content */
1010 if (xmlTextWriterEndDocument(assm->writer) < 0) {
1011 smlErrorSet(error, SML_ERROR_GENERIC, "Unable to end writer");
1012 goto error;
1013 }
1014
1015 xmlFreeTextWriter(assm->writer);
1016 assm->writer = NULL;
1017
1018 g_mutex_unlock(assm->mutex);
1019 smlTrace(TRACE_EXIT, "%s", __func__);
1020 return TRUE;
1021
1022 error:
1023 if (assm->writer) {
1024 xmlFreeTextWriter(assm->writer);
1025 assm->writer = NULL;
1026 }
1027 if (assm->header_buffer) {
1028 xmlBufferFree(assm->header_buffer);
1029 assm->header_buffer = NULL;
1030 }
1031 g_mutex_unlock(assm->mutex);
1032 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
1033 return FALSE;
1034 }
1035
1036 SmlBool smlXmlAssemblerStartCommand(SmlXmlAssembler *assm, unsigned int parentID, SmlCommand *cmd, SmlError **error)
1037 {
1038 CHECK_ERROR_REF
1039 smlAssert(assm);
1040 smlAssert(cmd);
1041
1042 if (cmd->type == SML_COMMAND_TYPE_UNKNOWN) {
1043 smlErrorSet(error, SML_ERROR_GENERIC, "No cmd set");
1044 goto error;
1045 }
1046
1047 if (!cmd->cmdID) {
1048 smlErrorSet(error, SML_ERROR_GENERIC, "No cmd ID set");
1049 goto error;
1050 }
1051
1052 /* Lets see if there already was a header before */
1053 if (!assm->header_buffer) {
1054 smlErrorSet(error, SML_ERROR_GENERIC, "Header not yet added");
1055 goto error;
1056 }
1057
1058 SmlXmlAssemblerCommand *assmcmd = smlTryMalloc0(sizeof(SmlXmlAssemblerCommand), error);
1059 if (!assmcmd)
1060 goto error;
1061 assmcmd->nodeType = SML_ASSEMBLER_NODE_OPEN;
1062 assmcmd->cmdID = cmd->cmdID;
1063 assmcmd->cmdType = cmd->type;
1064
1065 GList **appendto = &(assm->commands);
1066 if (parentID) {
1067 /* If we have a parent we first have to search for this command */
1068 SmlXmlAssemblerCommand *excmd = NULL;
1069 GList *b = NULL;
1070 for (b = assm->commands; b; b = b->next) {
1071 excmd = b->data;
1072 if (excmd->cmdID == parentID)
1073 appendto = &(excmd->children);
1074 }
1075 }
1076
1077 /* We first start a new parent writer that will write our command into a buffer */
1078 assmcmd->buffer = xmlBufferCreateSize(BUFFER_SIZE);
1079 if (!assmcmd->buffer) {
1080 smlErrorSet(error, SML_ERROR_GENERIC, "Unable to create new buffer");
1081 goto error_free_cmd;
1082 }
1083
1084 assm->writer = xmlNewTextWriterMemory(assmcmd->buffer, 0);
1085 if (!assm->writer) {
1086 smlErrorSet(error, SML_ERROR_GENERIC, "Unable to create new writer");
1087 goto error_free_buffer;
1088 }
1089
1090 /* We start without the root node */
1091 if (!_smlXmlAssemblerAddID(assm, SML_ELEMENT_CMDID, cmd->cmdID, error))
1092 goto error_free_writer;
1093
1094 switch (cmd->type) {
1095 case SML_COMMAND_TYPE_ALERT:
1096 if (!smlAlertAssemble(assm, cmd, error))
1097 goto error_free_writer;
1098 break;
1099 case SML_COMMAND_TYPE_SYNC:
1100 if (!smlSyncAssemble(assm, cmd, error))
1101 goto error_free_writer;
1102 break;
1103 case SML_COMMAND_TYPE_ADD:
1104 case SML_COMMAND_TYPE_REPLACE:
1105 case SML_COMMAND_TYPE_DELETE:
1106 if (!smlChangeAssemble(assm, cmd, error))
1107 goto error_free_writer;
1108 break;
1109 case SML_COMMAND_TYPE_PUT:
1110 case SML_COMMAND_TYPE_GET:
1111 if (!smlAccessAssemble(assm, cmd, error))
1112 goto error_free_writer;
1113 break;
1114 case SML_COMMAND_TYPE_MAP:
1115 if (!smlMapAssemble(assm, cmd, error))
1116 goto error_free_writer;
1117 break;
1118 case SML_COMMAND_TYPE_RESULTS:
1119 if (!smlResultsAssemble(assm, cmd, error))
1120 goto error_free_writer;
1121 break;
1122 default:
1123 smlErrorSet(error, SML_ERROR_GENERIC, "Unknown command type");
1124 goto error_free_writer;
1125 }
1126
1127 /* Now close the buffer */
1128 if (xmlTextWriterEndDocument(assm->writer) < 0) {
1129 smlErrorSet(error, SML_ERROR_GENERIC, "Unable to end writer");
1130 goto error_free_writer;
1131 }
1132
1133 xmlFreeTextWriter(assm->writer);
1134 assm->writer = NULL;
1135
1136 /* Now we can append the buffer and the parent*/
1137 *appendto = g_list_append(*appendto, assmcmd);
1138
1139 return TRUE;
1140
1141 error_free_writer:
1142 xmlFreeTextWriter(assm->writer);
1143 assm->writer = NULL;
1144 error_free_buffer:
1145 xmlBufferFree(assmcmd->buffer);
1146 error_free_cmd:
1147 smlSafeFree((gpointer *)&assmcmd);
1148 error:
1149 return FALSE;
1150 }
1151
1152 SmlBool smlXmlAssemblerEndCommand(SmlXmlAssembler *assm, unsigned int parentID, SmlError **error)
1153 {
1154 CHECK_ERROR_REF
1155 smlAssert(assm);
1156
1157 /* Lets see if there already was a header before */
1158 if (!assm->header_buffer) {
1159 smlErrorSet(error, SML_ERROR_GENERIC, "Header not yet added");
1160 goto error;
1161 }
1162
1163 SmlXmlAssemblerCommand *assmcmd = smlTryMalloc0(sizeof(SmlXmlAssemblerCommand), error);
1164 if (!assmcmd)
1165 goto error;
1166 assmcmd->nodeType = SML_ASSEMBLER_NODE_CLOSE;
1167
1168 GList **appendto = &(assm->commands);
1169 if (parentID) {
1170 /* If we have a parent we first have to search for this command */
1171 SmlXmlAssemblerCommand *excmd = NULL;
1172 GList *b = NULL;
1173 for (b = assm->commands; b; b = b->next) {
1174 excmd = b->data;
1175 if (excmd->cmdID == parentID)
1176 appendto = &(excmd->children);
1177 }
1178 }
1179
1180 /* Now we can append command */
1181 *appendto = g_list_append(*appendto, assmcmd);
1182
1183 return TRUE;
1184
1185 error:
1186 return FALSE;
1187 }
1188
1189 SmlBool smlXmlAssemblerRemCommand(SmlXmlAssembler *assm, unsigned int parentID, SmlError **error)
1190 {
1191 smlTrace(TRACE_ENTRY, "%s(%p, %i, %p)", __func__, assm, parentID, error);
1192 CHECK_ERROR_REF
1193 smlAssert(assm);
1194
1195 GList **removefrom = &(assm->commands);
1196 if (parentID) {
1197 /* If we have a parent we first have to search for this command */
1198 SmlXmlAssemblerCommand *excmd = NULL;
1199 GList *b = NULL;
1200 for (b = assm->commands; b; b = b->next) {
1201 excmd = b->data;
1202 if (excmd->cmdID == parentID)
1203 removefrom = &(excmd->children);
1204 }
1205 }
1206
1207 if (!*removefrom) {
1208 smlErrorSet(error, SML_ERROR_GENERIC, "Nothing to remove");
1209 goto error;
1210 }
1211
1212 GList *b = g_list_last(*removefrom);
1213 SmlXmlAssemblerCommand *cmd = b->data;
1214 *removefrom = g_list_delete_link(*removefrom, b);
1215 if (cmd->nodeType != SML_ASSEMBLER_NODE_OPEN) {
1216 smlErrorSet(error, SML_ERROR_GENERIC, "Trying to remove not a starting command");
1217 goto error;
1218 }
1219
1220 assm->moreDataSet = FALSE;
1221
1222 xmlBufferFree(cmd->buffer);
1223 smlSafeFree((gpointer *)&cmd);
1224
1225 smlTrace(TRACE_EXIT, "%s", __func__);
1226 return TRUE;
1227
1228 error:
1229 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
1230 return FALSE;
1231 }
1232
1233 SmlBool smlXmlAssemblerRemStatus(SmlXmlAssembler *assm, SmlError **error)
1234 {
1235 smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, assm, error);
1236 CHECK_ERROR_REF
1237 smlAssert(assm);
1238
1239 if (!assm->statuses) {
1240 smlErrorSet(error, SML_ERROR_GENERIC, "Trying to remove status but no status available");
1241 goto error;
1242 }
1243
1244 GList *b;
1245 SmlXmlAssemblerStatus *last = NULL;
1246 for (b = assm->statuses; b; b = b->next) {
1247 SmlXmlAssemblerStatus *status = b->data;
1248
1249 if (!status->buffer)
1250 break;
1251 last = status;
1252 }
1253
1254 if (last) {
1255 xmlBufferFree(last->buffer);
1256 last->buffer = NULL;
1257 }
1258
1259 assm->added_statuses--;
1260
1261 smlTrace(TRACE_EXIT, "%s", __func__);
1262 return TRUE;
1263
1264 error:
1265 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
1266 return FALSE;
1267 }
1268
1269 SmlBool smlXmlAssemblerReserveStatus(SmlXmlAssembler *assm, unsigned int cmdRef, unsigned int msgRef, unsigned int cmdID, SmlError **error)
1270 {
1271 smlTrace(TRACE_ENTRY, "%s(%p, %i, %i, %i, %p)", __func__, assm, cmdRef, msgRef, cmdID, error);
1272 CHECK_ERROR_REF
1273 smlAssert(assm);
1274
1275 /* We first start a new writer that will write our status into a buffer */
1276 SmlXmlAssemblerStatus *res = smlTryMalloc0(sizeof(SmlXmlAssemblerStatus), error);
1277 if (!res)
1278 goto error;
1279 res->cmdRef = cmdRef;
1280 res->cmdID = cmdID;
1281 res->msgRef = msgRef;
1282
1283 /* Now we can append the buffer */
1284 if (cmdRef != 0)
1285 assm->statuses = g_list_append(assm->statuses, res);
1286 else
1287 assm->statuses = g_list_prepend(assm->statuses, res);
1288 assm->reserved_statuses++;
1289
1290 smlTrace(TRACE_EXIT, "%s", __func__);
1291 return TRUE;
1292
1293 error:
1294 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
1295 return FALSE;
1296 }
1297
1298 SmlBool smlXmlAssemblerAddStatus(SmlXmlAssembler *assm, SmlStatus *status, SmlError **error)
1299 {
1300 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, assm, status, error);
1301 CHECK_ERROR_REF
1302 smlAssert(assm);
1303 smlAssert(g_mutex_trylock(assm->mutex));
1304 smlAssert(status);
1305 SmlXmlAssemblerStatus *res = NULL;
1306
1307 smlTrace(TRACE_INTERNAL, "Adding status with cmdRef %i, msgRef %i, cmd %s", status->cmdRef, status->msgRef, smlCommandTypeToString(status->type, error));
1308 /* this happens if the status is damaged */
1309 if (*error)
1310 goto error;
1311
1312 if (!status->msgRef) {
1313 smlErrorSet(error, SML_ERROR_GENERIC, "No msgref set");
1314 goto error;
1315 }
1316
1317 if (status->type == SML_COMMAND_TYPE_UNKNOWN) {
1318 smlErrorSet(error, SML_ERROR_GENERIC, "No cmd set");
1319 goto error;
1320 }
1321
1322 /* Lets see if there already was a header before */
1323 if (!assm->header_buffer) {
1324 smlErrorSet(error, SML_ERROR_GENERIC, "Header not yet added");
1325 goto error;
1326 }
1327
1328 /* Get the reserved buffer */
1329 GList *s = NULL;
1330 for (s = assm->statuses; s; s = s->next) {
1331 res = s->data;
1332 if (res->cmdRef == status->cmdRef && res->msgRef == status->msgRef)
1333 break;
1334 res = NULL;
1335 }
1336
1337 if (!res) {
1338 smlErrorSet(error, SML_ERROR_GENERIC, "Status not reserved");
1339 goto error;
1340 }
1341
1342 if (!res->cmdID) {
1343 smlErrorSet(error, SML_ERROR_GENERIC, "No cmd ID set");
1344 goto error;
1345 }
1346
1347 if (res->buffer) {
1348 smlErrorSet(error, SML_ERROR_GENERIC, "Status already added");
1349 goto error;
1350 }
1351
1352 /* We first start a new writer that will write our status into a buffer */
1353 res->buffer = xmlBufferCreateSize(BUFFER_SIZE);
1354 if (!res->buffer) {
1355 smlErrorSet(error, SML_ERROR_GENERIC, "Unable to create new buffer");
1356 goto error;
1357 }
1358
1359 assm->writer = xmlNewTextWriterMemory(res->buffer, 0);
1360 if (!assm->writer) {
1361 smlErrorSet(error, SML_ERROR_GENERIC, "Unable to create new writer");
1362 goto error_free_buffer;
1363 }
1364
1365 /* Begin of Status */
1366 if (!_smlXmlAssemblerStartNode(assm, SML_ELEMENT_STATUS, error))
1367 goto error;
1368
1369 /* CmdID */
1370 if (!_smlXmlAssemblerAddID(assm, SML_ELEMENT_CMDID, res->cmdID, error))
1371 goto error;
1372
1373 /* MsgRef */
1374 if (!_smlXmlAssemblerAddID(assm, SML_ELEMENT_MSGREF, status->msgRef, error))
1375 goto error;
1376
1377 /* CmdRef */
1378 if (!_smlXmlAssemblerAddID(assm, SML_ELEMENT_CMDREF, res->cmdRef, error))
1379 goto error;
1380
1381 /* Cmd */
1382 const char *cmdname = smlCommandTypeToString(status->type, error);
1383 if (!cmdname)
1384 goto error;
1385 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_CMD, cmdname, error))
1386 goto error;
1387
1388 /* TargetRef */
1389 if (status->targetRef) {
1390 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_TARGETREF, status->targetRef->locURI, error))
1391 goto error;
1392 }
1393
1394 /* SourceRef */
1395 if (status->sourceRef) {
1396 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_SOURCEREF, status->sourceRef->locURI, error))
1397 goto error;
1398 }
1399
1400 /* Cred */
1401
1402 /* Chal */
1403 if (status->type == SML_COMMAND_TYPE_HEADER && status->chal)
1404 {
1405 if (!_smlXmlAssemblerStartNode(assm, SML_ELEMENT_CHAL, error))
1406 goto error;
1407
1408 if (!_smlXmlAssemblerStartNode(assm, SML_ELEMENT_META, error))
1409 goto error;
1410
1411 if (!_smlXmlAssemblerAddStringNS(assm, SML_ELEMENT_FORMAT, SML_NAMESPACE_METINF, SML_BASE64, error))
1412 goto error;
1413
1414 switch (status->chal->type) {
1415 case SML_AUTH_TYPE_BASIC:
1416 if (!_smlXmlAssemblerAddStringNS(assm, SML_ELEMENT_TYPE, SML_NAMESPACE_METINF, SML_AUTH_BASIC, error))
1417 goto error;
1418 break;
1419 case SML_AUTH_TYPE_MD5:
1420 if (!_smlXmlAssemblerAddStringNS(assm, SML_ELEMENT_TYPE, SML_NAMESPACE_METINF, SML_AUTH_MD5, error))
1421 goto error;
1422 if (status->chal->nonce_b64 &&
1423 !_smlXmlAssemblerAddStringNS(assm, SML_ELEMENT_NEXTNONCE, SML_NAMESPACE_METINF, status->chal->nonce_b64, error))
1424 goto error;
1425 break;
1426 default:
1427 smlErrorSet(error, SML_ERROR_GENERIC, "Unknown auth type");
1428 goto error;
1429 }
1430
1431 //META
1432 if (!_smlXmlAssemblerEndNode(assm, error))
1433 goto error;
1434
1435 //CHAL
1436 if (!_smlXmlAssemblerEndNode(assm, error))
1437 goto error;
1438 }
1439
1440 /* Data */
1441 if (status->data) {
1442 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_DATA, status->data, error))
1443 goto error;
1444 }
1445
1446 /* Item */
1447 if (status->type == SML_COMMAND_TYPE_ALERT && status->anchor)
1448 {
1449 if (!_smlXmlAssemblerStartNode(assm, SML_ELEMENT_ITEM, error))
1450 goto error;
1451
1452 if (!_smlXmlAssemblerStartNode(assm, SML_ELEMENT_DATA, error))
1453 goto error;
1454
1455 if (!smlAnchorAssemble(status->anchor, assm, error))
1456 goto error;
1457
1458 //DATA
1459 if (!_smlXmlAssemblerEndNode(assm, error))
1460 goto error;
1461
1462 //ITEM
1463 if (!_smlXmlAssemblerEndNode(assm, error))
1464 goto error;
1465 }
1466
1467 /* End of Status */
1468 if (!_smlXmlAssemblerEndNode(assm, error))
1469 goto error;
1470
1471 /* Now close the buffer and get the content */
1472 if (xmlTextWriterEndDocument(assm->writer) < 0) {
1473 smlErrorSet(error, SML_ERROR_GENERIC, "Unable to end writer");
1474 goto error_free_writer;
1475 }
1476
1477 xmlFreeTextWriter(assm->writer);
1478 assm->writer = NULL;
1479
1480 assm->added_statuses++;
1481
1482 g_mutex_unlock(assm->mutex);
1483 smlTrace(TRACE_EXIT, "%s", __func__);
1484 return TRUE;
1485
1486 error_free_writer:
1487 xmlFreeTextWriter(assm->writer);
1488 assm->writer = NULL;
1489 error_free_buffer:
1490 xmlBufferFree(res->buffer);
1491 res->buffer = NULL;
1492 error:
1493 g_mutex_unlock(assm->mutex);
1494 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
1495 return FALSE;
1496 }
1497
1498 SmlBool smlXmlAssemblerMissingStatus(SmlXmlAssembler *assm)
1499 {
1500 smlAssert(assm);
1501
1502 if (assm->reserved_statuses - assm->added_statuses > 0)
1503 return TRUE;
1504
1505 return FALSE;
1506 }
1507
1508 static void flush_list(GList *list)
1509 {
1510 GList *l = NULL;
1511 for (l = list; l; l = l->next) {
1512 SmlXmlAssemblerCommand *cmd = l->data;
1513
1514 if (cmd->nodeType != SML_ASSEMBLER_NODE_CLOSE && cmd->children)
1515 flush_list(cmd->children);
1516
1517 xmlBufferFree(cmd->buffer);
1518 smlSafeFree((gpointer *)&cmd);
1519 }
1520
1521 g_list_free(list);
1522 }
1523
1524 void smlXmlAssemblerFree(SmlXmlAssembler *assm)
1525 {
1526 smlTrace(TRACE_ENTRY, "%s(%p)", __func__, assm);
1527 smlAssert(assm);
1528
1529 if (assm->header_buffer) {
1530 xmlBufferFree(assm->header_buffer);
1531 assm->header_buffer = NULL;
1532 }
1533
1534 while (assm->statuses) {
1535 SmlXmlAssemblerStatus *status = assm->statuses->data;
1536
1537 if (status->buffer)
1538 xmlBufferFree(status->buffer);
1539
1540 smlSafeFree((gpointer *)&status);
1541 assm->statuses = g_list_delete_link(assm->statuses, assm->statuses);
1542 }
1543
1544 flush_list(assm->commands);
1545 flush_list(assm->last_commands);
1546
1547 g_mutex_free(assm->mutex);
1548 smlSafeFree((gpointer *)&assm);
1549
1550 smlTrace(TRACE_EXIT, "%s", __func__);
1551 }
1552
1553 /* This function returns the highest command id that is still in the
1554 * assembler after flushing which is: number of statuses + 1 */
1555 unsigned int smlXmlAssemblerFlush(SmlXmlAssembler *assm)
1556 {
1557 smlTrace(TRACE_ENTRY, "%s(%p)", __func__, assm);
1558 smlAssert(assm);
1559
1560 unsigned int newid = 1;
1561 SmlBool missing = FALSE;
1562
1563 /* Remove the statuses */
1564 GList *s = NULL;
1565 GList *s2 = g_list_copy(assm->statuses);
1566 for (s = s2; s; s = s->next) {
1567 SmlXmlAssemblerStatus *status = s->data;
1568 /* Only remove statuses that were added already */
1569 if (!status->buffer) {
1570 /* If the status was not yet added, we have to reset the command id.
1571 * We start with id #2 (since #1 will be the header reply) */
1572 /* FIXME: why should we reset a command id? */
1573 newid++;
1574 // status->cmdID = newid;
1575 missing = TRUE;
1576 } else if (!missing) {
1577 xmlBufferFree(status->buffer);
1578 assm->statuses = g_list_remove(assm->statuses, status);
1579 smlSafeFree((gpointer *)&status);
1580 assm->reserved_statuses--;
1581 assm->added_statuses--;
1582 }
1583 }
1584 g_list_free(s2);
1585
1586 /* Remove all commands that are complete
1587 * Perhaps more correct remove all commands from the last message.
1588 * The actual commands are cached to support error 407 handling.
1589 * (AUTHENTICATION_REQUIRED)
1590 */
1591 if (assm->last_commands)
1592 flush_list(assm->last_commands);
1593 assm->last_commands = assm->commands;
1594 assm->commands = NULL;
1595
1596 /* Reset LargeObject handling */
1597 assm->moreDataSet = FALSE;
1598
1599 smlTrace(TRACE_EXIT, "%s: %i", __func__, newid);
1600 return newid;
1601 }
1602
1603 SmlBool smlXmlAssemblerStart(SmlXmlAssembler *assm, SmlSession *session, SmlError **error)
1604 {
1605 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, assm, session, error);
1606 CHECK_ERROR_REF
1607 smlAssert(assm);
1608 smlAssert(g_mutex_trylock(assm->mutex));
1609 smlAssert(session);
1610
1611 assm->session = session;
1612
1613 g_mutex_unlock(assm->mutex);
1614 smlTrace(TRACE_EXIT, "%s", __func__);
1615 return TRUE;
1616 }
1617
1618
1619 SmlBool smlXmlAssemblerEnd(SmlXmlAssembler *assm, SmlError **error)
1620 {
1621 smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, assm, error);
1622 CHECK_ERROR_REF
1623 smlAssert(assm);
1624 smlAssert(g_mutex_trylock(assm->mutex));
1625
1626 //Close syncml
1627 if (!_smlXmlAssemblerEndNode(assm, error))
1628 goto error;
1629
1630 if (_smlXmlAssemblerEndNode(assm, NULL)) {
1631 smlErrorSet(error, SML_ERROR_GENERIC, "Extra node open");
1632 goto error;
1633 }
1634
1635 g_mutex_unlock(assm->mutex);
1636 smlTrace(TRACE_EXIT, "%s", __func__);
1637 return TRUE;
1638
1639 error:
1640 g_mutex_unlock(assm->mutex);
1641 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
1642 return FALSE;
1643 }
1644
1645 SmlBool smlXmlAssemblerAddChildren(SmlXmlAssembler *assm, GList *b, SmlError **error)
1646 {
1647 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, assm, b, error);
1648 CHECK_ERROR_REF
1649 smlAssert(assm);
1650 const char *opt = smlAssemblerGetOption(assm->assembler, "ONLY_REPLACE");
1651 SmlBool onlyReplace = (opt && atoi(opt)) ? TRUE : FALSE;
1652
1653 SmlXmlAssemblerCommand *cmd = NULL;
1654 const char *cmdname = NULL;
1655
1656 for (; b; b = b->next) {
1657 cmd = b->data;
1658 switch (cmd->nodeType) {
1659 case SML_ASSEMBLER_NODE_OPEN:
1660 /* Add the corresponding command opener */
1661
1662 if (cmd->cmdType == SML_COMMAND_TYPE_ADD && onlyReplace)
1663 cmdname = SML_ELEMENT_REPLACE;
1664 else {
1665 cmdname = smlCommandTypeToString(cmd->cmdType, error);
1666 if (!cmdname)
1667 goto error;
1668 }
1669 smlTrace(TRACE_INTERNAL, "opening node %s", cmdname);
1670
1671 if (!_smlXmlAssemblerStartNode(assm, cmdname, error))
1672 goto error;
1673
1674 int rc = xmlTextWriterWriteRawLen(assm->writer, xmlBufferContent(cmd->buffer), xmlBufferLength(cmd->buffer));
1675 if (rc < 0) {
1676 smlErrorSet(error, SML_ERROR_GENERIC, "Unable to write raw node data (%d).", rc);
1677 goto error;
1678 }
1679
1680 if (cmd->children) {
1681 if (!smlXmlAssemblerAddChildren(assm, cmd->children, error))
1682 goto error;
1683 }
1684
1685 smlTrace(TRACE_INTERNAL, "%s: closing node", __func__);
1686 if (!_smlXmlAssemblerEndNode(assm, error))
1687 goto error;
1688 break;
1689 case SML_ASSEMBLER_NODE_CLOSE:
1690 /*smlTrace(TRACE_INTERNAL, "%s: closing node". __func__);
1691 if (!_smlXmlAssemblerEndNode(assm, error))
1692 goto error;*/
1693 break;
1694 }
1695 }
1696
1697 smlTrace(TRACE_EXIT, "%s", __func__);
1698 return TRUE;
1699
1700 error:
1701 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
1702 return FALSE;
1703 }
1704
1705 SmlBool smlXmlAssemblerRunFull(SmlXmlAssembler *assm, char **data, unsigned int *size, SmlBool *end, SmlBool final, SmlBool check, unsigned int maxsize, SmlError **error)
1706 {
1707 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p, %p, %i, %i, %i, %p)", __func__, assm, data, size, end, final, check, maxsize, error);
1708 CHECK_ERROR_REF
1709 smlAssert(assm);
1710 smlAssert(g_mutex_trylock(assm->mutex));
1711 smlAssert(data);
1712 smlAssert(size);
1713 smlAssert(assm->session);
1714 unsigned int buffersize = 0;
1715
1716 /* Return an error if there is no header */
1717 if (!assm->header_buffer) {
1718 smlErrorSet(error, SML_ERROR_GENERIC, "No header available");
1719 goto error;
1720 }
1721
1722 /* Return an error if there is no status/command. Note that if
1723 * statuses have been reserved, at least the first status
1724 * must be added */
1725 if (check && !assm->statuses && !assm->commands) {
1726 smlErrorSet(error, SML_ERROR_GENERIC, "No status/command available");
1727 goto error;
1728 }
1729
1730 if (check && assm->statuses && final) {
1731 SmlXmlAssemblerStatus *status = assm->statuses->data;
1732 if (!status->buffer) {
1733 smlErrorSet(error, SML_ERROR_GENERIC, "Missing the first status with cmdRef %i", status->cmdRef);
1734 goto error;
1735 }
1736 }
1737
1738 /* Create the final buffer and writer */
1739 xmlBuffer *buffer = xmlBufferCreateSize(BUFFER_SIZE);
1740 if (!buffer) {
1741 smlErrorSet(error, SML_ERROR_GENERIC, "Unable to create new buffer");
1742 goto error;
1743 }
1744
1745 assm->writer = xmlNewTextWriterMemory(buffer, 0);
1746 if (!assm->writer) {
1747 smlErrorSet(error, SML_ERROR_GENERIC, "Unable to create new writer");
1748 goto error_free_buffer;
1749 }
1750
1751 /* Sync4j has a bug and cannot handle the default XML encoding.
1752 * The default XML encoding is UTF-8. So this default encoding
1753 * is explicitly added to support buggy XML parsers.
1754 */
1755 if (xmlTextWriterStartDocument(assm->writer, NULL, "UTF-8", NULL) < 0) {
1756 smlErrorSet(error, SML_ERROR_GENERIC, "Unable to create new writer");
1757 goto error_free_writer;
1758 }
1759
1760 /* Add the syncml start node */
1761 switch (assm->session->version) {
1762 case SML_VERSION_10:
1763 xmlTextWriterWriteRaw(assm->writer, (xmlChar *)"<!DOCTYPE SyncML PUBLIC \"-//SYNCML//DTD SyncML 1.0//EN\" \"http://www.syncml.org/docs/syncml_represent_v10_20001207.dtd\">");
1764 if (!_smlXmlAssemblerStartNodeNS(assm, SML_ELEMENT_SYNCML, SML_NAMESPACE_SYNCML10, error))
1765 goto error_free_writer;
1766 break;
1767 case SML_VERSION_11:
1768 xmlTextWriterWriteRaw(assm->writer, (xmlChar *)"<!DOCTYPE SyncML PUBLIC \"-//SYNCML//DTD SyncML 1.1//EN\" \"http://www.syncml.org/docs/syncml_represent_v11_20020213.dtd\">");
1769 if (!_smlXmlAssemblerStartNodeNS(assm, SML_ELEMENT_SYNCML, SML_NAMESPACE_SYNCML11, error))
1770 goto error_free_writer;
1771 break;
1772 case SML_VERSION_12:
1773 xmlTextWriterWriteRaw(assm->writer, (xmlChar *)"<!DOCTYPE SyncML PUBLIC \"-//SYNCML//DTD SyncML 1.2//EN\" \"http://www.openmobilealliance.org/tech/DTD/OMA-TS-SyncML_RepPro_DTD-V1_2.dtd\">");
1774 if (!_smlXmlAssemblerStartNodeNS(assm, SML_ELEMENT_SYNCML, SML_NAMESPACE_SYNCML12, error))
1775 goto error_free_writer;
1776 break;
1777 default:
1778 smlErrorSet(error, SML_ERROR_GENERIC, "Unknown version");
1779 goto error_free_writer;
1780 }
1781
1782 /* Add the header */
1783 int rc = xmlTextWriterWriteRawLen(assm->writer, xmlBufferContent(assm->header_buffer), xmlBufferLength(assm->header_buffer));
1784 if (rc < 0) {
1785 smlErrorSet(error, SML_ERROR_GENERIC, "Unable to write raw header data (%d).", rc);
1786 goto error_free_writer;
1787 }
1788
1789 /* Start the sync body */
1790 if (!_smlXmlAssemblerStartNode(assm, SML_ELEMENT_SYNCBODY, error))
1791 goto error_free_writer;
1792
1793 // FIXME: why do we need 20 extra bytes here?
1794 // FIXME: buffersize is never read !!!
1795 buffersize += 20 + xmlBufferLength(assm->header_buffer);
1796
1797 /* Add the statuses */
1798 GList *b = NULL;
1799 SmlBool missingstatus = FALSE;
1800 smlTrace(TRACE_INTERNAL, "%s: Now adding %i statuses",
1801 __func__, g_list_length(assm->statuses));
1802 for (b = assm->statuses; b; b = b->next) {
1803 SmlXmlAssemblerStatus *status = b->data;
1804 if (!status->buffer || xmlBufferLength(status->buffer) == 0) {
1805 if (status->cmdRef == 0 && check) {
1806 smlErrorSet(error, SML_ERROR_GENERIC, "Reserved status 0 has not been added");
1807 goto error_free_writer;
1808 }
1809 smlTrace(TRACE_INTERNAL, "%s: Reserved status %i is missing",
1810 __func__, status->cmdRef);
1811 missingstatus = TRUE;
1812 break;
1813 }
1814
1815 buffersize += xmlBufferLength(status->buffer);
1816 //if (maxsize && buffersize > maxsize)
1817 // break;
1818 rc = xmlTextWriterWriteRawLen(assm->writer, xmlBufferContent(status->buffer), xmlBufferLength(status->buffer));
1819 if (rc < 0) {
1820 smlErrorSet(error, SML_ERROR_GENERIC, "Unable to write raw status data (%d - %d of %d: %s).",
1821 rc, xmlBufferLength(status->buffer),
1822 buffersize, xmlBufferContent(status->buffer));
1823 goto error_free_writer;
1824 }
1825 }
1826
1827 /* We cannot have missing statuses when its final. And we cannot add commands */
1828 if (missingstatus && final && check) {
1829 smlErrorSet(error, SML_ERROR_GENERIC, "Reserved status has not been added");
1830 goto error_free_writer;
1831 }
1832
1833 /* Add the commands. Parent commands are added in the order they were added. */
1834 if (!smlXmlAssemblerAddChildren(assm, assm->commands, error))
1835 goto error_free_writer;
1836
1837 if (final) {
1838 smlTrace(TRACE_INTERNAL, "%s: setting final", __func__);
1839 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_FINAL, "", error))
1840 goto error_free_writer;
1841 }
1842
1843 /* Close syncbody */
1844 if (!_smlXmlAssemblerEndNode(assm, error))
1845 goto error_free_writer;
1846
1847 /* Close syncml */
1848 if (!_smlXmlAssemblerEndNode(assm, error))
1849 goto error_free_writer;
1850
1851 if (xmlTextWriterEndDocument(assm->writer) < 0) {
1852 smlErrorSet(error, SML_ERROR_GENERIC, "Unable to end writer");
1853 goto error;
1854 }
1855
1856
1857 xmlFreeTextWriter(assm->writer);
1858 assm->writer = NULL;
1859
1860 // the buffer was created with xmlBufferCreateSize
1861 // so we must free it via the libxml API and not via smlSafeCFree
1862 *size = xmlBufferLength(buffer);
1863 *data = g_strndup((const char *) xmlBufferContent(buffer), *size);
1864 xmlBufferFree(buffer);
1865 if (end) {
1866 if (final && !assm->commands)
1867 *end = TRUE;
1868 else
1869 *end = FALSE;
1870 }
1871 smlTrace(TRACE_INTERNAL, "%s: Message Assembled: %s",
1872 __func__, VA_STRING(*data));
1873
1874 g_mutex_unlock(assm->mutex);
1875 smlTrace(TRACE_EXIT, "%s", __func__);
1876 return TRUE;
1877
1878 error_free_writer:
1879 xmlFreeTextWriter(assm->writer);
1880 assm->writer = NULL;
1881 error_free_buffer:
1882 xmlBufferFree(buffer);
1883 error:
1884 g_mutex_unlock(assm->mutex);
1885 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
1886 return FALSE;
1887 }
1888
1889 static unsigned int calc_list(GList *list)
1890 {
1891 unsigned int size = 0;
1892
1893 for (; list; list = list->next) {
1894 SmlXmlAssemblerCommand *cmd = list->data;
1895 size += 15;
1896 if (cmd->nodeType != SML_ASSEMBLER_NODE_CLOSE) {
1897 size += xmlBufferLength(cmd->buffer);
1898 if (cmd->children)
1899 size += calc_list(cmd->children);
1900 }
1901 }
1902
1903 return size;
1904 }
1905
1906 SmlBool smlXmlAssemblerRun(SmlXmlAssembler *assm, char **data, unsigned int *size, SmlBool *end, SmlBool final, unsigned int maxsize, SmlError **error)
1907 {
1908 CHECK_ERROR_REF
1909 SmlBool ans = smlXmlAssemblerRunFull(assm, data, size, end, final, TRUE, maxsize, error);
1910
1911 if (ans)
1912 smlLog("sent-%i.xml", *data, *size);
1913 else
1914 smlTrace(TRACE_ERROR, "%s - %s", __func__, smlErrorPrint(error));
1915
1916 return ans;
1917 }
1918
1919 unsigned int smlXmlAssemblerCheckSize(SmlXmlAssembler *assm, SmlBool headeronly, SmlError **error)
1920 {
1921 CHECK_ERROR_REF
1922 smlAssert(assm);
1923 SmlXmlAssemblerStatus *status = NULL;
1924 unsigned int size = 0;
1925
1926 /* Add the size if the syncml tags etc */
1927 size += 20;
1928
1929 /* Add the size of the header */
1930 if (assm->header_buffer)
1931 size += xmlBufferLength(assm->header_buffer);
1932
1933 if (!headeronly) {
1934 /* Add the size of the status */
1935 GList *b = NULL;
1936 for (b = assm->statuses; b; b = b->next) {
1937 status = b->data;
1938 if (!status->buffer)
1939 break;
1940
1941 size += xmlBufferLength(status->buffer);
1942 }
1943
1944 /* Add the size of the commands */
1945 size += calc_list(assm->commands);
1946 }
1947
1948 return size;
1949 }
1950
1951 SmlBool smlXmlAssemblerNextCmdRef(SmlXmlAssembler *assm, unsigned int *cmdRef, unsigned int *msgRef)
1952 {
1953 smlAssert(assm);
1954 smlAssert(cmdRef);
1955 smlAssert(msgRef);
1956 SmlXmlAssemblerStatus *status = NULL;
1957
1958 GList *b = NULL;
1959 for (b = assm->statuses; b; b = b->next) {
1960 status = b->data;
1961 if (!status->buffer) {
1962 *cmdRef = status->cmdRef;
1963 *msgRef = status->msgRef;
1964 return TRUE;
1965 }
1966 }
1967
1968 return FALSE;
1969 }
1970
1978 SmlXmlAssembler *smlXmlAssemblerNew(SmlAssembler *assembler, SmlAssemblerFunctions *functions, SmlError **error)
1979 {
1980 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, assembler, functions, error);
1981 CHECK_ERROR_REF
1982
1983 SmlXmlAssembler *assm = smlTryMalloc0(sizeof(SmlXmlAssembler), error);
1984 if (!assm)
1985 goto error;
1986 assm->assembler = assembler;
1987 assm->mutex = g_mutex_new();
1988 if (!assm->mutex)
1989 goto error_mutex;
1990
1991 functions->start = (SmlAssemblerStartFunction)smlXmlAssemblerStart;
1992 functions->free = (SmlAssemblerFreeFunction)smlXmlAssemblerFree;
1993 functions->run = (SmlAssemblerRunFunction)smlXmlAssemblerRun;
1994 functions->end = (SmlAssemblerEndFunction)smlXmlAssemblerEnd;
1995 functions->add_header = (SmlAssemblerHeaderFunction)smlXmlAssemblerAddHeader;
1996 functions->start_cmd = (SmlAssemblerStartCommandFunction)smlXmlAssemblerStartCommand;
1997 functions->end_cmd = (SmlAssemblerEndCommandFunction)smlXmlAssemblerEndCommand;
1998 functions->rem_cmd = (SmlAssemblerRemCommandFunction)smlXmlAssemblerRemCommand;
1999 functions->add_status = (SmlAssemblerStatusFunction)smlXmlAssemblerAddStatus;
2000 functions->rem_status = (SmlAssemblerRemStatusFunction)smlXmlAssemblerRemStatus;
2001 functions->reserve_status = (SmlAssemblerReserveStatusFunction)smlXmlAssemblerReserveStatus;
2002 functions->missing_status = (SmlAssemblerStatusMissingFunction)smlXmlAssemblerMissingStatus;
2003 functions->check_size = (SmlAssemblerCheckFunction)smlXmlAssemblerCheckSize;
2004 functions->next_cmdref = (SmlAssemblerNextCmdRefFunction)smlXmlAssemblerNextCmdRef;
2005 functions->flush = (SmlAssemblerFlushFunction)smlXmlAssemblerFlush;
2006 functions->restore_cmds = (SmlAssemblerRestoreCommandsFunction)smlXmlAssemblerRestoreCommands;
2007
2008 smlTrace(TRACE_EXIT, "%s: %p", __func__, assm);
2009 return assm;
2010
2011 error_mutex:
2012 smlSafeFree((gpointer *)&assm);
2013 smlErrorSet(error, SML_ERROR_GENERIC, "%s - Cannot create new mutex.", __func__);
2014 error:
2015 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
2016 return NULL;
2017 }
2018
2019 static SmlBool _smlXmlDevInfDataStoreAssembleRxTx(SmlXmlAssembler *assm, const char *element, const char *cttype, const char *version, SmlError **error)
2020 {
2021 smlTrace(TRACE_ENTRY, "%s(%p, %s, %s, %s, %p)", __func__, assm, VA_STRING(element), VA_STRING(cttype), VA_STRING(version), error);
2022 CHECK_ERROR_REF
2023 smlAssert(assm);
2024 smlAssert(element);
2025 smlAssert(cttype);
2026
2027 if (!_smlXmlAssemblerStartNode(assm, element, error))
2028 goto error;
2029
2030 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_CTTYPE, cttype, error))
2031 goto error;
2032
2033 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_VERCT, version, error))
2034 goto error;
2035
2036 if (!_smlXmlAssemblerEndNode(assm, error))
2037 goto error;
2038
2039 smlTrace(TRACE_EXIT, "%s", __func__);
2040 return TRUE;
2041
2042 error:
2043 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
2044 return FALSE;
2045 }
2046
2047 static SmlBool _smlXmlDevInfDataStoreAssembleCTCap(
2048 SmlXmlAssembler *assm,
2049 const SmlDevInfCTCap *ctcap,
2050 SmlBool flat,
2051 SmlError **error)
2052 {
2053 smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, assm, ctcap, error);
2054 CHECK_ERROR_REF
2055 smlAssert(assm);
2056 smlAssert(ctcap);
2057
2058 if (!flat)
2059 {
2060 // start CTCap
2061 if (!_smlXmlAssemblerStartNode(assm, SML_ELEMENT_CTCAP, error))
2062 goto error;
2063 }
2064
2065 // add CTType
2066 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_CTTYPE, ctcap->ct->cttype, error))
2067 goto error;
2068
2069 // add VerCT
2070 // SyncML 1.0 and 1.1 does not support VerCT in CTCap
2071 // because this info is in the VERSION property.
2072 if (!flat)
2073 {
2074 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_VERCT, ctcap->ct->verct, error))
2075 goto error;
2076 }
2077
2078 // add properties
2079 GList *hprop = NULL;
2080 for (hprop = ctcap->properties; hprop; hprop = hprop->next)
2081 {
2082 SmlDevInfProperty *property = hprop->data;
2083
2084 if (!flat)
2085 {
2086 // add Property
2087 if (!_smlXmlAssemblerStartNode(assm, SML_ELEMENT_PROPERTY, error))
2088 goto error;
2089 }
2090
2091 // add PropName
2092 if (property->propName != NULL &&
2093 !_smlXmlAssemblerAddString(assm, SML_ELEMENT_PROPNAME, property->propName, error))
2094 goto error;
2095
2096 // add DataType
2097 if (property->dataType != NULL &&
2098 !_smlXmlAssemblerAddString(assm, SML_ELEMENT_DATATYPE, property->dataType, error))
2099 goto error;
2100
2101 // add MaxOccur
2102 if (property->maxOccur > 0 &&
2103 !_smlXmlAssemblerAddID(assm, SML_ELEMENT_MAXOCCUR, property->maxOccur, error))
2104 goto error;
2105
2106 // add MaxSize
2107 if (property->maxSize > 0) {
2108 /* There was a change of the element name in OMA DS DevInf 1.2. */
2109 if (flat) {
2110 if (!_smlXmlAssemblerAddID(
2111 assm,
2112 SML_ELEMENT_SIZE,
2113 property->maxSize,
2114 error))
2115 goto error;
2116 } else {
2117 if (!_smlXmlAssemblerAddID(
2118 assm,
2119 SML_ELEMENT_MAXSIZE,
2120 property->maxSize,
2121 error))
2122 goto error;
2123 }
2124 }
2125
2126 // add NoTruncate
2127 if (property->noTruncate)
2128 {
2129 if (!_smlXmlAssemblerStartNode(assm, SML_ELEMENT_NOTRUNCATE, error))
2130 goto error;
2131 if (!_smlXmlAssemblerEndNode(assm, error))
2132 goto error;
2133 }
2134
2135 // add DisplayName
2136 if (property->displayName != NULL &&
2137 !_smlXmlAssemblerAddString(assm, SML_ELEMENT_DISPLAYNAME, property->displayName, error))
2138 goto error;
2139
2140 // add values
2141 GList *hvalue = NULL;
2142 for (hvalue = property->valEnums; hvalue; hvalue = hvalue->next)
2143 {
2144 char *valEnum = hvalue->data;
2145
2146 // add ValEnum
2147 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_VALENUM, valEnum, error))
2148 goto error;
2149
2150 } // end values for loop
2151
2152 // add parameters
2153 GList *hparam = NULL;
2154 for (hparam = property->propParams; hparam; hparam = hparam->next)
2155 {
2156 SmlDevInfPropParam *param = hparam->data;
2157
2158 if (!flat)
2159 {
2160 // add PropParam
2161 if (!_smlXmlAssemblerStartNode(assm, SML_ELEMENT_PROPPARAM, error))
2162 goto error;
2163 }
2164
2165 // add ParamName
2166 if (param->paramName != NULL &&
2167 !_smlXmlAssemblerAddString(assm, SML_ELEMENT_PARAMNAME, param->paramName, error))
2168 goto error;
2169
2170 // add DataType
2171 if (param->dataType != NULL &&
2172 !_smlXmlAssemblerAddString(assm, SML_ELEMENT_DATATYPE, param->dataType, error))
2173 goto error;
2174
2175 // add DisplayName
2176 if (param->displayName != NULL &&
2177 !_smlXmlAssemblerAddString(assm, SML_ELEMENT_DISPLAYNAME, param->displayName, error))
2178 goto error;
2179
2180 // add values
2181 hvalue = NULL;
2182 for (hvalue = param->valEnums; hvalue; hvalue = hvalue->next)
2183 {
2184 char *valEnum = hvalue->data;
2185
2186 // add ValEnum
2187 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_VALENUM, valEnum, error))
2188 goto error;
2189
2190 } // end values for loop
2191
2192 if (!flat)
2193 {
2194 // end PropParam
2195 if (!_smlXmlAssemblerEndNode(assm, error))
2196 goto error;
2197 }
2198
2199 } // end params for loop
2200
2201 if (!flat)
2202 {
2203 // end Property
2204 if (!_smlXmlAssemblerEndNode(assm, error))
2205 goto error;
2206 }
2207
2208 } //end of ctcap->properties for loop
2209
2210 if (!flat)
2211 {
2212 // end CTCap
2213 if (!_smlXmlAssemblerEndNode(assm, error))
2214 goto error;
2215 }
2216
2217 smlTrace(TRACE_EXIT, "%s", __func__);
2218 return TRUE;
2219
2220 error:
2221 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
2222 return FALSE;
2223 }
2224
2225 static SmlBool _smlXmlDevInfDataStoreAssemble(
2226 SmlXmlAssembler *assm,
2227 SmlDevInfDataStore *datastore,
2228 SmlDevInf *devinf,
2229 SmlError **error)
2230 {
2231 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p, %p)", __func__, assm, datastore, devinf, error);
2232 CHECK_ERROR_REF
2233 smlAssert(datastore);
2234 smlAssert(assm);
2235
2236 GList *contentTypes = NULL;
2237
2238 if (!datastore->sourceref) {
2239 smlErrorSet(error, SML_ERROR_GENERIC, "Missing sourceref");
2240 goto error;
2241 }
2242
2243 if (!datastore->rxPrefContentType) {
2244 smlErrorSet(error, SML_ERROR_GENERIC, "Missing rx-pref");
2245 goto error;
2246 }
2247
2248 if (!datastore->txPrefContentType) {
2249 smlErrorSet(error, SML_ERROR_GENERIC, "Missing tx-pref");
2250 goto error;
2251 }
2252
2253 if (!datastore->synccap) {
2254 smlErrorSet(error, SML_ERROR_GENERIC, "No sync capabilities");
2255 goto error;
2256 }
2257
2258 // Datastore
2259 if (!_smlXmlAssemblerStartNode(assm, SML_ELEMENT_DATASTORE, error))
2260 goto error;
2261
2262 //SourceRef
2263 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_SOURCEREF, datastore->sourceref, error))
2264 goto error;
2265
2266 //displayname
2267 if (datastore->displayname) {
2268 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_DISPLAYNAME, datastore->displayname, error))
2269 goto error;
2270 }
2271
2272 //maxguidsize
2273 if (datastore->maxGUIDSize) {
2274 if (!_smlXmlAssemblerAddID(assm, SML_ELEMENT_MAXGUIDSIZE, datastore->maxGUIDSize, error))
2275 goto error;
2276 }
2277
2278 //rx-pref
2279 if (!_smlXmlDevInfDataStoreAssembleRxTx(assm, SML_ELEMENT_RXPREF, datastore->rxPrefContentType, datastore->rxPrefVersion, error))
2280 goto error;
2281 contentTypes = g_list_append(
2282 contentTypes,
2283 smlDevInfNewContentType(
2284 datastore->rxPrefContentType,
2285 datastore->rxPrefVersion, error));
2286
2287 //rx
2288 if (datastore->rx) {
2289 GList *hl;
2290 for (hl = datastore->rx; hl; hl = hl->next)
2291 {
2292 SmlDevInfContentType *ct = hl->data;
2293 if (!_smlXmlDevInfDataStoreAssembleRxTx(assm, SML_ELEMENT_RX, ct->cttype, ct->verct, error))
2294 goto error;
2295 contentTypes = g_list_append(
2296 contentTypes,
2297 smlDevInfNewContentType(ct->cttype, ct->verct, error));
2298 }
2299 }
2300
2301 //tx-pref
2302 if (!_smlXmlDevInfDataStoreAssembleRxTx(assm, SML_ELEMENT_TXPREF, datastore->txPrefContentType, datastore->txPrefVersion, error))
2303 goto error;
2304 contentTypes = g_list_append(
2305 contentTypes,
2306 smlDevInfNewContentType(
2307 datastore->txPrefContentType,
2308 datastore->txPrefVersion, error));
2309
2310 //tx
2311 if (datastore->tx) {
2312 GList *hl;
2313 for (hl = datastore->tx; hl; hl = hl->next)
2314 {
2315 SmlDevInfContentType *ct = hl->data;
2316 if (!_smlXmlDevInfDataStoreAssembleRxTx(assm, SML_ELEMENT_TX, ct->cttype, ct->verct, error))
2317 goto error;
2318 contentTypes = g_list_append(
2319 contentTypes,
2320 smlDevInfNewContentType(ct->cttype, ct->verct, error));
2321 }
2322 }
2323
2324 // CTCap (if SyncML version 1.2 device info)
2325 if (devinf->version >= SML_DEVINF_VERSION_12)
2326 {
2327 GList *hct = NULL;
2328 for (hct = contentTypes; hct; hct = hct->next) {
2329 SmlDevInfContentType *ct = hct->data;
2330 const SmlDevInfCTCap *ctcap = smlDevInfGetCTCap(devinf, ct);
2331 if (ctcap != NULL)
2332 {
2333 // we found a matching CTCap
2334 // so let's dump it
2335 if (!_smlXmlDevInfDataStoreAssembleCTCap(assm, ctcap, FALSE, error))
2336 goto error;
2337 } else {
2338 // we have a content type without CTCap
2339 // this is a real source of trouble
2340 // WARNING: should we fail on this issue?
2341 smlTrace(TRACE_INTERNAL, "%s: found a content type (%s %d) without CTCap",
2342 __func__, VA_STRING(ct->cttype), ct->verct);
2343 }
2344 } // end of contentTypes for loop
2345 } // end of SML_DEVINF_VERSION_12
2346
2347 // cleanup list of content types
2348 while(contentTypes)
2349 {
2350 SmlDevInfContentType *ct = contentTypes->data;
2351 contentTypes = g_list_remove(contentTypes, ct);
2352 smlDevInfFreeContentType(ct);
2353 }
2354
2355 //Dsmem
2356 if (datastore->maxmem || datastore->maxid) {
2357 //Dsmem
2358 if (!_smlXmlAssemblerStartNode(assm, SML_ELEMENT_DSMEM, error))
2359 goto error;
2360
2361 //shared
2362 if (datastore->sharedMem) {
2363 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_SHAREDMEM, "", error))
2364 goto error;
2365 }
2366
2367 //maxid
2368 if (datastore->maxid) {
2369 if (!_smlXmlAssemblerAddID(assm, SML_ELEMENT_MAXID, datastore->maxid, error))
2370 goto error;
2371 }
2372
2373 //maxmem
2374 if (datastore->maxmem) {
2375 if (!_smlXmlAssemblerAddID(assm, SML_ELEMENT_MAXMEM, datastore->maxmem, error))
2376 goto error;
2377 }
2378
2379 //DsMem
2380 if (!_smlXmlAssemblerEndNode(assm, error))
2381 goto error;
2382 }
2383
2384 //SyncCap
2385 if (!_smlXmlAssemblerStartNode(assm, SML_ELEMENT_SYNCCAP, error))
2386 goto error;
2387
2388 //SyncTypes
2389 if (smlDevInfDataStoreGetSyncCap(datastore, SML_DEVINF_SYNCTYPE_TWO_WAY)) {
2390 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_SYNCTYPE, "1", error))
2391 goto error;
2392 }
2393 if (smlDevInfDataStoreGetSyncCap(datastore, SML_DEVINF_SYNCTYPE_SLOW_SYNC)) {
2394 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_SYNCTYPE, "2", error))
2395 goto error;
2396 }
2397 if (smlDevInfDataStoreGetSyncCap(datastore, SML_DEVINF_SYNCTYPE_ONE_WAY_FROM_CLIENT)) {
2398 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_SYNCTYPE, "3", error))
2399 goto error;
2400 }
2401 if (smlDevInfDataStoreGetSyncCap(datastore, SML_DEVINF_SYNCTYPE_REFRESH_FROM_CLIENT)) {
2402 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_SYNCTYPE, "4", error))
2403 goto error;
2404 }
2405 if (smlDevInfDataStoreGetSyncCap(datastore, SML_DEVINF_SYNCTYPE_ONE_WAY_FROM_SERVER)) {
2406 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_SYNCTYPE, "5", error))
2407 goto error;
2408 }
2409 if (smlDevInfDataStoreGetSyncCap(datastore, SML_DEVINF_SYNCTYPE_REFRESH_FROM_SERVER)) {
2410 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_SYNCTYPE, "6", error))
2411 goto error;
2412 }
2413 if (smlDevInfDataStoreGetSyncCap(datastore, SML_DEVINF_SYNCTYPE_SERVER_ALERTED_SYNC)) {
2414 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_SYNCTYPE, "7", error))
2415 goto error;
2416 }
2417
2418 //SyncCap
2419 if (!_smlXmlAssemblerEndNode(assm, error))
2420 goto error;
2421
2422 //DataStore
2423 if (!_smlXmlAssemblerEndNode(assm, error))
2424 goto error;
2425
2426 smlTrace(TRACE_EXIT, "%s", __func__);
2427 return TRUE;
2428
2429 error:
2430 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
2431 return FALSE;
2432 }
2433
2434 SmlBool smlXmlDevInfAssemble(SmlDevInf *devinf, SmlDevInfVersion version, char **data, unsigned int *size, SmlError **error)
2435 {
2436 smlTrace(TRACE_ENTRY, "%s(%p, %i, %p, %p, %p)", __func__, devinf, version, data, size, error);
2437 CHECK_ERROR_REF
2438 smlAssert(devinf);
2439 smlAssert(data);
2440 smlAssert(size);
2441
2442 // sometime devinf->version is empty
2443 // both version fields should be identical
2444 smlTrace(TRACE_INTERNAL, "%s: devinf version: %i, version: %i", __func__, devinf->version, version);
2445 if (devinf->version == SML_DEVINF_VERSION_UNKNOWN)
2446 devinf->version = version;
2447 if (version == SML_DEVINF_VERSION_UNKNOWN)
2448 version = devinf->version;
2449 smlAssert(devinf->version == version);
2450
2451 SmlXmlAssembler *assm = smlTryMalloc0(sizeof(SmlXmlAssembler), error);
2452 if (!assm)
2453 goto error;
2454
2455 /* We first start a new parent writer that will write our command into a buffer */
2456 xmlBuffer *buffer = xmlBufferCreateSize(BUFFER_SIZE);
2457 if (!buffer) {
2458 smlErrorSet(error, SML_ERROR_GENERIC, "Unable to create new buffer");
2459 goto error_free_assm;
2460 }
2461
2462 assm->writer = xmlNewTextWriterMemory(buffer, 0);
2463 if (!assm->writer) {
2464 smlErrorSet(error, SML_ERROR_GENERIC, "Unable to create new writer");
2465 goto error_free_buffer;
2466 }
2467
2468 //Devinf
2469 if (!_smlXmlAssemblerStartNodeNS(assm, SML_ELEMENT_DEVINF, SML_NAMESPACE_DEVINF, error))
2470 goto error_free_writer;
2471
2472 //Verdtd
2473 switch (version) {
2474 case SML_DEVINF_VERSION_12:
2475 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_VERDTD, "1.2", error))
2476 goto error_free_writer;
2477 break;
2478 case SML_DEVINF_VERSION_11:
2479 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_VERDTD, "1.1", error))
2480 goto error_free_writer;
2481 break;
2482 case SML_DEVINF_VERSION_10:
2483 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_VERDTD, "1.0", error))
2484 goto error_free_writer;
2485 break;
2486 case SML_DEVINF_VERSION_UNKNOWN:
2487 smlErrorSet(error, SML_ERROR_GENERIC, "Unknown devinf version");
2488 goto error_free_writer;
2489 break;
2490 }
2491
2492 //Man
2493 if (devinf->manufacturer) {
2494 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_MAN, devinf->manufacturer, error))
2495 goto error_free_writer;
2496 }
2497
2498 //Mod
2499 if (devinf->model) {
2500 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_MOD, devinf->model, error))
2501 goto error_free_writer;
2502 }
2503
2504 //OEM
2505 if (devinf->oem) {
2506 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_OEM, devinf->oem, error))
2507 goto error_free_writer;
2508 }
2509
2510 //FwV
2511 if (devinf->firmwareVersion) {
2512 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_FWV, devinf->firmwareVersion, error))
2513 goto error_free_writer;
2514 }
2515
2516 //SwV
2517 if (devinf->softwareVersion) {
2518 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_SWV, devinf->softwareVersion, error))
2519 goto error_free_writer;
2520 }
2521
2522 //HwV
2523 if (devinf->hardwareVersion) {
2524 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_HWV, devinf->hardwareVersion, error))
2525 goto error_free_writer;
2526 }
2527
2528 //DevID
2529 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_DEVID, devinf->devid, error))
2530 goto error_free_writer;
2531
2532 //Devtyp
2533 const char *devtype = smlDevInfDevTypeToString(devinf->devtyp, error);
2534 if (!devtype)
2535 goto error_free_writer;
2536
2537 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_DEVTYPE, devtype, error))
2538 goto error_free_writer;
2539
2540 //UTC (>= 1.1)
2541 if (devinf->supportsUTC && version != SML_DEVINF_VERSION_10) {
2542 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_UTC, "", error))
2543 goto error_free_writer;
2544 }
2545
2546 //Large objs (>= 1.1)
2547 if (devinf->supportsLargeObjs && version != SML_DEVINF_VERSION_10) {
2548 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_SUPPORTLARGEOBJS, "", error))
2549 goto error_free_writer;
2550 }
2551
2552 //Number of changes (>= 1.1)
2553 if (devinf->supportsNumberOfChanges && version != SML_DEVINF_VERSION_10) {
2554 if (!_smlXmlAssemblerAddString(assm, SML_ELEMENT_SUPPORTNUMBEROFCHANGES, "", error))
2555 goto error_free_writer;
2556 }
2557
2558 //Add the datastores
2559 GList *d = NULL;
2560 for (d = devinf->datastores; d; d = d->next) {
2561 SmlDevInfDataStore *datastore = d->data;
2562 if (!_smlXmlDevInfDataStoreAssemble(assm, datastore, devinf, error))
2563 goto error_free_writer;
2564 }
2565
2566 // CTCap (only for SyncML 1.0 and 1.1)
2567 if (
2568 devinf->version < SML_DEVINF_VERSION_12 &&
2569 devinf->ctcaps) {
2570 if (!_smlXmlAssemblerStartNode(assm, SML_ELEMENT_CTCAP, error))
2571 goto error_free_writer;
2572
2573 for (d = devinf->ctcaps; d; d = d->next) {
2574 SmlDevInfCTCap *ctcap = d->data;
2575
2576 if (!_smlXmlDevInfDataStoreAssembleCTCap(assm, ctcap, TRUE, error))
2577 goto error_free_writer;
2578 }
2579
2580 if (!_smlXmlAssemblerEndNode(assm, error))
2581 goto error_free_writer;
2582 }
2583
2584 //Devinf
2585 if (!_smlXmlAssemblerEndNode(assm, error))
2586 goto error_free_writer;
2587
2588 /* Now close the buffer */
2589 if (xmlTextWriterEndDocument(assm->writer) < 0) {
2590 smlErrorSet(error, SML_ERROR_GENERIC, "Unable to end writer");
2591 goto error_free_writer;
2592 }
2593
2594 xmlFreeTextWriter(assm->writer);
2595 assm->writer = NULL;
2596
2597 *size = xmlBufferLength(buffer);
2598 *data = g_strndup((const char *) xmlBufferContent(buffer), *size);
2599
2600 xmlBufferFree(buffer);
2601
2602 smlSafeFree((gpointer *)&assm);
2603
2604 smlTrace(TRACE_INTERNAL, "Message Assembled: %s", *data);
2605
2606 smlTrace(TRACE_EXIT, "%s", __func__);
2607 return TRUE;
2608
2609 error_free_writer:
2610 xmlFreeTextWriter(assm->writer);
2611 assm->writer = NULL;
2612 error_free_buffer:
2613 xmlBufferFree(buffer);
2614 error_free_assm:
2615 smlSafeFree((gpointer *)&assm);
2616 error:
2617 g_warning("%s: %s", __func__, smlErrorPrint(error));
2618 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
2619 return FALSE;
2620 }
2621
2622 void smlXmlAssemblerRestoreCommands(SmlXmlAssembler *assm)
2623 {
2624 smlTrace(TRACE_ENTRY, "%s", __func__);
2625 smlAssert(assm->commands == NULL);
2626
2627 assm->commands = assm->last_commands;
2628 assm->last_commands = NULL;
2629
2630 smlTrace(TRACE_EXIT, "%s", __func__);
2631 }
2632