improves group principals resolving / fixes user setting
[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         
225         foreach ($this->calendars as $calUri => $cal) {
226             $container = $this->findContainerForCalendar($calUri, $cal['displayname'], $defaultCalendarsName,
227                     $type, $application_id, $modelName);
228             
229             $this->decorator->setCalendarProperties($container, $this->calendars[$calUri]);
230             
231             $grants = $this->getCalendarGrants($calUri);
232             Tinebase_Container::getInstance()->setGrants($container->getId(), $grants, TRUE, FALSE);
233         }
234     }
235     
236     /**
237      * decide which calendar to use as default calendar
238      * if there is a remote default calendar, use that. If not, use the first we find
239      * 
240      * @return string
241      */
242     protected function _getDefaultCalendarsName() 
243     {
244         $defaultCalendarsName = '';
245         foreach ($this->calendarICSs as $calUri => $calICSs) {
246             if ($this->mapToDefaultContainer == $this->calendars[$calUri]['displayname']) {
247                 return $this->calendars[$calUri]['displayname'];
248             } elseif ($defaultCalendarsName === '') {
249                 $defaultCalendarsName = $this->calendars[$calUri]['displayname'];
250             }
251         }
252         return $defaultCalendarsName;
253     }
254     
255     /**
256      * 
257      * @param string $onlyCurrentUserOrganizer
258      * @return boolean
259      * 
260      * @todo check if $onlyCurrentUserOrganizer is needed
261      * @todo check deletes
262      */
263     public function updateAllCalendarData($onlyCurrentUserOrganizer = false)
264     {
265         if (count($this->calendarICSs) < 1 && ! $this->findAllCalendarICSs()) {
266             if (Tinebase_Core::isLogLevel(Zend_Log::INFO))
267                 Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' no calendars found for: ' . $this->userName);
268             return false;
269         }
270         
271         $newICSs = array();
272         $calendarEventBackend = Calendar_Controller_Event::getInstance()->getBackend();
273         
274         foreach ($this->calendarICSs as $calUri => $calICSs) {
275             $start = 0;
276             $max = count($calICSs);
277             $etags = array();
278             do {
279                 $requestEnd = '';
280                 for ($i = $start; $i < $max && $i < ($this->maxBulkRequest+$start); ++$i) {
281                     $requestEnd .= '  <a:href>' . $calICSs[$i] . "</a:href>\n";
282                 }
283                 $start = $i;
284                 $requestEnd .= '</b:calendar-multiget>';
285                 $result = $this->calDavRequest('REPORT', $calUri, self::getEventETagsRequest . $requestEnd, 1);
286                 
287                 foreach ($result as $key => $value) {
288                     if (isset($value['{DAV:}getetag'])) {
289                         $name = explode('/', $key);
290                         $name = end($name);
291                         $id = $this->_getEventIdFromName($name);
292                         $etags[$key] = array( 'id' => $id, 'etag' => $value['{DAV:}getetag']);
293                     }
294                 }
295             } while($start < $max);
296             
297             //check etags
298             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' '
299                 . ' Got ' . count($etags) . ' etags');
300             if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' '
301                 . ' etags: ' . print_r($etags, true));
302             
303             // @todo find out deleted events
304             foreach ($etags as $ics => $data) {
305                 try {
306                     $etagCheck = $calendarEventBackend->checkETag($data['id'], $data['etag']);
307                     if ($etagCheck) {
308                         continue; // same
309                     } else {
310                         $eventExists = true; // different
311                     }
312                 } catch (Tinebase_Exception_NotFound $tenf) {
313                     $eventExists = false;
314                 }
315                 
316                 if (!isset($newICSs[$calUri])) {
317                     $newICSs[$calUri] = array();
318                     $this->existingRecordIds[$calUri] = array();
319                 }
320                 $newICSs[$calUri][] = $ics;
321                 if ($eventExists) {
322                     $this->existingRecordIds[$calUri][] = $data['id'];
323                 }
324             }
325         }
326         
327         if (($count = count($newICSs)) > 0) {
328             if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' ' 
329                     . $count . ' calendar(s) changed for: ' . $this->userName);
330             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' ' 
331                     . ' events changed: ' . print_r($newICSs, true));
332             $this->calendarICSs = $newICSs;
333             $this->importAllCalendarData($onlyCurrentUserOrganizer, /* $update = */ true);
334         } else {
335             if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE))
336                 Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__ . ' no changes found for: ' . $this->userName);
337         }
338     }
339     
340     protected function _getEventIdFromName($name)
341     {
342         $id = ($pos = strpos($name, '.')) === false ? $name : substr($name, 0, $pos);
343         if (strlen($id) > 40) {
344             $id = sha1($id);
345         }
346         return $id;
347     }
348     
349     public function importAllCalendarData($onlyCurrentUserOrganizer = false, $update = false)
350     {
351         if (count($this->calendarICSs) < 1 && ! $this->findAllCalendarICSs()) {
352             return false;
353         }
354         
355         if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . ' ' . __LINE__
356             . ' Importing all calendar data for user ' . $this->userName . ' with ics uris: ' . print_r(array_keys($this->calendarICSs), true));
357         
358         Calendar_Controller_Event::getInstance()->sendNotifications(false);
359         Calendar_Controller_Event::getInstance()->useNotes(false);
360         Sabre\VObject\Component\VCalendar::$propertyMap['ATTACH'] = '\\Calendar_Import_CalDav_SabreAttachProperty';
361         
362         $this->decorator->initCalendarImport();
363         
364         $modelName = Tinebase_Core::getApplicationInstance('Calendar')->getDefaultModel();
365         $application_id = Tinebase_Application::getInstance()->getApplicationByName('Calendar')->getId();
366         $type = Tinebase_Model_Container::TYPE_PERSONAL; //Tinebase_Model_Container::TYPE_SHARED;
367         $defaultContainer = Tinebase_Container::getInstance()->getDefaultContainer('Calendar_Model_Event');
368         $calendarEventBackend = Calendar_Controller_Event::getInstance()->getBackend();
369         
370         $defaultCalendarsName = $this->_getDefaultCalendarsName();
371         
372         foreach ($this->calendarICSs as $calUri => $calICSs) {
373             if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . ' ' . __LINE__
374                 . ' Processing calendar ' . print_r($this->calendars[$calUri], true));
375             
376             $container = $this->findContainerForCalendar($calUri, $this->calendars[$calUri]['displayname'], $defaultCalendarsName,
377                     $type, $application_id, $modelName);
378             
379             $this->decorator->setCalendarProperties($container, $this->calendars[$calUri]);
380             
381             // we shouldnt do the grants here as the caldav user file may not contain all users, so setting the grants wont work properly!
382             // use importAllCalendars to have the grants set
383             //$grants = $this->getCalendarGrants($calUri);
384             //Tinebase_Container::getInstance()->setGrants($container->getId(), $grants, TRUE, FALSE);
385             
386             $start = 0;
387             $max = count($calICSs);
388             do {
389                 $etags = array();
390                 $requestEnd = '';
391                 for ($i = $start; $i < $max && $i < ($this->maxBulkRequest+$start); ++$i) {
392                     $requestEnd .= '  <a:href>' . $calICSs[$i] . "</a:href>\n";
393                 }
394                 $start = $i;
395                 $requestEnd .= '</b:calendar-multiget>';
396                 $result = $this->calDavRequest('REPORT', $calUri, self::getAllCalendarDataRequest . $requestEnd, 1);
397                 
398                 foreach ($result as $key => $value) {
399                     if (isset($value['{urn:ietf:params:xml:ns:caldav}calendar-data'])) {
400                         $data = $value['{urn:ietf:params:xml:ns:caldav}calendar-data'];
401                         $name = explode('/', $key);
402                         $name = end($name);
403                         $id = $this->_getEventIdFromName($name);
404                         try {
405                             if ($update && in_array($id, $this->existingRecordIds[$calUri])) {
406                                 $event = new Calendar_Frontend_WebDAV_Event($container, $id);
407                                 if ($onlyCurrentUserOrganizer) {
408                                     // assert current user is organizer
409                                     if ($event->getRecord()->organizer && $event->getRecord()->organizer == Tinebase_Core::getUser()->contact_id) {
410                                         $event->put($data);
411                                     } else {
412                                         continue;
413                                     }
414                                 } else {
415                                     $event->put($data);
416                                 }
417                                 
418                             } else {
419                                 $event = Calendar_Frontend_WebDAV_Event::create(
420                                     $container,
421                                     $name,
422                                     $data,
423                                     $onlyCurrentUserOrganizer
424                                 );
425                             }
426                             
427                             if ($event) {
428                                 $etags[$event->getRecord()->getId()] = $value['{DAV:}getetag'];
429                             }
430                         } catch (Exception $e) {
431                             // don't warn on VTODOs
432                             if (strpos($data, 'BEGIN:VTODO') !== false) {
433                                 if (Tinebase_Core::isLogLevel(Zend_Log::INFO))
434                                     Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Skipping VTODO');
435                             } else {
436                                 if (Tinebase_Core::isLogLevel(Zend_Log::WARN))
437                                     Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' Could not create event from data: ' . $data);
438                                 Tinebase_Exception::log($e);
439                             }
440                         }
441                     }
442                 }
443                 
444                 $calendarEventBackend->setETags($etags);
445             } while($start < $max);
446         }
447         return true;
448     }
449     
450     public function getCalendarGrants($calUri)
451     {
452         $grants = array();
453         $user = array();
454         $type = array();
455         $privilege = array();
456         foreach ($this->calendars[$calUri]['acl']->getPrivileges() as $ace)
457         {
458             if ('{DAV:}authenticated' == $ace['principal']) {
459                 $user[] = 0;
460                 $type[] = Tinebase_Acl_Rights::ACCOUNT_TYPE_ANYONE;
461                 $privilege[] = $ace['privilege'];
462             } elseif (isset($this->principals[$ace['principal']])) {
463                 $user[] = $this->principals[$ace['principal']]->getId();
464                 $type[] = Tinebase_Acl_Rights::ACCOUNT_TYPE_USER;
465                 $privilege[] = $ace['privilege'];
466             } elseif (isset($this->principalGroups[$ace['principal']])) {
467                 foreach($this->principalGroups[$ace['principal']] as $principal) {
468                     if ('{DAV:}authenticated' == $principal) {
469                         $user[] = 0;
470                         $type[] = Tinebase_Acl_Rights::ACCOUNT_TYPE_ANYONE;
471                         $privilege[] = $ace['privilege'];
472                     } elseif (isset($this->principals[$principal])) {
473                         $user[] = $this->principals[$principal]->getId();
474                         $type[] = Tinebase_Acl_Rights::ACCOUNT_TYPE_USER;
475                         $privilege[] = $ace['privilege'];
476                     } else {
477                         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG))
478                             Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ 
479                                 . ' there is an unresolved principal: ' . $principal . ' in group: ' . $ace['principal']);
480                     }
481                 }
482             } else {
483                 if (Tinebase_Core::isLogLevel(Zend_Log::WARN))
484                     Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' couldn\'t resolve principal: '.$ace['principal']);
485             }
486         }
487         for ($i=0; $i<count($user); ++$i) {
488             switch ($privilege[$i]) {
489                 case '{DAV:}all':
490                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_READ ] = true;
491                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_ADD] = true;
492                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_EDIT] = true;
493                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_DELETE] = true;
494                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_EXPORT] = true;
495                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_SYNC] = true;
496                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_ADMIN] = true;
497                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_FREEBUSY] = true;
498                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_PRIVATE] = true;
499                     break;
500                 case '{urn:ietf:params:xml:ns:caldav}read-free-busy':
501                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_FREEBUSY] = true;
502                     break;
503                 case '{DAV:}read':
504                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_READ] = true;
505                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_EXPORT] = true;
506                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_SYNC] = true;
507                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_FREEBUSY] = true;
508                     break;
509                 case '{DAV:}write':
510                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_ADD] = true;
511                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_EDIT] = true;
512                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_DELETE] = true;
513                     break;
514                 case '{DAV:}read-current-user-privilege-set':
515                     continue;
516                 default:
517                     if (Tinebase_Core::isLogLevel(Zend_Log::WARN))
518                         Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' unknown privilege: ' . $privilege[$i]);
519                     continue;
520             }
521             $grants[$user[$i]]['account_id'] = $user[$i];
522             $grants[$user[$i]]['account_type'] = $type[$i];
523         }
524         
525         if (Tinebase_Core::isLogLevel(Zend_Log::INFO))
526             Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' found ' . count($grants) . ' grants for calendar: ' . $calUri);
527         if (Tinebase_Core::isLogLevel(Zend_Log::TRACE))
528             Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' grants: ' . print_r($grants, true));
529         
530         return new Tinebase_Record_RecordSet('Tinebase_Model_Grants', $grants, TRUE);
531     }
532     
533     public function updateAllCalendarDataForUsers(array $users)
534     {
535         $result = true;
536         // first only update/import events where the current user is also the organizer
537         foreach ($users as $username => $pwd) {
538             $this->clearCurrentUserCalendarData();
539             $this->userName = $username;
540             $this->password = $pwd;
541             if (!$this->updateAllCalendarData(true)) {
542                 $result = false;
543             }
544         }
545         // then update all events again
546         foreach ($users as $username => $pwd) {
547             $this->clearCurrentUserCalendarData();
548             $this->userName = $username;
549             $this->password = $pwd;
550             if (!$this->updateAllCalendarData(false)) {
551                 $result = false;
552             }
553         }
554         return $result;
555     }
556     
557     public function importAllCalendarDataForUsers(array $users)
558     {
559         $result = true;
560         // first only import events where the current user is also the organizer
561         foreach ($users as $username => $pwd) {
562             $this->clearCurrentUserCalendarData();
563             $this->userName = $username;
564             $this->password = $pwd;
565             if (!$this->importAllCalendarData(true)) {
566                 $result = false;
567             }
568         }
569         // then import all events again
570         foreach ($users as $username => $pwd) {
571             $this->clearCurrentUserCalendarData();
572             $this->userName = $username;
573             $this->password = $pwd;
574             if (!$this->importAllCalendarData(false)) {
575                 $result = false;
576             }
577         }
578         return $result;
579     }
580     
581     public function importAllCalendarsForUsers(array $users)
582     {
583         if (!$this->findCurrentUserPrincipalForUsers($users)) {
584             return false;
585         }
586         
587         $result = true;
588         foreach ($users as $username => $pwd) {
589             $this->clearCurrentUserCalendarData();
590             $this->userName = $username;
591             $this->password = $pwd;
592             if (!$this->importAllCalendars()) {
593                 $result = false;
594             }
595         }
596         return $result;
597     }
598     
599     public function clearCurrentUserCalendarData()
600     {
601         $this->clearCurrentUserData();
602         $this->calendars = array();
603         $this->calendarICSs = array();
604     }
605 }