removes retry after 60 secs in findCurrentUserPrincipalForUsers
[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, 0, /* tries = */ 1);
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())
117             return false;
118         $result = $this->calDavRequest('PROPFIND', $this->currentUserPrincipal, self::findCalendarHomeSetRequest);
119         if (isset($result['{urn:ietf:params:xml:ns:caldav}calendar-home-set']))
120         {
121             $this->calendarHomeSet = $result['{urn:ietf:params:xml:ns:caldav}calendar-home-set'];
122             return true;
123         }
124         
125         Tinebase_Core::getLogger()->err(__METHOD__ . '::' . __LINE__ . ' couldn\'t find calendar homeset');
126         return false;
127     }
128     
129     public function resolvePrincipals(array $privileges)
130     {
131         foreach ($privileges as $ace)
132         {
133             if ( $ace['principal'] == '{DAV:}authenticated' || $ace['principal'] == $this->currentUserPrincipal ||
134                  isset($this->principals[$ace['principal']]) || isset($this->principalGroups[$ace['principal']]))
135                          continue;
136             $result = $this->calDavRequest('PROPFIND', $ace['principal'], self::resolvePrincipalRequest);
137             if (isset($result['{DAV:}group-member-set'])) {
138                 $this->principalGroups[$ace['principal']] = $result['{DAV:}group-member-set']->getPrincipals();
139             }
140         }
141     }
142     
143     public function clearCurrentUserData()
144     {
145         $this->currentUserPrincipal = '';
146         $this->calendarHomeSet = '';
147     }
148     
149     public function calDavRequest($method, $uri, $body, $depth = 0, $tries = 10)
150     {
151         $response = null;
152         while ($tries > 0)
153         {
154             try {
155                 if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__
156                         . ' Sending ' . $method . ' request ...');
157                 $response = $this->request($method, $uri, $body, array(
158                     'Depth' => $depth,
159                     'Content-Type' => 'text/xml',
160                 ));
161             } catch (Exception $e) {
162                 if (Tinebase_Core::isLogLevel(Zend_Log::WARN))
163                     Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__
164                             . ' Caldav request failed: '
165                             . '(' . $this->userName . ')' . $method . ' ' . $uri . "\n" . $body
166                             . "\n" . $e->getMessage());
167                 if (--$tries > 0) {
168                     if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__
169                             . ' Sleeping 60 seconds and retrying ... ');
170                     sleep(60);
171                 }
172                 continue;
173             }
174             break;
175         }
176         
177         if (! $response) {
178             throw new Tinebase_Exception("no response");
179         }
180         
181         $result = $this->parseMultiStatus($response['body']);
182         
183         //fputs($this->requestLogFH, $method.' '.$uri."\n".$body."\n".$depth."\n".$response['body']."\n\n\n\n\n\n\n", 10000000);
184         //echo $body."\n\n";
185         //print_r($response);
186         
187         // If depth was 0, we only return the top item
188         if ($depth===0) {
189             reset($result);
190             $result = current($result);
191             return isset($result[200])?$result[200]:array();
192         }
193         
194         $newResult = array();
195         foreach($result as $href => $statusList)
196         {
197             $newResult[$href] = isset($statusList[200])?$statusList[200]:array();
198         }
199         
200         return $newResult;
201     }
202 }