increase number of tries for user principal
[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($tries = 1)
68     {
69         $result = $this->calDavRequest('PROPFIND', '/principals/', self::findCurrentUserPrincipalRequest, 0, $tries);
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         foreach ($users as $username => $pwd) {
93             $this->userName = $username;
94             $this->password = $pwd;
95             
96             if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . ' ' . __LINE__
97                 . ' Find principal for user ' . $this->userName);
98             try {
99                 if (! $this->findCurrentUserPrincipal()) {
100                     if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE)) Tinebase_Core::getLogger()->notice(__METHOD__ . ' ' . __LINE__
101                         . ' Skipping ' . $username);
102                     unset($users[$username]);
103                 }
104             } catch (Tinebase_Exception $te) {
105                 // TODO should use better exception (Not_Authenticatied, ...)
106                 if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE)) Tinebase_Core::getLogger()->notice(__METHOD__ . ' ' . __LINE__
107                         . ' Skipping ' . $username);
108                 unset($users[$username]);
109             }
110         }
111         return count($users) > 0;
112     }
113     
114     public function findCalendarHomeSet()
115     {
116         if ('' == $this->currentUserPrincipal && ! $this->findCurrentUserPrincipal(/* tries = */ 3)) {
117             return false;
118         }
119         $result = $this->calDavRequest('PROPFIND', $this->currentUserPrincipal, self::findCalendarHomeSetRequest);
120         
121         if (isset($result['{urn:ietf:params:xml:ns:caldav}calendar-home-set'])) {
122             $this->calendarHomeSet = $result['{urn:ietf:params:xml:ns:caldav}calendar-home-set'];
123             return true;
124         }
125         
126         Tinebase_Core::getLogger()->err(__METHOD__ . '::' . __LINE__ . ' couldn\'t find calendar homeset');
127         return false;
128     }
129     
130     public function resolvePrincipals(array $privileges)
131     {
132         foreach ($privileges as $ace)
133         {
134             if ( $ace['principal'] == '{DAV:}authenticated' || $ace['principal'] == $this->currentUserPrincipal ||
135                  isset($this->principals[$ace['principal']]) || isset($this->principalGroups[$ace['principal']]))
136                          continue;
137             $result = $this->calDavRequest('PROPFIND', $ace['principal'], self::resolvePrincipalRequest);
138             if (isset($result['{DAV:}group-member-set'])) {
139                 $this->principalGroups[$ace['principal']] = $result['{DAV:}group-member-set']->getPrincipals();
140             }
141         }
142     }
143     
144     public function clearCurrentUserData()
145     {
146         $this->currentUserPrincipal = '';
147         $this->calendarHomeSet = '';
148     }
149     
150     public function calDavRequest($method, $uri, $body, $depth = 0, $tries = 10)
151     {
152         $response = null;
153         while ($tries > 0)
154         {
155             try {
156                 if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__
157                         . ' Sending ' . $method . ' request ...');
158                 $response = $this->request($method, $uri, $body, array(
159                     'Depth' => $depth,
160                     'Content-Type' => 'text/xml',
161                 ));
162             } catch (Exception $e) {
163                 if (Tinebase_Core::isLogLevel(Zend_Log::WARN))
164                     Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__
165                             . ' Caldav request failed: '
166                             . '(' . $this->userName . ')' . $method . ' ' . $uri . "\n" . $body
167                             . "\n" . $e->getMessage());
168                 if (--$tries > 0) {
169                     if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__
170                             . ' Sleeping 60 seconds and retrying ... ');
171                     sleep(60);
172                 }
173                 continue;
174             }
175             break;
176         }
177         
178         if (! $response) {
179             throw new Tinebase_Exception("no response");
180         }
181         
182         $result = $this->parseMultiStatus($response['body']);
183         
184         //fputs($this->requestLogFH, $method.' '.$uri."\n".$body."\n".$depth."\n".$response['body']."\n\n\n\n\n\n\n", 10000000);
185         //echo $body."\n\n";
186         //print_r($response);
187         
188         // If depth was 0, we only return the top item
189         if ($depth===0) {
190             reset($result);
191             $result = current($result);
192             return isset($result[200])?$result[200]:array();
193         }
194         
195         $newResult = array();
196         foreach($result as $href => $statusList)
197         {
198             $newResult[$href] = isset($statusList[200])?$statusList[200]:array();
199         }
200         
201         return $newResult;
202     }
203 }