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

Revision 7589, 18.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
52include_once('backend/zarafa/mapi/class.recurrence.php');
53
54class FreeBusyPublish {
55
56    var $session;
57    var $calendar;
58    var $entryid;
59    var $starttime;
60    var $length;
61    var $store;
62    var $proptags;
63
64    /**
65     * Constuctor
66     *
67     * @param mapi_session $session MAPI Session
68     * @param mapi_folder $calendar Calendar to publish
69     * @param string $entryid AddressBook Entry ID for the user we're publishing for
70     */
71
72
73    function FreeBusyPublish($session, $store, $calendar, $entryid)
74    {
75        $properties["entryid"] = PR_ENTRYID;
76        $properties["parent_entryid"] = PR_PARENT_ENTRYID;
77        $properties["message_class"] = PR_MESSAGE_CLASS;
78        $properties["icon_index"] = PR_ICON_INDEX;
79        $properties["subject"] = PR_SUBJECT;
80        $properties["display_to"] = PR_DISPLAY_TO;
81        $properties["importance"] = PR_IMPORTANCE;
82        $properties["sensitivity"] = PR_SENSITIVITY;
83        $properties["startdate"] = "PT_SYSTIME:PSETID_Appointment:0x820d";
84        $properties["duedate"] = "PT_SYSTIME:PSETID_Appointment:0x820e";
85        $properties["recurring"] = "PT_BOOLEAN:PSETID_Appointment:0x8223";
86        $properties["recurring_data"] = "PT_BINARY:PSETID_Appointment:0x8216";
87        $properties["busystatus"] = "PT_LONG:PSETID_Appointment:0x8205";
88        $properties["label"] = "PT_LONG:PSETID_Appointment:0x8214";
89        $properties["alldayevent"] = "PT_BOOLEAN:PSETID_Appointment:0x8215";
90        $properties["private"] = "PT_BOOLEAN:PSETID_Common:0x8506";
91        $properties["meeting"] = "PT_LONG:PSETID_Appointment:0x8217";
92        $properties["startdate_recurring"] = "PT_SYSTIME:PSETID_Appointment:0x8235";
93        $properties["enddate_recurring"] = "PT_SYSTIME:PSETID_Appointment:0x8236";
94        $properties["location"] = "PT_STRING8:PSETID_Appointment:0x8208";
95        $properties["duration"] = "PT_LONG:PSETID_Appointment:0x8213";
96        $properties["responsestatus"] = "PT_LONG:PSETID_Appointment:0x8218";
97        $properties["reminder"] = "PT_BOOLEAN:PSETID_Common:0x8503";
98        $properties["reminder_minutes"] = "PT_LONG:PSETID_Common:0x8501";
99        $properties["contacts"] = "PT_MV_STRING8:PSETID_Common:0x853a";
100        $properties["contacts_string"] = "PT_STRING8:PSETID_Common:0x8586";
101        $properties["categories"] = "PT_MV_STRING8:PS_PUBLIC_STRINGS:Keywords";
102        $properties["reminder_time"] = "PT_SYSTIME:PSETID_Common:0x8502";
103        $properties["commonstart"] = "PT_SYSTIME:PSETID_Common:0x8516";
104        $properties["commonend"] = "PT_SYSTIME:PSETID_Common:0x8517";
105        $properties["basedate"] = "PT_SYSTIME:PSETID_Appointment:0x8228";
106        $properties["timezone_data"] = "PT_BINARY:PSETID_Appointment:0x8233";
107        $this->proptags = getPropIdsFromStrings($store, $properties);
108
109        $this->session = $session;
110        $this->calendar = $calendar;
111        $this->entryid = $entryid;
112        $this->store = $store;
113    }
114
115    /**
116     * Publishes the infomation
117     * @paam timestamp $starttime Time from which to publish data  (usually now)
118     * @paam integer $length Amount of seconds from $starttime we should publish
119     */
120    function publishFB($starttime, $length) {
121        $start = $starttime;
122        $end = $starttime + $length;
123
124        // Get all the items in the calendar that we need
125
126        $calendaritems = Array();
127
128        $restrict = Array(RES_OR,
129                             Array(
130                                   // OR
131                                   // (item[start] >= start && item[start] <= end)
132                                   Array(RES_AND,
133                                         Array(
134                                               Array(RES_PROPERTY,
135                                                     Array(RELOP => RELOP_GE,
136                                                           ULPROPTAG => $this->proptags["startdate"],
137                                                           VALUE => $start
138                                                           )
139                                                     ),
140                                               Array(RES_PROPERTY,
141                                                     Array(RELOP => RELOP_LE,
142                                                           ULPROPTAG => $this->proptags["startdate"],
143                                                           VALUE => $end
144                                                           )
145                                                     )
146                                               )
147                                         ),
148                                   // OR
149                                   // (item[end]   >= start && item[end]   <= end)
150                                   Array(RES_AND,
151                                         Array(
152                                               Array(RES_PROPERTY,
153                                                     Array(RELOP => RELOP_GE,
154                                                           ULPROPTAG => $this->proptags["duedate"],
155                                                           VALUE => $start
156                                                           )
157                                                     ),
158                                               Array(RES_PROPERTY,
159                                                     Array(RELOP => RELOP_LE,
160                                                           ULPROPTAG => $this->proptags["duedate"],
161                                                           VALUE => $end
162                                                           )
163                                                     )
164                                               )
165                                         ),
166                                   // OR
167                                   // (item[start] <  start && item[end]   >  end)
168                                   Array(RES_AND,
169                                         Array(
170                                               Array(RES_PROPERTY,
171                                                     Array(RELOP => RELOP_LT,
172                                                           ULPROPTAG => $this->proptags["startdate"],
173                                                           VALUE => $start
174                                                           )
175                                                     ),
176                                               Array(RES_PROPERTY,
177                                                     Array(RELOP => RELOP_GT,
178                                                           ULPROPTAG => $this->proptags["duedate"],
179                                                           VALUE => $end
180                                                           )
181                                                     )
182                                               )
183                                         ),
184                                   // OR
185                                   Array(RES_OR,
186                                         Array(
187                                               // OR
188                                               // (EXIST(ecurrence_enddate_property) && item[isRecurring] == true && item[end] >= start)
189                                               Array(RES_AND,
190                                                     Array(
191                                                           Array(RES_EXIST,
192                                                                 Array(ULPROPTAG => $this->proptags["enddate_recurring"],
193                                                                       )
194                                                                 ),
195                                                           Array(RES_PROPERTY,
196                                                                 Array(RELOP => RELOP_EQ,
197                                                                       ULPROPTAG => $this->proptags["recurring"],
198                                                                       VALUE => true
199                                                                       )
200                                                                 ),
201                                                           Array(RES_PROPERTY,
202                                                                 Array(RELOP => RELOP_GE,
203                                                                       ULPROPTAG => $this->proptags["enddate_recurring"],
204                                                                       VALUE => $start
205                                                                       )
206                                                                 )
207                                                           )
208                                                     ),
209                                               // OR
210                                               // (!EXIST(ecurrence_enddate_property) && item[isRecurring] == true && item[start] <= end)
211                                               Array(RES_AND,
212                                                     Array(
213                                                           Array(RES_NOT,
214                                                                 Array(
215                                                                       Array(RES_EXIST,
216                                                                             Array(ULPROPTAG => $this->proptags["enddate_recurring"]
217                                                                                   )
218                                                                             )
219                                                                       )
220                                                                 ),
221                                                           Array(RES_PROPERTY,
222                                                                 Array(RELOP => RELOP_LE,
223                                                                       ULPROPTAG => $this->proptags["startdate"],
224                                                                       VALUE => $end
225                                                                       )
226                                                                 ),
227                                                           Array(RES_PROPERTY,
228                                                                 Array(RELOP => RELOP_EQ,
229                                                                       ULPROPTAG => $this->proptags["recurring"],
230                                                                       VALUE => true
231                                                                       )
232                                                                 )
233                                                           )
234                                                     )
235                                               )
236                                         ) // EXISTS OR
237                                   )
238                             );        // global OR
239
240        $contents = mapi_folder_getcontentstable($this->calendar);
241        mapi_table_restrict($contents, $restrict);
242
243        while(1) {
244            $rows = mapi_table_queryrows($contents, array_values($this->proptags), 0, 50);
245
246            if(!is_array($rows))
247                break;
248
249            if(empty($rows))
250                break;
251
252            foreach ($rows as $row) {
253                $occurrences = Array();
254                if(isset($row[$this->proptags['recurring']]) && $row[$this->proptags['recurring']]) {
255                    $recur = new Recurrence($this->store, $row);
256
257                    $occurrences = $recur->getItems($starttime, $starttime + $length);
258                } else {
259                    $occurrences[] = $row;
260                }
261
262                $calendaritems = array_merge($calendaritems, $occurrences);
263            }
264        }
265
266        // $calendaritems now contains all the calendar items in the specified time
267        // frame. We now need to merge these into a flat array of begin/end/status
268        // objects. This also filters out all the 'free' items (status 0)
269
270        $freebusy = $this->mergeItemsFB($calendaritems);
271
272        // $freebusy now contains the start, end and status of all items, merged.
273
274        // Get the FB interface
275        try {
276            $fbsupport = mapi_freebusysupport_open($this->session, $this->store);
277        } catch (MAPIException $e) {
278            if($e->getCode() == MAPI_E_NOT_FOUND) {
279                $e->setHandled();
280                if(function_exists("dump")) {
281                    dump("Error in opening freebusysupport object.");
282                }
283            }
284        }
285
286        // Open updater for this user
287        if(isset($fbsupport) && $fbsupport) {
288            $updaters = mapi_freebusysupport_loadupdate($fbsupport, Array($this->entryid));
289
290            $updater = $updaters[0];
291
292            // Send the data
293            mapi_freebusyupdate_reset($updater);
294            mapi_freebusyupdate_publish($updater, $freebusy);
295            mapi_freebusyupdate_savechanges($updater, $start-24*60*60, $end);
296
297            // We're finished
298            mapi_freebusysupport_close($fbsupport);
299        }
300        else
301            ZLog::Write(LOGLEVEL_WARN, "FreeBusyPublish is not available");
302    }
303
304    /**
305    * Sorts by timestamp, if equal, then end before start
306    */
307    function cmp($a, $b)
308    {
309        if ($a["time"] == $b["time"]) {
310            if($a["type"] < $b["type"])
311                return 1;
312            if($a["type"] > $b["type"])
313                return -1;
314            return 0;
315        }
316        return ($a["time"] > $b["time"] ? 1 : -1);
317    }
318
319    /**
320    * Function mergeItems
321    * @author Steve Hardy
322    */
323    function mergeItemsFB($items)
324    {
325        $merged = Array();
326        $timestamps = Array();
327        $csubj = Array();
328        $cbusy = Array();
329        $level = 0;
330        $laststart = null;
331
332        foreach($items as $item)
333        {
334            $ts["type"] = 0;
335            $ts["time"] = $item[$this->proptags["startdate"]];
336            $ts["subject"] = $item[PR_SUBJECT];
337            $ts["status"] = (isset($item[$this->proptags["busystatus"]])) ? $item[$this->proptags["busystatus"]] : 0; //ZP-197
338            $timestamps[] = $ts;
339
340            $ts["type"] = 1;
341            $ts["time"] = $item[$this->proptags["duedate"]];
342            $ts["subject"] = $item[PR_SUBJECT];
343            $ts["status"] = (isset($item[$this->proptags["busystatus"]])) ? $item[$this->proptags["busystatus"]] : 0; //ZP-197
344            $timestamps[] = $ts;
345        }
346
347        usort($timestamps, Array($this, "cmp"));
348        $laststart = 0; // seb added
349
350        foreach($timestamps as $ts)
351        {
352            switch ($ts["type"])
353            {
354                case 0: // Start
355                    if ($level != 0 && $laststart != $ts["time"])
356                    {
357                        $newitem["start"] = $laststart;
358                        $newitem["end"] = $ts["time"];
359                        $newitem["subject"] = join(",", $csubj);
360                        $newitem["status"] = !empty($cbusy) ? max($cbusy) : 0;
361                        if($newitem["status"] > 0)
362                            $merged[] = $newitem;
363                    }
364
365                    $level++;
366
367                    $csubj[] = $ts["subject"];
368                    $cbusy[] = $ts["status"];
369
370                    $laststart = $ts["time"];
371                    break;
372                case 1: // End
373                    if ($laststart != $ts["time"])
374                    {
375                        $newitem["start"] = $laststart;
376                        $newitem["end"] = $ts["time"];
377                        $newitem["subject"] = join(",", $csubj);
378                        $newitem["status"] = !empty($cbusy) ? max($cbusy) : 0;
379                        if($newitem["status"] > 0)
380                            $merged[] = $newitem;
381                    }
382
383                    $level--;
384
385                    array_splice($csubj, array_search($ts["subject"], $csubj, 1), 1);
386                    array_splice($cbusy, array_search($ts["status"], $cbusy, 1), 1);
387
388                    $laststart = $ts["time"];
389                    break;
390            }
391        }
392
393        return $merged;
394    }
395
396}
397?>
Note: See TracBrowser for help on using the repository browser.