"Fossies" - the Fresh Open Source Software Archive 
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) PHP source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "streamer.php" see the
Fossies "Dox" file reference documentation.
1 <?php
2 /***********************************************
3 * File : streamer.php
4 * Project : Z-Push
5 * Descr : This file handles streaming of
6 * WBXML objects. It must be
7 * subclassed so the internals of
8 * the object can be specified via
9 * $mapping. Basically we set/read
10 * the object variables of the
11 * subclass according to the mappings
12 *
13 *
14 * Created : 01.10.2007
15 *
16 * � Zarafa Deutschland GmbH, www.zarafaserver.de
17 * This file is distributed under GPL v2.
18 * Consult LICENSE file for details
19 ************************************************/
20 include_once("zpushdtd.php");
21
22 define('STREAMER_VAR', 1);
23 define('STREAMER_ARRAY', 2);
24 define('STREAMER_TYPE', 3);
25
26 define('STREAMER_TYPE_DATE', 1);
27 define('STREAMER_TYPE_HEX', 2);
28 define('STREAMER_TYPE_DATE_DASHES', 3);
29 define('STREAMER_TYPE_MAPI_STREAM', 4);
30
31
32 class Streamer {
33 var $_mapping;
34
35 var $content;
36 var $attributes;
37 var $flags;
38 var $_setread;
39 var $_setchange;
40 var $_setflag;
41
42 function Streamer($mapping) {
43 $this->_mapping = $mapping;
44 $this->flags = false;
45 $this->_setflag = false;
46 $this->_setchange = false;
47 $this->_setread = false;
48 $this->_setcategories = false;
49 }
50
51 // Decodes the WBXML from $input until we reach the same depth level of WBXML. This
52 // means that if there are multiple objects at this level, then only the first is decoded
53 // SubOjects are auto-instantiated and decoded using the same functionality
54 function decode(&$decoder) {
55
56 // START HACK dw2412
57 // We need this just for decoding items sent by HTC Android Devices (HTC DESIRE Z - maybe others!) the right way...
58 switch (get_class($this)) {
59 case "SyncAppointment" :
60 if (!isset($this->_mapping[SYNC_POOMCAL_BODY]))
61 $this->_mapping += array(
62 SYNC_POOMCAL_BODY => array (STREAMER_VAR => "body"),
63 SYNC_POOMCAL_BODYTRUNCATED => array (STREAMER_VAR => "bodytruncated"),
64 SYNC_POOMCAL_RTF => array (STREAMER_VAR => "rtf"),
65 );
66 break;
67 case "SyncContact" :
68 if (!isset($this->_mapping[SYNC_POOMCONTACTS_BODY]))
69 $this->_mapping += array(
70 SYNC_POOMCONTACTS_RTF => array (STREAMER_VAR => "rtf"),
71 SYNC_POOMCONTACTS_BODY => array (STREAMER_VAR => "body"),
72 SYNC_POOMCONTACTS_BODYSIZE => array (STREAMER_VAR => "bodysize"),
73 SYNC_POOMCONTACTS_BODYTRUNCATED => array (STREAMER_VAR => "bodytruncated"),
74 );
75 break;
76 }
77 // END HACK dw2412
78
79 while(1) {
80 $entity = $decoder->getElement();
81 if (isset($entity[EN_TAG])) {
82 switch ($entity[EN_TAG]) {
83 case "POOMMAIL:Read" :
84 $this->_setread=true; break;
85 case "POOMMAIL:Flag" :
86 $this->_setflag=true; break;
87 case "POOMMAIL:Categories" :
88 $this->_setcategories=true; break;
89 default :
90 $this->_setflag=false;
91 $this->_setread=false;
92 $this->_setcategories=false;
93 $this->_setchange=true;
94 };
95 };
96
97 if($entity[EN_TYPE] == EN_TYPE_STARTTAG) {
98 if(! ($entity[EN_FLAGS] & EN_FLAGS_CONTENT) && (isset($entity[EN_TAG]) && $entity[EN_TAG] != '' && isset($this->_mapping[$entity[EN_TAG]]))) {
99 $map = $this->_mapping[$entity[EN_TAG]];
100 if(!isset($map[STREAMER_TYPE])) {
101 $this->$map[STREAMER_VAR] = "";
102 } else if ($map[STREAMER_TYPE] == STREAMER_TYPE_DATE || $map[STREAMER_TYPE] == STREAMER_TYPE_DATE_DASHES ) {
103 $this->$map[STREAMER_VAR] = "";
104 } else if ($map[STREAMER_TYPE] == "SyncPoommailFlag") { // added dw2412 to support empty flag = flag to delete
105 $this->poommailflag = new SyncPoommailFlag();
106 $this->poommailflag->flagstatus="";
107 }
108 continue;
109 } else if (! ($entity[EN_FLAGS] & EN_FLAGS_CONTENT) && (!isset($entity[EN_TAG]) || $entity[EN_TAG] == '' || !isset($this->_mapping[$entity[EN_TAG]])))
110 debugLog("Streamer::DEBUGDEBUGDEBUG:".print_r($entity,true));
111 // Found a start tag
112 if(!isset($this->_mapping[$entity[EN_TAG]])) {
113 // This tag shouldn't be here, abort
114 debugLog("Tag " . $entity[EN_TAG] . " unexpected in type XML type " . get_class($this));
115 return false;
116 } else {
117 $map = $this->_mapping[$entity[EN_TAG]];
118
119 // Handle an array
120 if(isset($map[STREAMER_ARRAY])) {
121 while(1) {
122 if(!$decoder->getElementStartTag($map[STREAMER_ARRAY]))
123 break;
124 if(isset($map[STREAMER_TYPE])) {
125 $decoded = new $map[STREAMER_TYPE];
126 $decoded->decode($decoder);
127 } else {
128 $decoded = $decoder->getElementContent();
129 }
130
131 if(!isset($this->$map[STREAMER_VAR]))
132 $this->$map[STREAMER_VAR] = array($decoded);
133 else
134 array_push($this->$map[STREAMER_VAR], $decoded);
135
136 if(!$decoder->getElementEndTag())
137 return false;
138 }
139 if(!$decoder->getElementEndTag())
140 return false;
141 } else { // Handle single value
142 if(isset($map[STREAMER_TYPE])) {
143 // Complex type, decode recursively
144 if($map[STREAMER_TYPE] == STREAMER_TYPE_DATE || $map[STREAMER_TYPE] == STREAMER_TYPE_DATE_DASHES) {
145 $decoded = $this->parseDate($decoder->getElementContent());
146 if(!$decoder->getElementEndTag())
147 return false;
148 } else if($map[STREAMER_TYPE] == STREAMER_TYPE_HEX) {
149 $decoded = hex2bin($decoder->getElementContent());
150 if(!$decoder->getElementEndTag())
151 return false;
152 } else {
153 $subdecoder = new $map[STREAMER_TYPE]();
154 if($subdecoder->decode($decoder) === false)
155 return false;
156
157 $decoded = $subdecoder;
158
159 if(!$decoder->getElementEndTag()) {
160 debugLog("No end tag for " . $entity[EN_TAG]);
161 return false;
162 }
163 }
164 } else {
165 // Simple type, just get content
166 $decoded = $decoder->getElementContent();
167
168 if($decoded === false) {
169 // debug("Unable to get content for " . $entity[EN_TAG]);
170 // return false;
171 // the tag is declared to have content, but no content is available.
172 // set an empty content
173 $decoded = "";
174 }
175
176 if(!$decoder->getElementEndTag()) {
177 debugLog("Unable to get end tag for " . $entity[EN_TAG]);
178 return false;
179 }
180 }
181 // $decoded now contains data object (or string)
182 $this->$map[STREAMER_VAR] = $decoded;
183 }
184 }
185 }
186 else if($entity[EN_TYPE] == EN_TYPE_ENDTAG) {
187 $decoder->ungetElement($entity);
188 break;
189 }
190 else {
191 debugLog("Unexpected content in type");
192 break;
193 }
194 }
195 }
196
197 // Encodes this object and any subobjects - output is ordered according to mapping
198 function encode(&$encoder) {
199 $attributes = isset($this->attributes) ? $this->attributes : array();
200
201 foreach($this->_mapping as $tag => $map) {
202 if(isset($this->$map[STREAMER_VAR])) {
203 // Variable is available
204 if(is_object($this->$map[STREAMER_VAR])) {
205 // Subobjects can do their own encoding
206 $encoder->startTag($tag);
207 $this->$map[STREAMER_VAR]->encode($encoder);
208 $encoder->endTag();
209 } else if(isset($map[STREAMER_ARRAY])) {
210 // Array of objects
211 $encoder->startTag($tag); // Outputs array container (eg Attachments)
212 foreach ($this->$map[STREAMER_VAR] as $element) {
213 if(is_object($element)) {
214 $encoder->startTag($map[STREAMER_ARRAY]); // Outputs object container (eg Attachment)
215 $element->encode($encoder);
216 $encoder->endTag();
217 } else {
218 if(strlen($element) == 0)
219 // Do not output empty items. Not sure if we should output an empty tag with $encoder->startTag($map[STREAMER_ARRAY], false, true);
220 ;
221 else {
222 $encoder->startTag($map[STREAMER_ARRAY]);
223 $encoder->content($element);
224 $encoder->endTag();
225 }
226 }
227 }
228 $encoder->endTag();
229 } else {
230 // Simple type
231 if(strlen($this->$map[STREAMER_VAR]) == 0) {
232 // Do not output empty items. See above: $encoder->startTag($tag, false, true);
233 continue;
234 } else if ($encoder->_multipart == true &&
235 ($tag == SYNC_AIRSYNCBASE_DATA ||
236 $tag == SYNC_AIRSYNCBASE_ATTACHMENT ||
237 $tag == SYNC_ITEMOPERATIONS_DATA)) { // START ADDED dw2412 to support mulitpart output
238 $encoder->_bodyparts[] = $this->$map[STREAMER_VAR];
239 $encoder->startTag(SYNC_ITEMOPERATIONS_PART);
240 $encoder->content("".(sizeof($encoder->_bodyparts)-1)."");
241 $encoder->endTag();
242 continue; // END ADDED dw2412 to support mulitpart output
243 } else if ($encoder->_multipart == false &&
244 ($tag == SYNC_ITEMOPERATIONS_DATA)) { // START ADDED dw2412 to support mulitpart output
245 $encoder->startTag($tag);
246 $encoder->content(base64_encode($this->$map[STREAMER_VAR]));
247 $encoder->endTag();
248 continue; // END ADDED dw2412 to support mulitpart output
249 } else
250 $encoder->startTag($tag);
251
252 if(isset($map[STREAMER_TYPE]) && ($map[STREAMER_TYPE] == STREAMER_TYPE_DATE || $map[STREAMER_TYPE] == STREAMER_TYPE_DATE_DASHES)) {
253 if($this->$map[STREAMER_VAR] != 0) // don't output 1-1-1970
254 $encoder->content($this->formatDate($this->$map[STREAMER_VAR], $map[STREAMER_TYPE]));
255 } else if(isset($map[STREAMER_TYPE]) && $map[STREAMER_TYPE] == STREAMER_TYPE_HEX) {
256 $encoder->content(strtoupper(bin2hex($this->$map[STREAMER_VAR])));
257 } else if(isset($map[STREAMER_TYPE]) && $map[STREAMER_TYPE] == STREAMER_TYPE_MAPI_STREAM) {
258 $encoder->content($this->$map[STREAMER_VAR]);
259 } else if ($tag == SYNC_POOMMAIL2_CONVERSATIONINDEX ||
260 $tag == SYNC_POOMMAIL2_CONVERSATIONID) {
261 $encoder->contentopaque($this->$map[STREAMER_VAR]);
262 } else {
263 $encoder->content($this->$map[STREAMER_VAR]);
264 }
265 $encoder->endTag();
266 }
267 }
268 }
269 // Output our own content
270 if(isset($this->content))
271 $encoder->content($this->content);
272
273 }
274
275
276
277 // Oh yeah. This is beautiful. Exchange outputs date fields differently in calendar items
278 // and emails. We could just always send one or the other, but unfortunately nokia's 'Mail for
279 // exchange' depends on this quirk. So we have to send a different date type depending on where
280 // it's used. Sigh.
281 function formatDate($ts, $type) {
282 if($type == STREAMER_TYPE_DATE)
283 return gmstrftime("%Y%m%dT%H%M%SZ", $ts);
284 else if($type == STREAMER_TYPE_DATE_DASHES)
285 return gmstrftime("%Y-%m-%dT%H:%M:%S.000Z", $ts);
286 }
287
288 function parseDate($ts) {
289 if(preg_match("/(\d{4})[^0-9]*(\d{2})[^0-9]*(\d{2})T(\d{2})[^0-9]*(\d{2})[^0-9]*(\d{2})(.\d+)?Z/", $ts, $matches)) {
290 if ($matches[1] >= 2038){
291 $matches[1] = 2038;
292 $matches[2] = 1;
293 $matches[3] = 18;
294 $matches[4] = $matches[5] = $matches[6] = 0;
295 }
296 return gmmktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
297 } else if (preg_match("/(\d{4})[^0-9]*(\d{2})[^0-9]*(\d{2})/", $ts, $matches)) { // Fixes SAMSUNG Date Problem. Samsung send in Contacts dates only the date without time information... unfortunately...
298 if ($matches[1] >= 2038){
299 $matches[1] = 2038;
300 $matches[2] = 1;
301 $matches[3] = 18;
302 }
303 $matches[4] = $matches[5] = $matches[6] = 0;
304 return gmmktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
305 }
306 return 0;
307 }
308 };
309
310 ?>