194e64208a8d6dc3dd65058dcd6412d56d32af2a
[tine20] / tine20 / Tinebase / Import / CalDav / Client.php
1 <?php
2
3 /**
4  * Tine 2.0
5  * 
6  * @package     Tinebase
7  * @subpackage  Import
8  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
9  * @author      Paul Mehrer <p.mehrer@metaways.de>
10  * @copyright   Copyright (c) 2014 Metaways Infosystems GmbH (http://www.metaways.de)
11  * 
12  * @todo        
13  */
14
15 /**
16  * Tinebase_Import_CalDav
17  * 
18  * @package     Tinebase
19  * @subpackage  Import
20  * 
21  */
22 class Tinebase_Import_CalDav_Client extends \Sabre\DAV\Client
23 {
24     protected $currentUserPrincipal = '';
25     protected $calendarHomeSet = '';
26     protected $principals = array();
27     protected $principalGroups = array();
28     
29     protected $requestLogFH;
30     
31     const findCurrentUserPrincipalRequest = 
32 '<?xml version="1.0"?>
33 <d:propfind xmlns:d="DAV:">
34   <d:prop>
35     <d:current-user-principal />
36   </d:prop>
37 </d:propfind>';
38
39     const findCalendarHomeSetRequest =
40 '<?xml version="1.0"?>
41 <d:propfind xmlns:d="DAV:">
42   <d:prop>
43     <x:calendar-home-set xmlns:x="urn:ietf:params:xml:ns:caldav"/>
44   </d:prop>
45 </d:propfind>';
46     
47     const resolvePrincipalRequest =
48 '<?xml version="1.0"?>
49 <d:propfind xmlns:d="DAV:">
50   <d:prop>
51     <d:group-member-set />
52     <d:displayname />
53   </d:prop>
54 </d:propfind>';
55     
56     public function __construct(array $a)
57     {
58         parent::__construct($a);
59         
60         //$this->requestLogFH = fopen('/var/log/tine20/requestLog', 'w');
61         
62         $this->propertyMap['{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set'] = 'Sabre\CalDAV\Property\SupportedCalendarComponentSet';
63         $this->propertyMap['{DAV:}acl'] = 'Sabre\DAVACL\Property\Acl';
64         $this->propertyMap['{DAV:}group-member-set'] = 'Tinebase_Import_CalDav_GroupMemberSet';
65     }
66     
67     public function findCurrentUserPrincipal()
68     {
69         $result = $this->calDavRequest('PROPFIND', '/principals/', self::findCurrentUserPrincipalRequest);
70         if (isset($result['{DAV:}current-user-principal']))
71         {
72             try {
73                 $user = Tinebase_User::getInstance()->getUserByLoginName($this->userName);
74                 Tinebase_Core::set(Tinebase_Core::USER, $user);
75                 $credentialCache = Tinebase_Auth_CredentialCache::getInstance()->cacheCredentials($this->userName, $this->password);
76                 Tinebase_Core::set(Tinebase_Core::USERCREDENTIALCACHE, $credentialCache);
77             } catch (Tinebase_Exception_NotFound $e) {
78                 Tinebase_Core::getLogger()->err(__METHOD__ . '::' . __LINE__ . ' can\'t find tine20 user: ' . $this->userName);
79                 return false;
80             }
81             $this->currentUserPrincipal = $result['{DAV:}current-user-principal'];
82             $this->principals[$this->currentUserPrincipal] = $user;
83             return true;
84         }
85         
86         Tinebase_Core::getLogger()->err(__METHOD__ . '::' . __LINE__ . ' couldn\'t find current users principal');
87         return false;
88     }
89     
90     public function findCurrentUserPrincipalForUsers(array $users)
91     {
92         $result = true;
93         foreach ($users as $username => $pwd) {
94             $this->userName = $username;
95             $this->password = $pwd;
96             if (!$this->findCurrentUserPrincipal()) {
97                 $result = false;
98             }
99         }
100         return $result;
101     }
102     
103     public function findCalendarHomeSet()
104     {
105         if ('' == $this->currentUserPrincipal && ! $this->findCurrentUserPrincipal())
106             return false;
107         $result = $this->calDavRequest('PROPFIND', $this->currentUserPrincipal, self::findCalendarHomeSetRequest);
108         if (isset($result['{urn:ietf:params:xml:ns:caldav}calendar-home-set']))
109         {
110             $this->calendarHomeSet = $result['{urn:ietf:params:xml:ns:caldav}calendar-home-set'];
111             return true;
112         }
113         
114         Tinebase_Core::getLogger()->err(__METHOD__ . '::' . __LINE__ . ' couldn\'t find calendar homeset');
115         return false;
116     }
117     
118     public function resolvePrincipals(array $privileges)
119     {
120         foreach ($privileges as $ace)
121         {
122             if ( $ace['principal'] == '{DAV:}authenticated' || $ace['principal'] == $this->currentUserPrincipal ||
123                  isset($this->principals[$ace['principal']]) || isset($this->principalGroups[$ace['principal']]))
124                          continue;
125             $result = $this->calDavRequest('PROPFIND', $ace['principal'], self::resolvePrincipalRequest);
126             if (isset($result['{DAV:}group-member-set'])) {
127                 $this->principalGroups[$ace['principal']] = $result['{DAV:}group-member-set']->getPrincipals();
128             }
129         }
130     }
131     
132     public function clearCurrentUserData()
133     {
134         $this->currentUserPrincipal = '';
135         $this->calendarHomeSet = '';
136     }
137     
138     public function calDavRequest($method, $uri, $body, $depth = 0)
139     {
140         $redo = 0;
141         $response = null;
142         while (++$redo < 10)
143         {
144             try {
145                 $response = $this->request($method, $uri, $body, array(
146                     'Depth' => $depth,
147                     'Content-Type' => 'text/xml',
148                 ));
149             } catch (Exception $e) {
150                 if (Tinebase_Core::isLogLevel(Zend_Log::WARN))
151                     Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' caldav request failed, sleeping 60 seconds and retrying: '
152                             . $method . ' ' . $uri . "\n" . $body . "\n" . $e->getMessage());
153                 sleep(60);
154                 continue;
155             }
156             break;
157         }
158         
159         if (! $response) {
160             throw new Tinebase_Exception("no response after several retries");
161         }
162         
163         $result = $this->parseMultiStatus($response['body']);
164         
165         //fputs($this->requestLogFH, $method.' '.$uri."\n".$body."\n".$depth."\n".$response['body']."\n\n\n\n\n\n\n", 10000000);
166         //echo $body."\n\n";
167         //print_r($response);
168         
169         // If depth was 0, we only return the top item
170         if ($depth===0) {
171             reset($result);
172             $result = current($result);
173             return isset($result[200])?$result[200]:array();
174         }
175         
176         $newResult = array();
177         foreach($result as $href => $statusList)
178         {
179             $newResult[$href] = isset($statusList[200])?$statusList[200]:array();
180         }
181         
182         return $newResult;
183     }
184 }