source: trunk/zpush/backend/zarafa/mapi/mapi.util.php @ 7589

Revision 7589, 13.6 KB checked in by douglas, 11 years ago (diff)

Ticket #3209 - Integrar módulo de sincronização Z-push ao Expresso

Line 
1<?php
2/*
3 * Copyright 2005 - 2012  Zarafa B.V.
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Affero General Public License, version 3,
7 * as published by the Free Software Foundation with the following additional
8 * term according to sec. 7:
9 *
10 * According to sec. 7 of the GNU Affero General Public License, version
11 * 3, the terms of the AGPL are supplemented with the following terms:
12 *
13 * "Zarafa" is a registered trademark of Zarafa B.V. The licensing of
14 * the Program under the AGPL does not imply a trademark license.
15 * Therefore any rights, title and interest in our trademarks remain
16 * entirely with us.
17 *
18 * However, if you propagate an unmodified version of the Program you are
19 * allowed to use the term "Zarafa" to indicate that you distribute the
20 * Program. Furthermore you may use our trademarks where it is necessary
21 * to indicate the intended purpose of a product or service provided you
22 * use it in accordance with honest practices in industrial or commercial
23 * matters.  If you want to propagate modified versions of the Program
24 * under the name "Zarafa" or "Zarafa Server", you may only do so if you
25 * have a written permission by Zarafa B.V. (to acquire a permission
26 * please contact Zarafa at trademark@zarafa.com).
27 *
28 * The interactive user interface of the software displays an attribution
29 * notice containing the term "Zarafa" and/or the logo of Zarafa.
30 * Interactive user interfaces of unmodified and modified versions must
31 * display Appropriate Legal Notices according to sec. 5 of the GNU
32 * Affero General Public License, version 3, when you propagate
33 * unmodified or modified versions of the Program. In accordance with
34 * sec. 7 b) of the GNU Affero General Public License, version 3, these
35 * Appropriate Legal Notices must retain the logo of Zarafa or display
36 * the words "Initial Development by Zarafa" if the display of the logo
37 * is not reasonably feasible for technical reasons. The use of the logo
38 * of Zarafa in Legal Notices is allowed for unmodified and modified
39 * versions of the software.
40 *
41 * This program is distributed in the hope that it will be useful,
42 * but WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
44 * GNU Affero General Public License for more details.
45 *
46 * You should have received a copy of the GNU Affero General Public License
47 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
48 *
49 */
50
51
52/**
53 * Function to make a MAPIGUID from a php string.
54 * The C++ definition for the GUID is:
55 *  typedef struct _GUID
56 *  {
57 *   unsigned long        Data1;
58 *   unsigned short       Data2;
59 *   unsigned short       Data3;
60 *   unsigned char        Data4[8];
61 *  } GUID;
62 *
63 * A GUID is normally represented in the following form:
64 *     {00062008-0000-0000-C000-000000000046}
65 *
66 * @param String GUID
67 */
68function makeGuid($guid)
69{
70    // remove the { and } from the string and explode it into an array
71    $guidArray = explode('-', substr($guid, 1,strlen($guid)-2));
72
73    // convert to hex!
74    $data1[0] = intval(substr($guidArray[0], 0, 4),16); // we need to split the unsigned long
75    $data1[1] = intval(substr($guidArray[0], 4, 4),16);
76    $data2 = intval($guidArray[1], 16);
77    $data3 = intval($guidArray[2], 16);
78
79    $data4[0] = intval(substr($guidArray[3], 0, 2),16);
80    $data4[1] = intval(substr($guidArray[3], 2, 2),16);
81
82    for($i=0; $i < 6; $i++)
83    {
84        $data4[] = intval(substr($guidArray[4], $i*2, 2),16);
85    }
86
87    return pack("vvvvCCCCCCCC", $data1[1], $data1[0], $data2, $data3, $data4[0],$data4[1],$data4[2],$data4[3],$data4[4],$data4[5],$data4[6],$data4[7]);
88}
89
90/**
91 * Function to get a human readable string from a MAPI error code
92 *
93 *@param int $errcode the MAPI error code, if not given, we use mapi_last_hresult
94 *@return string The defined name for the MAPI error code
95 */
96function get_mapi_error_name($errcode=null)
97{
98    if ($errcode === null){
99        $errcode = mapi_last_hresult();
100    }
101
102    if ($errcode !== 0) {
103        // get_defined_constants(true) is preferred, but crashes PHP
104        // https://bugs.php.net/bug.php?id=61156
105        $allConstants = get_defined_constants();
106
107        foreach ($allConstants as $key => $value) {
108            /**
109             * If PHP encounters a number beyond the bounds of the integer type,
110             * it will be interpreted as a float instead, so when comparing these error codes
111             * we have to manually typecast value to integer, so float will be converted in integer,
112             * but still its out of bound for integer limit so it will be auto adjusted to minus value
113             */
114            if ($errcode == (int) $value) {
115                // Check that we have an actual MAPI error or warning definition
116                $prefix = substr($key, 0, 7);
117                if ($prefix == "MAPI_E_" || $prefix == "MAPI_W_") {
118                    return $key;
119                }
120            }
121        }
122    } else {
123        return "NOERROR";
124    }
125
126    // error code not found, return hex value (this is a fix for 64-bit systems, we can't use the dechex() function for this)
127    $result = unpack("H*", pack("N", $errcode));
128    return "0x" . $result[1];
129}
130
131/**
132 * Parses properties from an array of strings. Each "string" may be either an ULONG, which is a direct property ID,
133 * or a string with format "PT_TYPE:{GUID}:StringId" or "PT_TYPE:{GUID}:0xXXXX" for named
134 * properties.
135 *
136 * @returns array of properties
137 */
138function getPropIdsFromStrings($store, $mapping)
139{
140    $props = array();
141
142    $ids = array("name"=>array(), "id"=>array(), "guid"=>array(), "type"=>array()); // this array stores all the information needed to retrieve a named property
143    $num = 0;
144
145    // caching
146    $guids = array();
147
148    foreach($mapping as $name=>$val){
149        if(is_string($val)) {
150            $split = explode(":", $val);
151
152            if(count($split) != 3){ // invalid string, ignore
153                trigger_error(sprintf("Invalid property: %s \"%s\"",$name,$val), E_USER_NOTICE);
154                continue;
155            }
156
157            if(substr($split[2], 0, 2) == "0x") {
158                $id = hexdec(substr($split[2], 2));
159            } else {
160                $id = $split[2];
161            }
162
163            // have we used this guid before?
164            if (!defined($split[1])){
165                if (!array_key_exists($split[1], $guids)){
166                    $guids[$split[1]] = makeguid($split[1]);
167                }
168                $guid = $guids[$split[1]];
169            }else{
170                $guid = constant($split[1]);
171            }
172
173            // temp store info about named prop, so we have to call mapi_getidsfromnames just one time
174            $ids["name"][$num] = $name;
175            $ids["id"][$num] = $id;
176            $ids["guid"][$num] = $guid;
177            $ids["type"][$num] = $split[0];
178            $num++;
179        }else{
180            // not a named property
181            $props[$name] = $val;
182        }
183    }
184
185    if (empty($ids["id"])){
186        return $props;
187    }
188
189    // get the ids
190    $named = mapi_getidsfromnames($store, $ids["id"], $ids["guid"]);
191    foreach($named as $num=>$prop){
192        $props[$ids["name"][$num]] = mapi_prop_tag(constant($ids["type"][$num]), mapi_prop_id($prop));
193    }
194
195    return $props;
196}
197
198/**
199 * Check wether a call to mapi_getprops returned errors for some properties.
200 * mapi_getprops function tries to get values of properties requested but somehow if
201 * if a property value can not be fetched then it changes type of property tag as PT_ERROR
202 * and returns error for that particular property, probable errors
203 * that can be returned as value can be MAPI_E_NOT_FOUND, MAPI_E_NOT_ENOUGH_MEMORY
204 *
205 * @param long $property Property to check for error
206 * @param Array $propArray An array of properties
207 * @return mixed Gives back false when there is no error, if there is, gives the error
208 */
209function propIsError($property, $propArray)
210{
211    if (array_key_exists(mapi_prop_tag(PT_ERROR, mapi_prop_id($property)), $propArray)) {
212        return $propArray[mapi_prop_tag(PT_ERROR, mapi_prop_id($property))];
213    } else {
214        return false;
215    }
216}
217
218/******** Macro Functions for PR_DISPLAY_TYPE_EX values *********/
219/**
220 * check addressbook object is a remote mailuser
221 */
222function DTE_IS_REMOTE_VALID($value) {
223    return !!($value & DTE_FLAG_REMOTE_VALID);
224}
225
226/**
227 * check addressbook object is able to receive permissions
228 */
229function DTE_IS_ACL_CAPABLE($value) {
230    return !!($value & DTE_FLAG_ACL_CAPABLE);
231}
232
233function DTE_REMOTE($value) {
234    return (($value & DTE_MASK_REMOTE) >> 8);
235}
236
237function DTE_LOCAL($value) {
238    return ($value & DTE_MASK_LOCAL);
239}
240
241/**
242 * Note: Static function, more like a utility function.
243 *
244 * Gets all the items (including recurring items) in the specified calendar in the given timeframe. Items are
245 * included as a whole if they overlap the interval <$start, $end> (non-inclusive). This means that if the interval
246 * is <08:00 - 14:00>, the item [6:00 - 8:00> is NOT included, nor is the item [14:00 - 16:00>. However, the item
247 * [7:00 - 9:00> is included as a whole, and is NOT capped to [8:00 - 9:00>.
248 *
249 * @param $store resource The store in which the calendar resides
250 * @param $calendar resource The calendar to get the items from
251 * @param $viewstart int Timestamp of beginning of view window
252 * @param $viewend int Timestamp of end of view window
253 * @param $propsrequested array Array of properties to return
254 * @param $rows array Array of rowdata as if they were returned directly from mapi_table_queryrows. Each recurring item is
255 *                    expanded so that it seems that there are only many single appointments in the table.
256 */
257function getCalendarItems($store, $calendar, $viewstart, $viewend, $propsrequested){
258    $result = array();
259    $properties = getPropIdsFromStrings($store, Array( "duedate" => "PT_SYSTIME:PSETID_Appointment:0x820e",
260                                               "startdate" =>  "PT_SYSTIME:PSETID_Appointment:0x820d",
261                                               "enddate_recurring" => "PT_SYSTIME:PSETID_Appointment:0x8236",
262                                               "recurring" => "PT_BOOLEAN:PSETID_Appointment:0x8223",
263                                               "recurring_data" => "PT_BINARY:PSETID_Appointment:0x8216",
264                                               "timezone_data" => "PT_BINARY:PSETID_Appointment:0x8233",
265                                               "label" => "PT_LONG:PSETID_Appointment:0x8214"
266                                                ));
267
268    // Create a restriction that will discard rows of appointments that are definitely not in our
269    // requested time frame
270
271    $table = mapi_folder_getcontentstable($calendar);
272
273    $restriction =
274        // OR
275        Array(RES_OR,
276                 Array(
277                       Array(RES_AND,    // Normal items: itemEnd must be after viewStart, itemStart must be before viewEnd
278                             Array(
279                                   Array(RES_PROPERTY,
280                                         Array(RELOP => RELOP_GT,
281                                               ULPROPTAG => $properties["duedate"],
282                                               VALUE => $viewstart
283                                               )
284                                         ),
285                                   Array(RES_PROPERTY,
286                                         Array(RELOP => RELOP_LT,
287                                               ULPROPTAG => $properties["startdate"],
288                                               VALUE => $viewend
289                                               )
290                                         )
291                                   )
292                             ),
293                       // OR
294                       Array(RES_PROPERTY,
295                             Array(RELOP => RELOP_EQ,
296                                   ULPROPTAG => $properties["recurring"],
297                                   VALUE => true
298                                   )
299                             )
300                       ) // EXISTS OR
301                 );        // global OR
302
303    // Get requested properties, plus whatever we need
304    $proplist = array(PR_ENTRYID, $properties["recurring"], $properties["recurring_data"], $properties["timezone_data"]);
305    $proplist = array_merge($proplist, $propsrequested);
306    $propslist = array_unique($proplist);
307
308    $rows = mapi_table_queryallrows($table, $proplist, $restriction);
309
310    // $rows now contains all the items that MAY be in the window; a recurring item needs expansion before including in the output.
311
312    foreach($rows as $row) {
313        $items = array();
314
315        if(isset($row[$properties["recurring"]]) && $row[$properties["recurring"]]) {
316            // Recurring item
317            $rec = new Recurrence($store, $row);
318
319            // GetItems guarantees that the item overlaps the interval <$viewstart, $viewend>
320            $occurrences = $rec->getItems($viewstart, $viewend);
321            foreach($occurrences as $occurrence) {
322                // The occurrence takes all properties from the main row, but overrides some properties (like start and end obviously)
323                $item = $occurrence + $row;
324                array_push($items, $item);
325            }
326
327        } else {
328            // Normal item, it matched the search criteria and therefore overlaps the interval <$viewstart, $viewend>
329            array_push($items, $row);
330        }
331
332        $result = array_merge($result,$items);
333    }
334
335    // All items are guaranteed to overlap the interval <$viewstart, $viewend>. Note that we may be returning a few extra
336    // properties that the caller did not request (recurring, etc). This shouldn't be a problem though.
337    return $result;
338}
339?>
Note: See TracBrowser for help on using the repository browser.