3333c80f68e1da959098dd86f4ffc95fa9242d68
[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         $result = $this->calDavRequest('PROPFIND', $this->calendarHomeSet, $this->decorator->preparefindAllCalendarsRequest(self::findAllCalendarsRequest), 1);
83         
84         foreach ($result as $uri => $response) {
85             if (isset($response['{DAV:}resourcetype']) && isset($response['{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set']) && 
86                     $response['{DAV:}resourcetype']->is('{urn:ietf:params:xml:ns:caldav}calendar') &&
87                     in_array('VEVENT', $response['{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set']->getValue())) {
88                 $this->calendars[$uri]['acl'] = $response['{DAV:}acl'];
89                 $this->calendars[$uri]['displayname'] = $response['{DAV:}displayname'];
90                 $this->decorator->processAdditionalCalendarProperties($this->calendars[$uri], $response);
91                 $this->resolvePrincipals($this->calendars[$uri]['acl']->getPrivileges());
92             }
93         }
94         
95         if (count($this->calendars) > 0) {
96             return true;
97         } else {
98             if (Tinebase_Core::isLogLevel(Zend_Log::WARN))
99                 Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' couldn\'t find a calendar');
100             return false;
101         }
102     }
103     
104     public function findAllCalendarICSs()
105     {
106         if (count($this->calendars) < 1 && ! $this->findAllCalendars())
107             return false;
108         
109         foreach ($this->calendars as $calUri => $calendar) {
110             $result = $this->calDavRequest('PROPFIND', $calUri, self::findAllCalendarICSsRequest, 1);
111             foreach ($result as $ics => $value) {
112                 if (strpos($ics, '.ics') !== FALSE)
113                     $this->calendarICSs[$calUri][] = $ics;
114             }
115         }
116         
117         if (count($this->calendarICSs) > 0) {
118             return true;
119         } else {
120             if (Tinebase_Core::isLogLevel(Zend_Log::WARN))
121                 Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' all found calendars are empty');
122             return false;
123         }
124     }
125     
126     protected function findContainerForCalendar($calendarUri, $displayname, $defaultCalendarsName, $type, $application_id, $modelName)
127     {
128         if (! preg_match('@__uids__/([^/]+)@', $calendarUri, $matches)) {
129             throw new Exception('no uuid found in calendar uri');
130         }
131         $uuid = $matches[1];
132         
133         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . ' ' . __LINE__
134                 . ' $displayname = ' . $displayname . ' $defaultCalendarsName = ' . $defaultCalendarsName . ' $uuid = ' . $uuid);
135         
136         $filter = new Tinebase_Model_ContainerFilter(array(
137             array(
138                 'field' => 'uuid', 
139                 'operator' => 'equals', 
140                 'value' => $uuid
141             ),
142             array(
143                 'field' => 'model', 
144                 'operator' => 'equals', 
145                 'value' => 'Calendar_Model_Event'
146             ),
147         ));
148         $existingCalendar = Tinebase_Container::getInstance()->search($filter, null, false, false, 'sync')->getFirstRecord();
149         if ($existingCalendar) {
150             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . ' ' . __LINE__
151                 . ' Found existing calendar ' . $existingCalendar->name . ' (id: ' . $existingCalendar->getId() . ')');
152             return $existingCalendar;
153         }
154         
155         $counter = '';
156         
157         if ($defaultCalendarsName == $displayname) {
158             $existingCalendar = Tinebase_Container::getInstance()->getDefaultContainer('Calendar_Model_Event');
159             if (! $existingCalendar->uuid) {
160                 if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . ' ' . __LINE__
161                     . ' Found existing calendar with the same name');
162                 $existingCalendar->uuid = $uuid;
163                 return $existingCalendar;
164             }
165             $existingCalendar = null;
166             $counter = 1;
167         }
168         
169         try {
170             while (true) {
171                 $existingCalendar = Tinebase_Container::getInstance()->getContainerByName('Calendar', $displayname . $counter, $type, Tinebase_Core::getUser());
172                 
173                 if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . ' ' . __LINE__
174                     . ' Got calendar: ' . $existingCalendar->name . ' (id: ' . $existingCalendar->getId() . ')');
175                 
176                 if (! $existingCalendar->uuid) {
177                     $existingCalendar->uuid = $uuid;
178                     return $existingCalendar;
179                 }
180                 $counter += 1;
181             }
182         } catch (Tinebase_Exception_NotFound $e) {
183             $newContainer = new Tinebase_Model_Container(array(
184                 'name'              => $displayname . $counter,
185                 'type'              => $type,
186                 'backend'           => 'Sql',
187                 'application_id'    => $application_id,
188                 'model'             => $modelName,
189                 'uuid'              => $uuid
190             ));
191             return Tinebase_Container::getInstance()->addContainer($newContainer);
192         }
193     }
194     
195     public function importAllCalendars()
196     {
197         if (count($this->calendars) < 1 && ! $this->findAllCalendars()) {
198             return false;
199         }
200         
201         if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . ' ' . __LINE__ 
202             . ' Importing all calendars for user ' . $this->userName);
203         
204         Calendar_Controller_Event::getInstance()->sendNotifications(false);
205         Calendar_Controller_Event::getInstance()->useNotes(false);
206         Sabre\VObject\Component\VCalendar::$propertyMap['ATTACH'] = '\\Calendar_Import_CalDav_SabreAttachProperty';
207         
208         $this->decorator->initCalendarImport();
209         
210         $modelName = Tinebase_Core::getApplicationInstance('Calendar')->getDefaultModel();
211         $application_id = Tinebase_Application::getInstance()->getApplicationByName('Calendar')->getId();
212         $type = Tinebase_Model_Container::TYPE_PERSONAL; //Tinebase_Model_Container::TYPE_SHARED;
213         $defaultContainer = Tinebase_Container::getInstance()->getDefaultContainer('Calendar_Model_Event');
214         
215         $defaultCalendarsName = $this->_getDefaultCalendarsName();
216         
217         foreach ($this->calendars as $calUri => $cal) {
218             $container = $this->findContainerForCalendar($calUri, $cal['displayname'], $defaultCalendarsName,
219                     $type, $application_id, $modelName);
220             
221             $this->decorator->setCalendarProperties($container, $this->calendars[$calUri]);
222             
223             $grants = $this->getCalendarGrants($calUri);
224             Tinebase_Container::getInstance()->setGrants($container->getId(), $grants, TRUE, FALSE);
225         }
226     }
227     
228     /**
229      * decide which calendar to use as default calendar
230      * if there is a remote default calendar, use that. If not, use the first we find
231      * 
232      * @return string
233      */
234     protected function _getDefaultCalendarsName() 
235     {
236         $defaultCalendarsName = '';
237         foreach ($this->calendarICSs as $calUri => $calICSs) {
238             if ($this->mapToDefaultContainer == $this->calendars[$calUri]['displayname']) {
239                 return $this->calendars[$calUri]['displayname'];
240             } elseif ($defaultCalendarsName === '') {
241                 $defaultCalendarsName = $this->calendars[$calUri]['displayname'];
242             }
243         }
244         return $defaultCalendarsName;
245     }
246     
247     /**
248      * 
249      * @param string $onlyCurrentUserOrganizer
250      * @return boolean
251      * 
252      * @todo check if $onlyCurrentUserOrganizer is needed
253      * @todo check deletes
254      */
255     public function updateAllCalendarData($onlyCurrentUserOrganizer = false)
256     {
257         if (count($this->calendarICSs) < 1 && ! $this->findAllCalendarICSs()) {
258             if (Tinebase_Core::isLogLevel(Zend_Log::INFO))
259                 Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' no calendars found for: ' . $this->userName);
260             return false;
261         }
262         
263         $newICSs = array();
264         $calendarEventBackend = Calendar_Controller_Event::getInstance()->getBackend();
265         
266         foreach ($this->calendarICSs as $calUri => $calICSs) {
267             $start = 0;
268             $max = count($calICSs);
269             $etags = array();
270             do {
271                 $requestEnd = '';
272                 for ($i = $start; $i < $max && $i < ($this->maxBulkRequest+$start); ++$i) {
273                     $requestEnd .= '  <a:href>' . $calICSs[$i] . "</a:href>\n";
274                 }
275                 $start = $i;
276                 $requestEnd .= '</b:calendar-multiget>';
277                 $result = $this->calDavRequest('REPORT', $calUri, self::getEventETagsRequest . $requestEnd, 1);
278                 
279                 foreach ($result as $key => $value) {
280                     if (isset($value['{DAV:}getetag'])) {
281                         $name = explode('/', $key);
282                         $name = end($name);
283                         $id = $this->_getEventIdFromName($name);
284                         $etags[$key] = array( 'id' => $id, 'etag' => $value['{DAV:}getetag']);
285                     }
286                 }
287             } while($start < $max);
288             
289             //check etags
290             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' '
291                 . ' Got ' . count($etags) . ' etags');
292             if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' '
293                 . ' etags: ' . print_r($etags, true));
294             
295             // @todo find out deleted events
296             foreach ($etags as $ics => $data) {
297                 try {
298                     $etagCheck = $calendarEventBackend->checkETag($data['id'], $data['etag']);
299                     if ($etagCheck) {
300                         continue; // same
301                     } else {
302                         $eventExists = true; // different
303                     }
304                 } catch (Tinebase_Exception_NotFound $tenf) {
305                     $eventExists = false;
306                 }
307                 
308                 if (!isset($newICSs[$calUri])) {
309                     $newICSs[$calUri] = array();
310                     $this->existingRecordIds[$calUri] = array();
311                 }
312                 $newICSs[$calUri][] = $ics;
313                 if ($eventExists) {
314                     $this->existingRecordIds[$calUri][] = $data['id'];
315                 }
316             }
317         }
318         
319         if (($count = count($newICSs)) > 0) {
320             if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' ' 
321                     . $count . ' calendar(s) changed for: ' . $this->userName);
322             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' ' 
323                     . ' events changed: ' . print_r($newICSs, true));
324             $this->calendarICSs = $newICSs;
325             $this->importAllCalendarData($onlyCurrentUserOrganizer, /* $update = */ true);
326         } else {
327             if (Tinebase_Core::isLogLevel(Zend_Log::WARN))
328                 Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' no changes found for: ' . $this->userName);
329         }
330     }
331     
332     protected function _getEventIdFromName($name)
333     {
334         return ($pos = strpos($name, '.')) === false ? $name : substr($name, 0, $pos);
335     }
336     
337     public function importAllCalendarData($onlyCurrentUserOrganizer = false, $update = false)
338     {
339         if (count($this->calendarICSs) < 1 && ! $this->findAllCalendarICSs()) {
340             return false;
341         }
342         
343         if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . ' ' . __LINE__
344             . ' Importing all calendar data for user ' . $this->userName . ' with ics uris: ' . print_r(array_keys($this->calendarICSs), true));
345         
346         Calendar_Controller_Event::getInstance()->sendNotifications(false);
347         Calendar_Controller_Event::getInstance()->useNotes(false);
348         Sabre\VObject\Component\VCalendar::$propertyMap['ATTACH'] = '\\Calendar_Import_CalDav_SabreAttachProperty';
349         
350         $this->decorator->initCalendarImport();
351         
352         $modelName = Tinebase_Core::getApplicationInstance('Calendar')->getDefaultModel();
353         $application_id = Tinebase_Application::getInstance()->getApplicationByName('Calendar')->getId();
354         $type = Tinebase_Model_Container::TYPE_PERSONAL; //Tinebase_Model_Container::TYPE_SHARED;
355         $defaultContainer = Tinebase_Container::getInstance()->getDefaultContainer('Calendar_Model_Event');
356         $calendarEventBackend = Calendar_Controller_Event::getInstance()->getBackend();
357         
358         $defaultCalendarsName = $this->_getDefaultCalendarsName();
359         
360         foreach ($this->calendarICSs as $calUri => $calICSs) {
361             if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . ' ' . __LINE__
362                 . ' Processing calendar ' . print_r($this->calendars[$calUri], true));
363             
364             $container = $this->findContainerForCalendar($calUri, $this->calendars[$calUri]['displayname'], $defaultCalendarsName,
365                     $type, $application_id, $modelName);
366             
367             $this->decorator->setCalendarProperties($container, $this->calendars[$calUri]);
368             
369             // we shouldnt do the grants here as the caldav user file may not contain all users, so setting the grants wont work properly!
370             // use importAllCalendars to have the grants set
371             //$grants = $this->getCalendarGrants($calUri);
372             //Tinebase_Container::getInstance()->setGrants($container->getId(), $grants, TRUE, FALSE);
373             
374             $start = 0;
375             $max = count($calICSs);
376             do {
377                 $etags = array();
378                 $requestEnd = '';
379                 for ($i = $start; $i < $max && $i < ($this->maxBulkRequest+$start); ++$i) {
380                     $requestEnd .= '  <a:href>' . $calICSs[$i] . "</a:href>\n";
381                 }
382                 $start = $i;
383                 $requestEnd .= '</b:calendar-multiget>';
384                 $result = $this->calDavRequest('REPORT', $calUri, self::getAllCalendarDataRequest . $requestEnd, 1);
385                 
386                 foreach ($result as $key => $value) {
387                     if (isset($value['{urn:ietf:params:xml:ns:caldav}calendar-data'])) {
388                         $data = $value['{urn:ietf:params:xml:ns:caldav}calendar-data'];
389                         $name = explode('/', $key);
390                         $name = end($name);
391                         $id = $this->_getEventIdFromName($name);
392                         try {
393                             if ($update && in_array($id, $this->existingRecordIds[$calUri])) {
394                                 $event = new Calendar_Frontend_WebDAV_Event($container, $id);
395                                 $event->put($data);
396                             } else {
397                                 $event = Calendar_Frontend_WebDAV_Event::create(
398                                     $container,
399                                     $name,
400                                     $data,
401                                     $onlyCurrentUserOrganizer
402                                 );
403                             }
404                             
405                             if ($event) {
406                                 $etags[$event->getRecord()->getId()] = $value['{DAV:}getetag'];
407                             }
408                         } catch (Exception $e) {
409                             // don't warn on VTODOs
410                             if (strpos($data, 'BEGIN:VTODO') !== false) {
411                                 if (Tinebase_Core::isLogLevel(Zend_Log::INFO))
412                                     Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Skipping VTODO');
413                             } else {
414                                 if (Tinebase_Core::isLogLevel(Zend_Log::WARN))
415                                     Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' Could not create event from data: ' . $data);
416                                 Tinebase_Exception::log($e);
417                             }
418                         }
419                     }
420                 }
421                 
422                 $calendarEventBackend->setETags($etags);
423             } while($start < $max);
424         }
425         return true;
426     }
427     
428     public function getCalendarGrants($calUri)
429     {
430         $grants = array();
431         $user = array();
432         $type = array();
433         $privilege = array();
434         foreach ($this->calendars[$calUri]['acl']->getPrivileges() as $ace)
435         {
436             if ('{DAV:}authenticated' == $ace['principal']) {
437                 $user[] = 0;
438                 $type[] = Tinebase_Acl_Rights::ACCOUNT_TYPE_ANYONE;
439                 $privilege[] = $ace['privilege'];
440             } elseif (isset($this->principals[$ace['principal']])) {
441                 $user[] = $this->principals[$ace['principal']]->getId();
442                 $type[] = Tinebase_Acl_Rights::ACCOUNT_TYPE_USER;
443                 $privilege[] = $ace['privilege'];
444             } elseif (isset($this->principalGroups[$ace['principal']])) {
445                 foreach($this->principalGroups[$ace['principal']] as $principal) {
446                     if ('{DAV:}authenticated' == $principal) {
447                         $user[] = 0;
448                         $type[] = Tinebase_Acl_Rights::ACCOUNT_TYPE_ANYONE;
449                         $privilege[] = $ace['privilege'];
450                     } elseif (isset($this->principals[$principal])) {
451                         $user[] = $this->principals[$principal]->getId();
452                         $type[] = Tinebase_Acl_Rights::ACCOUNT_TYPE_USER;
453                         $privilege[] = $ace['privilege'];
454                     } else {
455                         if (Tinebase_Core::isLogLevel(Zend_Log::WARN))
456                             Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' there is an unresolved principal: ' . $principal . ' in group: ' . $ace['principal']);
457                     }
458                 }
459             } else {
460                 if (Tinebase_Core::isLogLevel(Zend_Log::WARN))
461                     Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' couldn\'t resolve principal: '.$ace['principal']);
462             }
463         }
464         for ($i=0; $i<count($user); ++$i) {
465             switch ($privilege[$i]) {
466                 case '{DAV:}all':
467                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_READ ] = true;
468                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_ADD] = true;
469                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_EDIT] = true;
470                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_DELETE] = true;
471                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_EXPORT] = true;
472                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_SYNC] = true;
473                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_ADMIN] = true;
474                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_FREEBUSY] = true;
475                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_PRIVATE] = true;
476                     break;
477                 case '{urn:ietf:params:xml:ns:caldav}read-free-busy':
478                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_FREEBUSY] = true;
479                     break;
480                 case '{DAV:}read':
481                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_READ] = true;
482                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_EXPORT] = true;
483                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_SYNC] = true;
484                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_FREEBUSY] = true;
485                     break;
486                 case '{DAV:}write':
487                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_ADD] = true;
488                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_EDIT] = true;
489                     $grants[$user[$i]][Tinebase_Model_Grants::GRANT_DELETE] = true;
490                     break;
491                 case '{DAV:}read-current-user-privilege-set':
492                     continue;
493                 default:
494                     if (Tinebase_Core::isLogLevel(Zend_Log::WARN))
495                         Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' unknown privilege: ' . $privilege[$i]);
496                     continue;
497             }
498             $grants[$user[$i]]['account_id'] = $user[$i];
499             $grants[$user[$i]]['account_type'] = $type[$i];
500         }
501         if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE))
502             Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__ . ' found grants: ' . print_r($grants, true) . ' for calendar: ' . $calUri);
503         
504         return new Tinebase_Record_RecordSet('Tinebase_Model_Grants', $grants, TRUE);
505     }
506     
507     public function updateAllCalendarDataForUsers(array $users)
508     {
509         $result = true;
510         // first only update/import events where the current user is also the organizer
511 //         foreach ($users as $username => $pwd) {
512 //             $this->clearCurrentUserCalendarData();
513 //             $this->userName = $username;
514 //             $this->password = $pwd;
515 //             if (!$this->updateAllCalendarData(true)) {
516 //                 $result = false;
517 //             }
518 //         }
519         // then update all events again
520         foreach ($users as $username => $pwd) {
521             $this->clearCurrentUserCalendarData();
522             $this->userName = $username;
523             $this->password = $pwd;
524             if (!$this->updateAllCalendarData(false)) {
525                 $result = false;
526             }
527         }
528         return $result;
529     }
530     
531     public function importAllCalendarDataForUsers(array $users)
532     {
533         $result = true;
534         // first only import events where the current user is also the organizer
535         foreach ($users as $username => $pwd) {
536             $this->clearCurrentUserCalendarData();
537             $this->userName = $username;
538             $this->password = $pwd;
539             if (!$this->importAllCalendarData(true)) {
540                 $result = false;
541             }
542         }
543         // then import all events again
544         foreach ($users as $username => $pwd) {
545             $this->clearCurrentUserCalendarData();
546             $this->userName = $username;
547             $this->password = $pwd;
548             if (!$this->importAllCalendarData(false)) {
549                 $result = false;
550             }
551         }
552         return $result;
553     }
554     
555     public function importAllCalendarsForUsers(array $users)
556     {
557         if (!$this->findCurrentUserPrincipalForUsers($users)) {
558             return false;
559         }
560         
561         $result = true;
562         foreach ($users as $username => $pwd) {
563             $this->clearCurrentUserCalendarData();
564             $this->userName = $username;
565             $this->password = $pwd;
566             if (!$this->importAllCalendars()) {
567                 $result = false;
568             }
569         }
570         return $result;
571     }
572     
573     public function clearCurrentUserCalendarData()
574     {
575         $this->clearCurrentUserData();
576         $this->calendars = array();
577         $this->calendarICSs = array();
578     }
579 }