source: contrib/z-push/streamer.php @ 4898

Revision 4898, 9.9 KB checked in by thiagoaos, 13 years ago (diff)

Ticket #2180 - Adicionado código fonte completo do zpush

Line 
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************************************************/
20include_once("zpushdtd.php");
21
22define('STREAMER_VAR', 1);
23define('STREAMER_ARRAY', 2);
24define('STREAMER_TYPE', 3);
25
26define('STREAMER_TYPE_DATE', 1);
27define('STREAMER_TYPE_HEX', 2);
28define('STREAMER_TYPE_DATE_DASHES', 3);
29define('STREAMER_TYPE_MAPI_STREAM', 4);
30
31
32class Streamer {
33    var $_mapping;
34
35    var $content;
36    var $attributes;
37    var $flags;
38
39    function Streamer($mapping) {
40        $this->_mapping = $mapping;
41        $this->flags = false;
42    }
43
44    // Decodes the WBXML from $input until we reach the same depth level of WBXML. This
45    // means that if there are multiple objects at this level, then only the first is decoded
46    // SubOjects are auto-instantiated and decoded using the same functionality
47    function decode(&$decoder) {
48        while(1) {
49            $entity = $decoder->getElement();
50
51            if($entity[EN_TYPE] == EN_TYPE_STARTTAG) {
52                if(! ($entity[EN_FLAGS] & EN_FLAGS_CONTENT)) {
53                    $map = $this->_mapping[$entity[EN_TAG]];
54                    if(!isset($map[STREAMER_TYPE])) {
55                        $this->$map[STREAMER_VAR] = "";
56                    } else if ($map[STREAMER_TYPE] == STREAMER_TYPE_DATE || $map[STREAMER_TYPE] == STREAMER_TYPE_DATE_DASHES ) {
57                        $this->$map[STREAMER_VAR] = "";
58                    }
59                    continue;
60                }
61                // Found a start tag
62                if(!isset($this->_mapping[$entity[EN_TAG]])) {
63                    // This tag shouldn't be here, abort
64                    debug("Tag " . $entity[EN_TAG] . " unexpected in type XML type " . get_class($this));
65                    return false;
66                } else {
67                    $map = $this->_mapping[$entity[EN_TAG]];
68
69                    // Handle an array
70                    if(isset($map[STREAMER_ARRAY])) {
71                        while(1) {
72                            if(!$decoder->getElementStartTag($map[STREAMER_ARRAY]))
73                                break;
74                            if(isset($map[STREAMER_TYPE])) {
75                                $decoded = new $map[STREAMER_TYPE];
76                                $decoded->decode($decoder);
77                            } else {
78                                $decoded = $decoder->getElementContent();
79                            }
80
81                            if(!isset($this->$map[STREAMER_VAR]))
82                                $this->$map[STREAMER_VAR] = array($decoded);
83                            else
84                                array_push($this->$map[STREAMER_VAR], $decoded);
85
86                            if(!$decoder->getElementEndTag())
87                                return false;
88                        }
89                        if(!$decoder->getElementEndTag())
90                            return false;
91                    } else { // Handle single value
92                        if(isset($map[STREAMER_TYPE])) {
93                            // Complex type, decode recursively
94                            if($map[STREAMER_TYPE] == STREAMER_TYPE_DATE || $map[STREAMER_TYPE] == STREAMER_TYPE_DATE_DASHES) {
95                                $decoded = $this->parseDate($decoder->getElementContent());
96                                if(!$decoder->getElementEndTag())
97                                    return false;
98                            } else if($map[STREAMER_TYPE] == STREAMER_TYPE_HEX) {
99                                $decoded = hex2bin($decoder->getElementContent());
100                                if(!$decoder->getElementEndTag())
101                                    return false;
102                            } else {
103                                $subdecoder = new $map[STREAMER_TYPE]();
104                                if($subdecoder->decode($decoder) === false)
105                                    return false;
106
107                                $decoded = $subdecoder;
108
109                                if(!$decoder->getElementEndTag()) {
110                                    debug("No end tag for " . $entity[EN_TAG]);
111                                    return false;
112                                }
113                            }
114                        } else {
115                            // Simple type, just get content
116                            $decoded = $decoder->getElementContent();
117
118                            if($decoded === false) {
119                                debug("Unable to get content for " . $entity[EN_TAG]);
120                                return false;
121                            }
122
123                            if(!$decoder->getElementEndTag()) {
124                                debug("Unable to get end tag for " . $entity[EN_TAG]);
125                                return false;
126                            }
127                        }
128                        // $decoded now contains data object (or string)
129                        $this->$map[STREAMER_VAR] = $decoded;
130                    }
131                }
132            }
133            else if($entity[EN_TYPE] == EN_TYPE_ENDTAG) {
134                $decoder->ungetElement($entity);
135                break;
136            }
137            else {
138                debug("Unexpected content in type");
139                break;
140            }
141        }
142    }
143
144    // Encodes this object and any subobjects - output is ordered according to mapping
145    function encode(&$encoder) {
146        $attributes = isset($this->attributes) ? $this->attributes : array();
147
148        foreach($this->_mapping as $tag => $map) {
149            if(isset($this->$map[STREAMER_VAR])) {
150                // Variable is available
151                if(is_object($this->$map[STREAMER_VAR])) {
152                    // Subobjects can do their own encoding
153                    $encoder->startTag($tag);
154                    $this->$map[STREAMER_VAR]->encode($encoder);
155                    $encoder->endTag();
156                } else if(isset($map[STREAMER_ARRAY])) {
157                    // Array of objects
158                    $encoder->startTag($tag); // Outputs array container (eg Attachments)
159                    foreach ($this->$map[STREAMER_VAR] as $element) {
160                        if(is_object($element)) {
161                            $encoder->startTag($map[STREAMER_ARRAY]); // Outputs object container (eg Attachment)
162                            $element->encode($encoder);
163                            $encoder->endTag();
164                        } else {
165                            if(strlen($element) == 0)
166                                  // Do not output empty items. Not sure if we should output an empty tag with $encoder->startTag($map[STREAMER_ARRAY], false, true);
167                                  ;
168                            else {
169                                $encoder->startTag($map[STREAMER_ARRAY]);
170                                $encoder->content($element);
171                                $encoder->endTag();
172                            }
173                        }
174                    }
175                    $encoder->endTag();
176                } else {
177                    // Simple type
178                    if(strlen($this->$map[STREAMER_VAR]) == 0) {
179                          // Do not output empty items. See above: $encoder->startTag($tag, false, true);
180                        continue;
181                    } else
182                        $encoder->startTag($tag);
183
184                    if(isset($map[STREAMER_TYPE]) && ($map[STREAMER_TYPE] == STREAMER_TYPE_DATE || $map[STREAMER_TYPE] == STREAMER_TYPE_DATE_DASHES)) {
185                        if($this->$map[STREAMER_VAR] != 0) // don't output 1-1-1970
186                            $encoder->content($this->formatDate($this->$map[STREAMER_VAR], $map[STREAMER_TYPE]));
187                    } else if(isset($map[STREAMER_TYPE]) && $map[STREAMER_TYPE] == STREAMER_TYPE_HEX) {
188                        $encoder->content(strtoupper(bin2hex($this->$map[STREAMER_VAR])));
189                    } else if(isset($map[STREAMER_TYPE]) && $map[STREAMER_TYPE] == STREAMER_TYPE_MAPI_STREAM) {
190                        $encoder->content($this->$map[STREAMER_VAR]);
191                    } else {
192                        $encoder->content($this->$map[STREAMER_VAR]);
193                    }
194                    $encoder->endTag();
195                }
196            }
197        }
198        // Output our own content
199        if(isset($this->content))
200            $encoder->content($this->content);
201
202    }
203
204
205
206    // Oh yeah. This is beautiful. Exchange outputs date fields differently in calendar items
207    // and emails. We could just always send one or the other, but unfortunately nokia's 'Mail for
208    // exchange' depends on this quirk. So we have to send a different date type depending on where
209    // it's used. Sigh.
210    function formatDate($ts, $type) {
211        if($type == STREAMER_TYPE_DATE)
212            return gmstrftime("%Y%m%dT%H%M%SZ", $ts);
213        else if($type == STREAMER_TYPE_DATE_DASHES)
214            return gmstrftime("%Y-%m-%dT%H:%M:%S.000Z", $ts);
215    }
216
217    function parseDate($ts) {
218        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)) {
219            if ($matches[1] >= 2038){
220                $matches[1] = 2038;
221                $matches[2] = 1;
222                $matches[3] = 18;
223                $matches[4] = $matches[5] = $matches[6] = 0;
224            }
225            return gmmktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
226        }
227        return 0;
228    }
229};
230
231?>
Note: See TracBrowser for help on using the repository browser.