1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21:
22: class Horde_SyncMl_XmlOutput
23: {
24: 25: 26:
27: protected $_msg_CmdID;
28:
29: 30: 31: 32:
33: public $output;
34:
35: protected $_uri;
36:
37: 38: 39: 40:
41: public function getOutput()
42: {
43: return $this->output->getOutput();
44: }
45:
46: 47: 48: 49:
50: public function getOutputSize()
51: {
52: return $this->output->getOutputSize();
53: }
54:
55: 56: 57:
58: public function isWBXML()
59: {
60: return is_a($this->output, 'Horde_Xml_Wbxml_Encoder');
61: }
62:
63: public function &singleton()
64: {
65: static $instance;
66: if (!isset($instance)) {
67: $instance = new Horde_SyncMl_XmlOutput();
68: }
69: return $instance;
70: }
71:
72: public function init(&$theoutputhandler)
73: {
74: $this->output = $theoutputhandler;
75: $this->_msg_CmdID = 1;
76:
77: }
78:
79: 80: 81: 82: 83: 84: 85: 86: 87:
88: public function ($respURI)
89: {
90: $state = $GLOBALS['backend']->state;
91:
92: $this->_uriMeta = $state->uriMeta;
93:
94: $this->output->startElement($this->_uri, 'SyncHdr');
95:
96: $this->output->startElement($this->_uri, 'VerDTD');
97: $chars = $state->getVerDTD();
98: $this->output->characters($chars);
99: $this->output->endElement($this->_uri, 'VerDTD');
100:
101: $this->output->startElement($this->_uri, 'VerProto');
102: $chars = $state->getProtocolName();
103: $this->output->characters($chars);
104: $this->output->endElement($this->_uri, 'VerProto');
105:
106: $this->output->startElement($this->_uri, 'SessionID');
107: $this->output->characters($state->sessionID);
108: $this->output->endElement($this->_uri, 'SessionID');
109:
110: $this->output->startElement($this->_uri, 'MsgID');
111: $this->output->characters($state->messageID);
112: $this->output->endElement($this->_uri, 'MsgID');
113:
114: $this->output->startElement($this->_uri, 'Target');
115: $this->output->startElement($this->_uri, 'LocURI');
116:
117: $this->output->characters($state->sourceURI);
118: $this->output->endElement($this->_uri, 'LocURI');
119: if ($state->user) {
120: $this->output->startElement($this->_uri, 'LocName');
121: $this->output->characters($state->user);
122: $this->output->endElement($this->_uri, 'LocName');
123: }
124: $this->output->endElement($this->_uri, 'Target');
125:
126: $this->output->startElement($this->_uri, 'Source');
127: $this->output->startElement($this->_uri, 'LocURI');
128:
129: $this->output->characters($state->targetURI);
130: $this->output->endElement($this->_uri, 'LocURI');
131: $this->output->endElement($this->_uri, 'Source');
132:
133: if ($respURI) {
134: $this->output->startElement($this->_uri, 'RespURI');
135: $this->output->characters($respURI);
136: $this->output->endElement($this->_uri, 'RespURI');
137: }
138:
139:
140: $this->output->startElement($this->_uri, 'Meta');
141:
142:
143:
144: $this->output->startElement($this->_uriMeta, 'MaxMsgSize');
145: $chars = Horde_SyncMl::SERVER_MAXMSGSIZE;
146: $this->output->characters($chars);
147: $this->output->endElement($this->_uriMeta, 'MaxMsgSize');
148:
149:
150:
151: if ($state->version > 0) {
152: $this->output->startElement($this->_uriMeta, 'MaxObjSize');
153: $this->output->characters(Horde_SyncMl::SERVER_MAXOBJSIZE);
154: $this->output->endElement($this->_uriMeta, 'MaxObjSize');
155: }
156: $this->output->endElement($this->_uri, 'Meta');
157:
158: $this->output->endElement($this->_uri, 'SyncHdr');
159: }
160:
161: public function outputInit()
162: {
163: $this->_uri = $GLOBALS['backend']->state->getURI();
164:
165: $this->output->startElement($this->_uri, 'SyncML', array());
166: }
167:
168: public function outputBodyStart()
169: {
170: $this->output->startElement($this->_uri, 'SyncBody', array());
171: }
172:
173: public function outputFinal()
174: {
175: $this->output->startElement($this->_uri, 'Final', array());
176: $this->output->endElement($this->_uri, 'Final');
177: }
178:
179: public function outputEnd()
180: {
181: $this->output->endElement($this->_uri, 'SyncBody', array());
182: $this->output->endElement($this->_uri, 'SyncML', array());
183: }
184:
185:
186: public function outputStatus($cmdRef, $cmd, $data,
187: $targetRef = '', $sourceRef = '',
188: $syncAnchorNext = '',
189: $syncAnchorLast = '')
190: {
191: $state = $GLOBALS['backend']->state;
192: $uriMeta = $state->uriMeta;
193:
194: $this->output->startElement($this->_uri, 'Status');
195: $this->_outputCmdID();
196:
197: $this->output->startElement($this->_uri, 'MsgRef');
198: $chars = $state->messageID;
199: $this->output->characters($chars);
200: $this->output->endElement($this->_uri, 'MsgRef');
201:
202: $this->output->startElement($this->_uri, 'CmdRef');
203: $chars = $cmdRef;
204: $this->output->characters($chars);
205: $this->output->endElement($this->_uri, 'CmdRef');
206:
207: $this->output->startElement($this->_uri, 'Cmd');
208: $chars = $cmd;
209: $this->output->characters($chars);
210: $this->output->endElement($this->_uri, 'Cmd');
211:
212: if (!empty($targetRef)) {
213: $this->output->startElement($this->_uri, 'TargetRef');
214: $this->output->characters($targetRef);
215: $this->output->endElement($this->_uri, 'TargetRef');
216: }
217:
218: if (!empty($sourceRef)) {
219: $this->output->startElement($this->_uri, 'SourceRef');
220: $this->output->characters($sourceRef);
221: $this->output->endElement($this->_uri, 'SourceRef');
222: }
223:
224:
225:
226: if ($cmd == 'SyncHdr' && !$state->authenticated) {
227:
228:
229: $data = $data == Horde_SyncMl::RESPONSE_CREDENTIALS_MISSING
230: ? Horde_SyncMl::RESPONSE_CREDENTIALS_MISSING
231: : Horde_SyncMl::RESPONSE_INVALID_CREDENTIALS;
232:
233: $this->output->startElement($this->_uri, 'Chal');
234: $this->output->startElement($this->_uri, 'Meta');
235:
236: $this->output->startElement($uriMeta, 'Type');
237: $this->output->characters('syncml:auth-basic');
238: $this->output->endElement($uriMeta, 'Type');
239:
240: $this->output->startElement($uriMeta, 'Format');
241: $this->output->characters('b64');
242: $this->output->endElement($uriMeta, 'Format');
243:
244: $this->output->endElement($this->_uri, 'Meta');
245: $this->output->endElement($this->_uri, 'Chal');
246:
247: }
248:
249: $this->output->startElement($this->_uri, 'Data');
250: $this->output->characters($data);
251: $this->output->endElement($this->_uri, 'Data');
252:
253: if (!empty($syncAnchorNext) || !empty($syncAnchorNLast)) {
254: $this->output->startElement($this->_uri, 'Item');
255: $this->output->startElement($this->_uri, 'Data');
256:
257: $this->output->startElement($uriMeta, 'Anchor');
258:
259: if (!empty($syncAnchorLast)) {
260: $this->output->startElement($uriMeta, 'Last');
261: $this->output->characters($syncAnchorLast);
262: $this->output->endElement($uriMeta, 'Last');
263: }
264:
265: if (!empty($syncAnchorNext)) {
266: $this->output->startElement($uriMeta, 'Next');
267: $this->output->characters($syncAnchorNext);
268: $this->output->endElement($uriMeta, 'Next');
269: }
270:
271: $this->output->endElement($uriMeta, 'Anchor');
272:
273: $this->output->endElement($this->_uri, 'Data');
274: $this->output->endElement($this->_uri, 'Item');
275: }
276:
277: $this->output->endElement($this->_uri, 'Status');
278:
279: }
280:
281: public function outputDevInf($cmdRef)
282: {
283: $state = $GLOBALS['backend']->state;
284: $uriMeta = $state->uriMeta;
285: $uriDevInf = $state->uriDevInf;
286:
287: $this->output->startElement($this->_uri, 'Results');
288: $this->_outputCmdID();
289:
290: $this->output->startElement($this->_uri, 'MsgRef');
291: $chars = $state->messageID;
292: $this->output->characters($chars);
293: $this->output->endElement($this->_uri, 'MsgRef');
294:
295: $this->output->startElement($this->_uri, 'CmdRef');
296: $chars = $cmdRef;
297: $this->output->characters($chars);
298: $this->output->endElement($this->_uri, 'CmdRef');
299:
300: $this->output->startElement($this->_uri, 'Meta');
301: $this->output->startElement($uriMeta, 'Type');
302: if ($state->wbxml) {
303: $this->output->characters(Horde_SyncMl::MIME_SYNCML_DEVICE_INFO_WBXML);
304: } else {
305: $this->output->characters(Horde_SyncMl::MIME_SYNCML_DEVICE_INFO_XML);
306: }
307:
308: $this->output->endElement($uriMeta, 'Type');
309: $this->output->endElement($this->_uri, 'Meta');
310:
311: $this->output->startElement($this->_uri, 'Item');
312: $this->output->startElement($this->_uri, 'Source');
313: $this->output->startElement($this->_uri, 'LocURI');
314: $this->output->characters($state->getDevInfURI());
315: $this->output->endElement($this->_uri, 'LocURI');
316: $this->output->endElement($this->_uri, 'Source');
317:
318: $this->output->startElement($this->_uri, 'Data');
319:
320: 321: 322:
323: $devinfoutput = $this->output->createSubHandler();
324:
325: $devinfoutput->startElement($uriDevInf , 'DevInf');
326: $devinfoutput->startElement($uriDevInf , 'VerDTD');
327: $devinfoutput->characters($state->getVerDTD());
328: $devinfoutput->endElement($uriDevInf , 'VerDTD');
329: $devinfoutput->startElement($uriDevInf , 'Man');
330: $devinfoutput->characters('The Horde Project (http://www.horde.org/)');
331: $devinfoutput->endElement($uriDevInf , 'Man');
332: $devinfoutput->startElement($uriDevInf , 'DevID');
333: $devinfoutput->characters(isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'localhost');
334: $devinfoutput->endElement($uriDevInf , 'DevID');
335: $devinfoutput->startElement($uriDevInf , 'DevTyp');
336: $devinfoutput->characters('server');
337: $devinfoutput->endElement($uriDevInf , 'DevTyp');
338:
339: if ($state->version > 0) {
340: $devinfoutput->startElement($uriDevInf , 'SupportLargeObjs');
341: $devinfoutput->endElement($uriDevInf , 'SupportLargeObjs');
342:
343: $devinfoutput->startElement($uriDevInf , 'SupportNumberOfChanges');
344: $devinfoutput->endElement($uriDevInf , 'SupportNumberOfChanges');
345: }
346: $this->_writeDataStore('notes', 'text/plain', '1.0', $devinfoutput);
347: $this->_writeDataStore('contacts', 'text/directory', '3.0',
348: $devinfoutput, array('text/x-vcard' => '2.1'));
349: $this->_writeDataStore('tasks', 'text/calendar', '2.0', $devinfoutput,
350: array('text/x-vcalendar' => '1.0'));
351: $this->_writeDataStore('calendar', 'text/calendar', '2.0',
352: $devinfoutput,
353: array('text/x-vcalendar' => '1.0'));
354: $devinfoutput->endElement($uriDevInf , 'DevInf');
355:
356: $this->output->opaque($devinfoutput->getOutput());
357: $this->output->endElement($this->_uri, 'Data');
358: $this->output->endElement($this->_uri, 'Item');
359: $this->output->endElement($this->_uri, 'Results');
360: }
361:
362: 363: 364: 365: 366: 367: 368: 369: 370: 371: 372: 373: 374: 375:
376: protected function _writeDataStore($sourceref, $mimetype, $version, &$output,
377: $additionaltypes = array())
378: {
379: $uriDevInf = $GLOBALS['backend']->state->uriDevInf;
380:
381: $output->startElement($uriDevInf , 'DataStore');
382: $output->startElement($uriDevInf , 'SourceRef');
383: $output->characters($sourceref);
384: $output->endElement($uriDevInf , 'SourceRef');
385:
386: $output->startElement($uriDevInf , 'Rx-Pref');
387: $output->startElement($uriDevInf , 'CTType');
388: $output->characters($mimetype);
389: $output->endElement($uriDevInf , 'CTType');
390: $output->startElement($uriDevInf , 'VerCT');
391: $output->characters($version);
392: $output->endElement($uriDevInf , 'VerCT');
393: $output->endElement($uriDevInf , 'Rx-Pref');
394:
395: foreach ($additionaltypes as $ct => $ctver){
396: $output->startElement($uriDevInf , 'Rx');
397: $output->startElement($uriDevInf , 'CTType');
398: $output->characters($ct);
399: $output->endElement($uriDevInf , 'CTType');
400: $output->startElement($uriDevInf , 'VerCT');
401: $output->characters($ctver);
402: $output->endElement($uriDevInf , 'VerCT');
403: $output->endElement($uriDevInf , 'Rx');
404: }
405:
406: $output->startElement($uriDevInf , 'Tx-Pref');
407: $output->startElement($uriDevInf , 'CTType');
408: $output->characters($mimetype);
409: $output->endElement($uriDevInf , 'CTType');
410: $output->startElement($uriDevInf , 'VerCT');
411: $output->characters($version);
412: $output->endElement($uriDevInf , 'VerCT');
413: $output->endElement($uriDevInf , 'Tx-Pref');
414:
415: foreach ($additionaltypes as $ct => $ctver){
416: $output->startElement($uriDevInf , 'Tx');
417: $output->startElement($uriDevInf , 'CTType');
418: $output->characters($ct);
419: $output->endElement($uriDevInf , 'CTType');
420: $output->startElement($uriDevInf , 'VerCT');
421: $output->characters($ctver);
422: $output->endElement($uriDevInf , 'VerCT');
423: $output->endElement($uriDevInf , 'Tx');
424: }
425:
426: $output->startElement($uriDevInf , 'SyncCap');
427:
428:
429: for ($i = 1; $i <= 6; ++$i) {
430: $output->startElement($uriDevInf , 'SyncType');
431: $output->characters($i);
432: $output->endElement($uriDevInf , 'SyncType');
433: }
434: $output->endElement($uriDevInf , 'SyncCap');
435: $output->endElement($uriDevInf , 'DataStore');
436: }
437:
438: public function outputAlert($alertCode, $clientDB = '', $serverDB = '', $lastAnchor = '', $nextAnchor = '')
439: {
440: $uriMeta = $GLOBALS['backend']->state->uriMeta;
441:
442: $this->output->startElement($this->_uri, 'Alert');
443: $this->_outputCmdID();
444:
445: $this->output->startElement($this->_uri, 'Data');
446: $chars = $alertCode;
447: $this->output->characters($chars);
448: $this->output->endElement($this->_uri, 'Data');
449:
450: $this->output->startElement($this->_uri, 'Item');
451:
452: if (!empty($clientDB)) {
453: $this->output->startElement($this->_uri, 'Target');
454: $this->output->startElement($this->_uri, 'LocURI');
455: $this->output->characters($clientDB);
456: $this->output->endElement($this->_uri, 'LocURI');
457: $this->output->endElement($this->_uri, 'Target');
458: }
459:
460: if (!empty($serverDB)) {
461: $this->output->startElement($this->_uri, 'Source');
462: $this->output->startElement($this->_uri, 'LocURI');
463: $this->output->characters($serverDB);
464: $this->output->endElement($this->_uri, 'LocURI');
465: $this->output->endElement($this->_uri, 'Source');
466: }
467:
468: $this->output->startElement($this->_uri, 'Meta');
469:
470: $this->output->startElement($uriMeta, 'Anchor');
471:
472: $this->output->startElement($uriMeta, 'Last');
473: $this->output->characters($lastAnchor);
474: $this->output->endElement($uriMeta, 'Last');
475:
476: $this->output->startElement($uriMeta, 'Next');
477: $this->output->characters($nextAnchor);
478: $this->output->endElement($uriMeta, 'Next');
479:
480: $this->output->endElement($uriMeta, 'Anchor');
481:
482:
483:
484: if ($GLOBALS['backend']->state->version > 0) {
485: $this->output->startElement($uriMeta, 'MaxObjSize');
486: $this->output->characters(Horde_SyncMl::SERVER_MAXOBJSIZE);
487: $this->output->endElement($uriMeta, 'MaxObjSize');
488: }
489: $this->output->endElement($this->_uri, 'Meta');
490:
491: $this->output->endElement($this->_uri, 'Item');
492: $this->output->endElement($this->_uri, 'Alert');
493:
494: }
495:
496:
497: public function outputGetDevInf()
498: {
499: $state = $GLOBALS['backend']->state;
500: $uriMeta = $state->uriMeta;
501:
502: $this->output->startElement($this->_uri, 'Get');
503: $this->_outputCmdID();
504:
505: $this->output->startElement($this->_uri, 'Meta');
506: $this->output->startElement($uriMeta, 'Type');
507: if ($state->wbxml) {
508: $chars = Horde_SyncMl::MIME_SYNCML_DEVICE_INFO_WBXML;
509: } else {
510: $chars = Horde_SyncMl::MIME_SYNCML_DEVICE_INFO_XML;
511: }
512: $this->output->characters($chars);
513: $this->output->endElement($uriMeta, 'Type');
514: $this->output->endElement($this->_uri, 'Meta');
515:
516: $this->output->startElement($this->_uri, 'Item');
517: $this->output->startElement($this->_uri, 'Target');
518: $this->output->startElement($this->_uri, 'LocURI');
519: $this->output->characters($state->getDevInfURI());
520: $this->output->endElement($this->_uri, 'LocURI');
521: $this->output->endElement($this->_uri, 'Target');
522: $this->output->endElement($this->_uri, 'Item');
523:
524: $this->output->endElement($this->_uri, 'Get');
525: }
526:
527: 528: 529: 530: 531: 532: 533: 534: 535: 536: 537: 538:
539: public function outputSyncCommand($command, $content = null, $contentType = null,
540: $encodingType = null, $cuid = null, $suid = null)
541: {
542: $uriMeta = $GLOBALS['backend']->state->uriMeta;
543:
544: $this->output->startElement($this->_uri, $command);
545: $this->_outputCmdID();
546:
547: if (isset($contentType)) {
548: $this->output->startElement($this->_uri, 'Meta');
549: $this->output->startElement($uriMeta, 'Type');
550: $this->output->characters($contentType);
551: $this->output->endElement($uriMeta, 'Type');
552: $this->output->endElement($this->_uri, 'Meta');
553: }
554:
555: if (isset($content) || isset($cuid) || isset($suid)) {
556: $this->output->startElement($this->_uri, 'Item');
557: if ($suid != null) {
558: $this->output->startElement($this->_uri, 'Source');
559: $this->output->startElement($this->_uri, 'LocURI');
560: $this->output->characters($suid);
561: $this->output->endElement($this->_uri, 'LocURI');
562: $this->output->endElement($this->_uri, 'Source');
563: }
564:
565: if ($cuid != null) {
566: $this->output->startElement($this->_uri, 'Target');
567: $this->output->startElement($this->_uri, 'LocURI');
568: $this->output->characters($cuid);
569: $this->output->endElement($this->_uri, 'LocURI');
570: $this->output->endElement($this->_uri, 'Target');
571: }
572:
573: if (!empty($encodingType)) {
574: $this->output->startElement($this->_uri, 'Meta');
575: $this->output->startElement($uriMeta, 'Format');
576: $this->output->characters($encodingType);
577: $this->output->endElement($uriMeta, 'Format');
578: $this->output->endElement($this->_uri, 'Meta');
579: }
580: if (isset($content)) {
581: $this->output->startElement($this->_uri, 'Data');
582: if($this->isWBXML()) {
583: $this->output->characters($content);
584: } else {
585: $device = $GLOBALS['backend']->state->getDevice();
586: if ($device->useCdataTag()) {
587:
588:
589: $this->output->opaque('<![CDATA[' . $content . ']]>');
590: } else {
591: $this->output->characters($content);
592: }
593: }
594: $this->output->endElement($this->_uri, 'Data');
595: }
596: $this->output->endElement($this->_uri, 'Item');
597: }
598:
599: $this->output->endElement($this->_uri, $command);
600:
601: return $this->_msg_CmdID - 1;
602: }
603:
604: public function outputSyncStart($clientLocURI, $serverLocURI, $numberOfChanges = null)
605: {
606: $this->output->startElement($this->_uri, 'Sync');
607: $this->_outputCmdID();
608:
609: $this->output->startElement($this->_uri, 'Target');
610: $this->output->startElement($this->_uri, 'LocURI');
611: $this->output->characters($clientLocURI);
612: $this->output->endElement($this->_uri, 'LocURI');
613: $this->output->endElement($this->_uri, 'Target');
614:
615: $this->output->startElement($this->_uri, 'Source');
616: $this->output->startElement($this->_uri, 'LocURI');
617: $this->output->characters($serverLocURI);
618: $this->output->endElement($this->_uri, 'LocURI');
619: $this->output->endElement($this->_uri, 'Source');
620:
621: if (is_int($numberOfChanges)) {
622: $this->output->startElement($this->_uri, 'NumberOfChanges');
623: $this->output->characters($numberOfChanges);
624: $this->output->endElement($this->_uri, 'NumberOfChanges');
625: }
626:
627: }
628:
629: public function outputSyncEnd()
630: {
631: $this->output->endElement($this->_uri, 'Sync');
632: }
633:
634:
635:
636:
637: protected function _outputCmdID()
638: {
639: $this->output->startElement($this->_uri, 'CmdID');
640: $this->output->characters($this->_msg_CmdID);
641: $this->_msg_CmdID++;
642: $this->output->endElement($this->_uri, 'CmdID');
643: }
644:
645: 646: 647:
648: protected function _singleEle($tag, $str, $uri = null)
649: {
650: if (empty($uri)) {
651: $uri = $this->_uri;
652: }
653: $this->output->startElement($uri, $tag);
654: $this->output->characters($str);
655: $this->output->endElement($uri, $tag);
656: }
657: }
658: