a8adacac633c53ad8a7ad470eb098da1c8a4e2b5
[tine20] / tine20 / Calendar / Import / CalDav / Client.php
1 <?php
2 //./tine20.php --username unittest --method Calendar.importCalDav url="https://osx-testfarm-mavericks-server.hh.metaways.de:8443" caldavuserfile=caldavuserfile.csv
3
4 /**
5  * Tine 2.0
6  * 
7  * @package     Calendar
8  * @subpackage  Import
9  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
10  * @author      Paul Mehrer <p.mehrer@metaways.de>
11  * @copyright   Copyright (c) 2014 Metaways Infosystems GmbH (http://www.metaways.de)
12  */
13
14 /**
15  * Calendar_Import_CalDAV
16  * 
17  * @package     Calendar
18  * @subpackage  Import
19  */
20 class Calendar_Import_CalDav_Client extends Tinebase_Import_CalDav_Client
21 {
22     protected $calendars = array();
23     protected $calendarICSs = array();
24     protected $existingRecordIds = array();
25     protected $maxBulkRequest = 20;
26     protected $mapToDefaultContainer = 'calendar';
27     protected $decorator = null;
28     
29     const findAllCalendarsRequest =
30 '<?xml version="1.0"?>
31 <d:propfind xmlns:d="DAV:">
32   <d:prop>
33     <d:resourcetype />
34     <d:acl />
35     <d:displayname />
36     <x:supported-calendar-component-set xmlns:x="urn:ietf:params:xml:ns:caldav"/>
37   </d:prop>
38 </d:propfind>';
39     
40     const findAllCalendarICSsRequest = 
41 '<?xml version="1.0"?>
42 <d:propfind xmlns:d="DAV:">
43   <d:prop>
44     <x:calendar-data xmlns:x="urn:ietf:params:xml:ns:caldav"/>
45   </d:prop>
46 </d:propfind>';
47     
48     const getAllCalendarDataRequest =
49 '<?xml version="1.0"?>
50 <b:calendar-multiget xmlns:a="DAV:" xmlns:b="urn:ietf:params:xml:ns:caldav">
51   <a:prop>
52     <b:calendar-data />
53     <a:getetag />
54   </a:prop>
55 ';
56     
57     const getEventETagsRequest =
58 '<?xml version="1.0"?>
59 <b:calendar-multiget xmlns:a="DAV:" xmlns:b="urn:ietf:params:xml:ns:caldav">
60   <a:prop>
61     <a:getetag />
62   </a:prop>
63 ';
64     
65     public function __construct(array $a, $flavor)
66     {
67         parent::__construct($a);
68         
69         $flavor = 'Calendar_Import_CalDav_Decorator_'.$flavor;
70         $this->decorator = new $flavor($this);
71     }
72     
73     public function findAllCalendars()
74     {
75         if ('' == $this->calendarHomeSet && ! $this->findCalendarHomeSet())
76             return false;
77         
78         //issue with follow location in curl!?!?
79         if ($this->calendarHomeSet[strlen($this->calendarHomeSet)-1] !== '/')
80             $this->calendarHomeSet .= '/';
81         
82         try {
83             $result = $this->calDavRequest('PROPFIND', $this->calendarHomeSet, $this->decorator->preparefindAllCalendarsRequest(self::findAllCalendarsRequest), 1);
84         } catch (Tinebase_Exception $te) {
85             if (Tinebase_Core::isLogLevel(Zend_Log::WARN))
86                 Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' request failed');
87             Tinebase_Exception::log($te);
88             return false;
89         }
90         
91         foreach ($result as $uri => $response) {
92             if (isset($response['{DAV:}resourcetype']) && isset($response['{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set']) && 
93                     $response['{DAV:}resourcetype']->is('{urn:ietf:params:xml:ns:caldav}calendar') &&
94                     in_array('VEVENT', $response['{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set']->getValue())) {
95                 $this->calendars[$uri]['acl'] = $response['{DAV:}acl'];
96                 $this->calendars[$uri]['displayname'] = $response['{DAV:}displayname'];
97                 $this->decorator->processAdditionalCalendarProperties($this->calendars[$uri], $response);
98                 $this->resolvePrincipals($this->calendars[$uri]['acl']->getPrivileges());
99             }
100         }
101         
102         if (count($this->calendars) > 0) {
103             return true;
104         } else {
105             if (Tinebase_Core::isLogLevel(Zend_Log::WARN))
106                 Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' couldn\'t find a calendar');
107             return false;
108         }
109     }
110     
111     public function findAllCalendarICSs()
112     {
113         if (count($this->calendars) < 1 && ! $this->findAllCalendars())
114             return false;
115         
116         foreach ($this->calendars as $calUri => $calendar) {
117             $result = $this->calDavRequest('PROPFIND', $calUri, self::findAllCalendarICSsRequest, 1);
118             foreach ($result as $ics => $value) {
119                 if (strpos($ics, '.ics') !== FALSE)
120                     $this->calendarICSs[$calUri][] = $ics;
121             }
122         }
123         
124         if (count($this->calendarICSs) > 0) {
125             return true;
126         } else {
127             if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE))
128                 Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__ . ' all found calendars are empty');
129             return false;
130         }
131     }
132     
133     protected function findContainerForCalendar($calendarUri, $displayname, $defaultCalendarsName, $type, $application_id, $modelName)
134     {
135         // sha1() the whole calendar uri as it is very hard to separate a uuid string from the uri otherwise
136         $uuid = sha1($calendarUri);
137         
138         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . ' ' . __LINE__
139                 . ' $calendarUri = ' . $calendarUri . ' / $displayname = ' . $displayname 
140                 . ' / $defaultCalendarsName = ' . $defaultCalendarsName . ' / $uuid = ' . $uuid);
141         
142         $filter = new Tinebase_Model_ContainerFilter(array(
143             array(
144                 'field' => 'uuid', 
145                 'operator' => 'equals', 
146                 'value' => $uuid
147             ),
148             array(
149                 'field' => 'model', 
150                 'operator' => 'equals', 
151                 'value' => 'Calendar_Model_Event'
152             ),
153         ));
154         $existingCalendar = Tinebase_Container::getInstance()->search($filter, null, false, false, 'sync')->getFirstRecord();
155         if ($existingCalendar) {
156             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . ' ' . __LINE__
157                 . ' Found existing calendar ' . $existingCalendar->name . ' (id: ' . $existingCalendar->getId() . ')');
158             return $existingCalendar;
159         }
160         
161         $counter = '';
162         
163         if ($defaultCalendarsName == $displayname) {
164             $existingCalendar = Tinebase_Container::getInstance()->getDefaultContainer('Calendar_Model_Event');
165             if (! $existingCalendar->uuid) {
166                 if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . ' ' . __LINE__
167                     . ' Found existing calendar with the same name');
168                 $existingCalendar->uuid = $uuid;
169                 return $existingCalendar;
170             }
171             $existingCalendar = null;
172             $counter = 1;
173         }
174         
175         try {
176             while (true) {
177                 $existingCalendar = Tinebase_Container::getInstance()->getContainerByName('Calendar', $displayname . $counter, $type, Tinebase_Core::getUser());
178                 
179                 if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . ' ' . __LINE__
180                     . ' Got calendar: ' . $existingCalendar->name . ' (id: ' . $existingCalendar->getId() . ')');
181                 
182                 if (! $existingCalendar->uuid) {
183                     $existingCalendar->uuid = $uuid;
184                     return $existingCalendar;
185                 }
186                 $counter += 1;
187             }
188         } catch (Tinebase_Exception_NotFound $e) {
189             $newContainer = new Tinebase_Model_Container(array(
190                 'name'              => $displayname . $counter,
191                 'type'              => $type,
192                 'backend'           => 'Sql',
193                 'application_id'    => $application_id,
194                 'model'             => $modelName,
195                 'uuid'              => $uuid
196             ));
197             return Tinebase_Container::getInstance()->addContainer($newContainer);
198         }
199     }
200     
201     public function importAllCalendars()
202     {
203         if (count($this->calendars) < 1 && ! $this->findAllCalendars()) {
204             return false;
205         }
206         
207         if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . ' ' . __LINE__ 
208             . ' Importing all calendars for user ' . $this->userName);
209         
210         Calendar_Controller_Event::getInstance()->sendNotifications(false);
211         Calendar_Controller_Event::getInstance()->useNotes(false);
212         Sabre\VObject\Component\VCalendar::$propertyMap['ATTACH'] = '\\Calendar_Import_CalDav_SabreAttachProperty';
213         
214         $this->decorator->initCalendarImport();
215         
216         $modelName = Tinebase_Core::getApplicationInstance('Calendar')->getDefaultModel();
217         $application_id = Tinebase_Application::getInstance()->getApplicationByName('Calendar')->getId();
218         $type = Tinebase_Model_Container::TYPE_PERSONAL;
219         
220         $defaultCalendarsName = $this->_getDefaultCalendarsName();
221         
222         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . ' ' . __LINE__
223             . ' Calendar uris to import: ' . print_r(array_keys($this->calendars), true));
224         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . ' ' . __LINE__
225             . ' Calendars to import: ' . print_r($this->calendars, true));
226         
227         foreach ($this->calendars as $calUri => $cal) {
228             $container = $this->findContainerForCalendar($calUri, $cal['displayname'], $defaultCalendarsName,
229                     $type, $application_id, $modelName);
230             
231             $this->decorator->setCalendarProperties($container, $this->calendars[$calUri]);
232             
233             $grants = $this->getCalendarGrants($calUri);
234             Tinebase_Container::getInstance()->setGrants($container->getId(), $grants, TRUE, FALSE);
235         }
236     }
237     
238     /**
239      * decide which calendar to use as default calendar
240      * if there is a remote default calendar, use that. If not, use the first we find
241      * 
242      * @return string
243      */
244     protected function _getDefaultCalendarsName() 
245     {
246         $defaultCalendarsName = '';
247         foreach ($this->calendarICSs as $calUri => $calICSs) {
248             if ($this->mapToDefaultContainer == $this->calendars[$calUri]['displayname']) {
249                 return $this->calendars[$calUri]['displayname'];
250             } elseif ($defaultCalendarsName === '') {
251                 $defaultCalendarsName = $this->calendars[$calUri]['displayname'];
252             }
253         }
254         return $defaultCalendarsName;
255     }
256     
257     /**
258      * 
259      * @param string $onlyCurrentUserOrganizer
260      * @return boolean
261      * 
262      * @todo check if $onlyCurrentUserOrganizer is needed
263      * @todo check deletes
264      */
265     public function updateAllCalendarData($onlyCurrentUserOrganizer = false)
266     {
267         if (count($this->calendarICSs) < 1 && ! $this->findAllCalendarICSs()) {
268             if (Tinebase_Core::isLogLevel(Zend_Log::INFO))
269                 Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' no calendars found for: ' . $this->userName);
270             return false;
271         }
272         
273         $newICSs = array();
274         $calendarEventBackend = Calendar_Controller_Event::getInstance()->getBackend();
275         
276         foreach ($this->calendarICSs as $calUri => $calICSs) {
277             $start = 0;
278             $max = count($calICSs);
279             $etags = array();
280             do {
281                 $requestEnd = '';
282                 for ($i = $start; $i < $max && $i < ($this->maxBulkRequest+$start); ++$i) {
283                     $requestEnd .= '  <a:href>' . $calICSs[$i] . "</a:href>\n";
284                 }
285                 $start = $i;
286                 $requestEnd .= '</b:calendar-multiget>';
287                 $result = $this->calDavRequest('REPORT', $calUri, self::getEventETagsRequest . $requestEnd, 1);
288                 
289                 foreach ($result as $key => $value) {
290                     if (isset($value['{DAV:}getetag'])) {
291                         $name = explode('/', $key);
292                         $name = end($name);
293                         $id = $this->_getEventIdFromName($name);
294                         $etags[$key] = array( 'id' => $id, 'etag' => $value['{DAV:}getetag']);
295                     }
296                 }
297             } while($start < $max);
298             
299             //check etags
300             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' '
301                 . ' Got ' . count($etags) . ' etags');
302             if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' '
303                 . ' etags: ' . print_r($etags, true));
304             
305             // @todo find out deleted events
306             foreach ($etags as $ics => $data) {
307                 try {
308                     $etagCheck = $calendarEventBackend->checkETag($data['id'], $data['etag']);
309                     if ($etagCheck) {
310                         continue; // same
311                     } else {
312                         $eventExists = true; // different
313                     }
314                 } catch (Tinebase_Exception_NotFound $tenf) {
315                     $eventExists = false;
316                 }
317                 
318                 if (!isset($newICSs[$calUri])) {
319                     $newICSs[$calUri] = array();
320                     $this->existingRecordIds[$calUri] = array();
321                 }
322                 $newICSs[$calUri][] = $ics;
323                 if ($eventExists) {
324                     $this->existingRecordIds[$calUri][] = $data['id'];
325                 }
326             }
327         }
328         
329         if (($count = count($newICSs)) > 0) {
330             if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' ' 
331                     . $count . ' calendar(s) changed for: ' . $this->userName);
332             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' ' 
333                     . ' events changed: ' . print_r($newICSs, true));
334             $this->calendarICSs = $newICSs;
335             $this->importAllCalendarData($onlyCurrentUserOrganizer, /* $update = */ true);
336         } else {
337             if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE))
338                 Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__ . ' no changes found for: ' . $this->userName);
339         }
340     }
341     
342     protected function _getEventIdFromName($name)
343     {
344         $id = ($pos = strpos($name, '.')) === false ? $name : substr($name, 0, $pos);
345         if (strlen($id) > 40) {
346             $id = sha1($id);
347         }
348         return $id;
349     }
350     
351     public function importAllCalendarData($onlyCurrentUserOrganizer = false, $update = false)
352     {
353         if (count($this->calendarICSs) < 1 && ! $this->findAllCalendarICSs()) {
354             return false;
355         }
356         
357         if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . ' ' . __LINE__
358             . ' Importing all calendar data for user ' . $this->userName . ' with ics uris: ' . print_r(array_keys($this->calendarICSs), true));
359         
360         Calendar_Controller_Event::getInstance()->sendNotifications(false);
361         Calendar_Controller_Event::getInstance()->useNotes(false);
362         Sabre\VObject\Component\VCalendar::$propertyMap['ATTACH'] = '\\Calendar_Import_CalDav_SabreAttachProperty';
363         
364         $this->decorator->initCalendarImport();
365         
366         $modelName = Tinebase_Core::getApplicationInstance('Calendar')->getDefaultModel();
367         $application_id = Tinebase_Application::getInstance()->getApplicationByName('Calendar')->getId();
368         $type = Tinebase_Model_Container::TYPE_PERSONAL; //Tinebase_Model_Container::TYPE_SHARED;
369         $defaultContainer = Tinebase_Container::getInstance()->getDefaultContainer('Calendar_Model_Event');
370         $calendarEventBackend = Calendar_Controller_Event::getInstance()->getBackend();
371         
372         $defaultCalendarsName = $this->_getDefaultCalendarsName();
373         
374         foreach ($this->calendarICSs as $calUri => $calICSs) {
375             if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . ' ' . __LINE__
376                 . ' Processing calendar ' . print_r($this->calendars[$calUri], true));
377             
378             $container = $this->findContainerForCalendar($calUri, $this->calendars[$calUri]['displayname'], $defaultCalendarsName,
379                     $type, $application_id, $modelName);
380             
381             $this->decorator->setCalendarProperties($container, $this->calendars[$calUri]);
382             
383             // we shouldnt do the grants here as the caldav user file may not contain all users, so setting the grants wont work properly!
384             // use importAllCalendars to have the grants set
385             //$grants = $this->getCalendarGrants($calUri);
386             //Tinebase_Container::getInstance()->setGrants($container->getId(), $grants, TRUE, FALSE);
387             
388             $start = 0;
389             $max = count($calICSs);
390             do {
391                 $etags = array();
392                 $requestEnd = '';
393                 for ($i = $start; $i < $max && $i < ($this->maxBulkRequest+$start); ++$i) {
394                     $requestEnd .= '  <a:href>' . $calICSs[$i] . "</a:href>\n";
395                 }
396                 $start = $i;
397                 $requestEnd .= '</b:calendar-multiget>';
398                 $result = $this->calDavRequest('REPORT', $calUri, self::getAllCalendarDataRequest . $requestEnd, 1);
399                 
400                 foreach ($result as $key => $value) {
401                     if (isset($value['{urn:ietf:params:xml:ns:caldav}calendar-data'])) {
402                         $data = $value['{urn:ietf:params:xml:ns:caldav}calendar-data'];
403                         $name = explode('/', $key);
404                         $name = end($name);
405                         $id = $this->_getEventIdFromName($name);
406                         try {
407                             if ($update && in_array($id, $this->existingRecordIds[$calUri])) {
408                                 $event = new Calendar_Frontend_WebDAV_Event($container, $id);
409                                 if ($onlyCurrentUserOrganizer) {
410                                     // assert current user is organizer
411                                     if ($event->getRecord()->organizer && $event->getRecord()->organizer == Tinebase_Core::getUser()->contact_id) {
412                                         $event->put($data);
413                                     } else {
414                                         continue;
415                                     }
416                                 } else {
417                                     $event->put($data);
418                                 }
419                                 
420                             } else {
421                                 $event = Calendar_Frontend_WebDAV_Event::create(
422                                     $container,
423                                     $name,
424                                     $data,
425                                     $onlyCurrentUserOrganizer
426                                 );
427                             }
428                             
429                             if ($event) {
430                                 $etags[$event->getRecord()->getId()] = $value['{DAV:}getetag'];
431                             }
432                         } catch (Exception $e) {
433                             // don't warn on VTODOs
434                             if (strpos($data, 'BEGIN:VTODO') !== false) {
435                                 if (Tinebase_Core::isLogLevel(Zend_Log::INFO))
436                                     Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Skipping VTODO');
437                             } else {
438                                 if (Tinebase_Core::isLogLevel(Zend_Log::WARN))
439                                     Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' Could not create event from data: ' . $data);
440                                 Tinebase_Exception::log($e);
441                             }
442                         }
443                     }
444                 }
445                 
446                 $calendarEventBackend->setETags($etags);
447             } while($start < $max);
448         }
449         return true;
450     }
451     
452     /**
453      * get Tine 2.0 group for given principal (by display name)
454      * - result is cached for 1 week
455      * 
456      * @param string $principal
457      * @return null|Tinebase_Model_Group
458      */
459     protected function _getGroupForPrincipal($principal)
460     {
461         $cacheId = convertCacheId('_getGroupForPrincipal' . $principal);
462         if (Tinebase_Core::getCache()->test($cacheId)) {
463             $group = Tinebase_Core::getCache()->load($cacheId);
464             if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . ' ' . __LINE__
465                     . ' Loading principal group from cache: ' . $group->name);
466             return $group;
467         }
468         
469         $group = null;
470         
471         $result = $this->calDavRequest('PROPFIND', $principal, self::resolvePrincipalRequest);
472         if (isset($result['{DAV:}group-member-set']) && isset($result['{DAV:}displayname'])) {
473             $groupDescription = $result['{DAV:}displayname'];
474             try {
475                 $group = Tinebase_Group::getInstance()->getGroupByPropertyFromSqlBackend('description',$groupDescription);
476                 if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . ' ' . __LINE__
477                         . ' Found matching group ' . $group->name . ' (' . $group->description .') for principal ' . $principal);
478                 Tinebase_Core::getCache()->save($group, $cacheId, array(), /* 1 week */ 24*3600*7);
479             } catch (Tinebase_Exception_Record_NotDefined $ternd) {
480                 if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE)) Tinebase_Core::getLogger()->notice(__METHOD__ . ' ' . __LINE__
481                         . ' Group not found: ' . $groupDescription);
482             }
483         }
484         
485         return $group;
486     }
487     
488     /**
489      * get grants for cal uri
490      * 
491      * @param string $calUri
492      * @return Tinebase_Record_RecordSet
493      */
494     public function getCalendarGrants($calUri)
495     {
496         $grants = array();
497         $user = array();
498         $type = array();
499         $privilege = array();
500         foreach ($this->calendars[$calUri]['acl']->getPrivileges() as $ace)
501         {
502             if ('{DAV:}authenticated' == $ace['principal']) {
503                 $user[] = 0;
504                 $type[] = Tinebase_Acl_Rights::ACCOUNT_TYPE_ANYONE;
505                 $privilege[] = $ace['privilege'];
506             } elseif (isset($this->principals[$ace['principal']])) {
507                 $user[] = $this->principals[$ace['principal']]->getId();
508                 $type[] = Tinebase_Acl_Rights::ACCOUNT_TYPE_USER;
509                 $privilege[] = $ace['privilege'];
510             } elseif (isset($this->principalGroups[$ace['principal']])) {
511                 foreach($this->principalGroups[$ace['principal']] as $principal) {
512                     if ('{DAV:}authenticated' == $principal) {
513                         $user[] = 0;
514                         $type[] = Tinebase_Acl_Rights::ACCOUNT_TYPE_ANYONE;
515                         $privilege[] = $ace['privilege'];
516                     } elseif (isset($this->principals[$principal])) {
517                         $user[] = $this->principals[$principal]->getId();
518                         $type[] = Tinebase_Acl_Rights::ACCOUNT_TYPE_USER;
519                         $privilege[] = $ace['privilege'];
520                     } else {
521                         $group = $this->_getGroupForPrincipal($principal);
522                         if ($group) {
523                             $user[] = $group->getId();
524                             $type[] = Tinebase_Acl_Rights::ACCOUNT_TYPE_GROUP;
525                             $privilege[] = $ace['privilege'];
526                         } else {
527                             if (Tinebase_Core::isLogLevel(Zend_Log::WARN))
528                                 Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ 
529                                     . ' There is an unresolved principal: ' . $principal . ' in group: ' . $ace['principal']);
530                         }
531                     }
532                 }
533             } else {
534                 if (Tinebase_Core::isLogLevel(Zend_Log::WARN))
535                     Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' Couldn\'t resolve principal: '.$ace['principal']);
536             }
537         }
538         for ($i=0; $i<count($user); ++$i) {
539             switch ($privilege[$i]) {
540                 case '{DAV:}all':
541                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_READ ] = true;
542                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_ADD] = true;
543                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_EDIT] = true;
544                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_DELETE] = true;
545                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_EXPORT] = true;
546                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_SYNC] = true;
547                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_ADMIN] = true;
548                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_FREEBUSY] = true;
549                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_PRIVATE] = true;
550                     break;
551                 case '{urn:ietf:params:xml:ns:caldav}read-free-busy':
552                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_FREEBUSY] = true;
553                     break;
554                 case '{DAV:}read':
555                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_READ] = true;
556                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_EXPORT] = true;
557                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_SYNC] = true;
558                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_FREEBUSY] = true;
559                     break;
560                 case '{DAV:}write':
561                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_ADD] = true;
562                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_EDIT] = true;
563                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_DELETE] = true;
564                     break;
565                 case '{DAV:}read-current-user-privilege-set':
566                     continue;
567                 default:
568                     if (Tinebase_Core::isLogLevel(Zend_Log::WARN))
569                         Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' unknown privilege: ' . $privilege[$i]);
570                     continue;
571             }
572             $grants[$user[$i]]['account_id'] = $user[$i];
573             $grants[$user[$i]]['account_type'] = $type[$i];
574         }
575         
576         if (Tinebase_Core::isLogLevel(Zend_Log::INFO))
577             Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' found ' . count($grants) . ' grants for calendar: ' . $calUri);
578         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG))
579             Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' grants: ' . print_r($grants, true));
580         
581         return new Tinebase_Record_RecordSet('Tinebase_Model_Grants', $grants, TRUE);
582     }
583     
584     public function updateAllCalendarDataForUsers(array $users)
585     {
586         $result = true;
587         // first only update/import events where the current user is also the organizer
588         foreach ($users as $username => $pwd) {
589             $this->clearCurrentUserCalendarData();
590             $this->userName = $username;
591             $this->password = $pwd;
592             if (!$this->updateAllCalendarData(true)) {
593                 $result = false;
594             }
595         }
596         // then update all events again
597         foreach ($users as $username => $pwd) {
598             $this->clearCurrentUserCalendarData();
599             $this->userName = $username;
600             $this->password = $pwd;
601             if (!$this->updateAllCalendarData(false)) {
602                 $result = false;
603             }
604         }
605         return $result;
606     }
607     
608     public function importAllCalendarDataForUsers(array $users)
609     {
610         $result = true;
611         // first only import events where the current user is also the organizer
612         foreach ($users as $username => $pwd) {
613             $this->clearCurrentUserCalendarData();
614             $this->userName = $username;
615             $this->password = $pwd;
616             if (!$this->importAllCalendarData(true)) {
617                 $result = false;
618             }
619         }
620         // then import all events again
621         foreach ($users as $username => $pwd) {
622             $this->clearCurrentUserCalendarData();
623             $this->userName = $username;
624             $this->password = $pwd;
625             if (!$this->importAllCalendarData(false)) {
626                 $result = false;
627             }
628         }
629         return $result;
630     }
631     
632     public function importAllCalendarsForUsers(array $users)
633     {
634         if (!$this->findCurrentUserPrincipalForUsers($users)) {
635             return false;
636         }
637         
638         $result = true;
639         foreach ($users as $username => $pwd) {
640             $this->clearCurrentUserCalendarData();
641             $this->userName = $username;
642             $this->password = $pwd;
643             if (!$this->importAllCalendars()) {
644                 $result = false;
645             }
646         }
647         return $result;
648     }
649     
650     public function clearCurrentUserCalendarData()
651     {
652         $this->clearCurrentUserData();
653         $this->calendars = array();
654         $this->calendarICSs = array();
655     }
656 }