1: <?php
2: /**
3: * Parser for the Outlook web access XML format.
4: *
5: * PHP version 5
6: *
7: * @category Kolab
8: * @package Kolab_FreeBusy
9: * @author Mathieu Parent <math.parent@gmail.com>
10: * @author Gunnar Wrobel <wrobel@pardus.de>
11: * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
12: * @link http://pear.horde.org/index.php?package=Kolab_FreeBusy
13: */
14:
15: /**
16: * Parser for the Outlook web access XML format.
17: *
18: * Copyright 2009-2012 Horde LLC (http://www.horde.org/)
19: * Copyright 2011 Kolab Systems AG
20: *
21: * See the enclosed file COPYING for license information (LGPL). If you did not
22: * receive this file, see
23: * http://www.horde.org/licenses/lgpl21.
24: *
25: * @category Kolab
26: * @package Kolab_FreeBusy
27: * @author Mathieu Parent <math.parent@gmail.com>
28: * @author Gunnar Wrobel <wrobel@pardus.de>
29: * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
30: * @link http://pear.horde.org/index.php?package=Kolab_FreeBusy
31: */
32: class Horde_Kolab_FreeBusy_Freebusy_Helper_Owa
33: {
34: /** OWA status codes */
35: const FREE = 0;
36: const TENTATIVE = 1;
37: const BUSY = 2;
38: const OUTOFOFFICE = 3;
39:
40: /**
41: * The XML document this driver works with.
42: *
43: * @var DOMDocument
44: */
45: private $_document;
46:
47: /**
48: * Constructor
49: *
50: * @param string|resource $input The input data.
51: *
52: * @throws Horde_Kolab_FreeBusy_Exception If the input is invalid.
53: */
54: public function __construct($input)
55: {
56: if (is_resource($input)) {
57: rewind($input);
58: $input = stream_get_contents($input);
59: }
60: $this->_document = new DOMDocument('1.0', 'UTF-8');
61: $this->_document->preserveWhiteSpace = false;
62: $this->_document->formatOutput = true;
63: $result = @$this->_document->loadXML($input);
64: if (!$result || empty($this->_document->documentElement)) {
65: throw new Horde_Kolab_FreeBusy_Exception('Invalid OWA input!');
66: }
67: }
68:
69: /**
70: * Return the XML document.
71: *
72: * @return string The complete XML document.
73: */
74: public function __toString()
75: {
76: return $this->_document->saveXML();
77: }
78:
79: /**
80: * Convert the free/busy data from the XML to an array.
81: *
82: * @param Horde_Date $start The start of the requested free/busy data.
83: * @param Horde_Date $end The end of the requested free/busy data.
84: * @param int $interval The interval of the data.
85: *
86: * @return array The data array representing the XML data.
87: */
88: public function convert($start, $end, $interval)
89: {
90: $noderoot = $this->_document->documentElement;
91: if (empty($noderoot) || empty($noderoot->childNodes)) {
92: throw new Horde_Kolab_FreeBusy_Exception('Invalid OWA input!');
93: }
94:
95: $children = $noderoot->childNodes;
96: if ($children->length != 1 || $children->item(0)->tagName != 'a:recipients') {
97: throw new Horde_Kolab_FreeBusy_Exception('Invalid OWA input!');
98: }
99:
100: $items = array();
101:
102: $nodes = $children->item(0)->childNodes;
103: for ($i = 0; $i < $nodes->length; $i++) {
104: $node = $nodes->item($i);
105: if ($node->tagName != 'a:item') {
106: continue;
107: }
108: $values = $node->childNodes;
109: $item = array();
110: for ($j = 0; $j < $values->length; $j++) {
111: $item[$values->item($j)->tagName] = $values->item($j)->textContent;
112: }
113: $items[] = $item;
114: }
115:
116: $object = array();
117: $object['start-date'] = $start;
118: $object['end-date'] = $end;
119:
120: foreach($items as $n => $item) {
121: if(!empty($item['a:fbdata']) && !empty($item['a:email'])) {
122: $fbdata = $item['a:fbdata'] . self::FREE;
123: $prev = '0';
124: $count = 0;
125: $start_date = $start;
126: $fbparsed = array();
127: for($i = 0; $i < strlen($fbdata) ; $i++) {
128: if($fbdata[$i] === $prev) {
129: $count++;
130: continue;
131: } else {
132: if($count) {
133: $end_date = $start_date->add(
134: $count * $interval * 60
135: );
136: if($prev != self::FREE) {
137: $fbparsed[] = array(
138: 'start-date' => $start_date,
139: 'end-date' => $end_date,
140: 'show-time-as' => $this->_stateAsString(
141: $prev
142: )
143: );
144: }
145: $start_date = $end_date;
146: }
147: $count = 1;
148: $prev = $fbdata[$i];
149: }
150: }
151: $object[$item['a:email']] = $fbparsed;
152: }
153: }
154:
155: return $object;
156: }
157:
158: /**
159: * Return state value, based on state code
160: *
161: * @param string $code State code.
162: *
163: * @return string State string
164: */
165: private function _stateAsString($code)
166: {
167: switch($code) {
168: case self::FREE:
169: return 'free';
170: case self::TENTATIVE:
171: return 'tentative';
172: case self::BUSY:
173: return 'busy';
174: case self::OUTOFOFFICE:
175: return 'outofoffice';
176: default:
177: return 'unknown';
178: }
179: }
180:
181: }