source: trunk/zpush/lib/utils/zpushadmin.php @ 7589

Revision 7589, 17.9 KB checked in by douglas, 11 years ago (diff)

Ticket #3209 - Integrar módulo de sincronização Z-push ao Expresso

Line 
1<?php
2/***********************************************
3* File      :   zpushadmin.php
4* Project   :   Z-Push
5* Descr     :   Administration tasks for users and devices
6*
7* Created   :   23.12.2011
8*
9* Copyright 2007 - 2012 Zarafa Deutschland GmbH
10*
11* This program is free software: you can redistribute it and/or modify
12* it under the terms of the GNU Affero General Public License, version 3,
13* as published by the Free Software Foundation with the following additional
14* term according to sec. 7:
15*
16* According to sec. 7 of the GNU Affero General Public License, version 3,
17* the terms of the AGPL are supplemented with the following terms:
18*
19* "Zarafa" is a registered trademark of Zarafa B.V.
20* "Z-Push" is a registered trademark of Zarafa Deutschland GmbH
21* The licensing of the Program under the AGPL does not imply a trademark license.
22* Therefore any rights, title and interest in our trademarks remain entirely with us.
23*
24* However, if you propagate an unmodified version of the Program you are
25* allowed to use the term "Z-Push" to indicate that you distribute the Program.
26* Furthermore you may use our trademarks where it is necessary to indicate
27* the intended purpose of a product or service provided you use it in accordance
28* with honest practices in industrial or commercial matters.
29* If you want to propagate modified versions of the Program under the name "Z-Push",
30* you may only do so if you have a written permission by Zarafa Deutschland GmbH
31* (to acquire a permission please contact Zarafa at trademark@zarafa.com).
32*
33* This program is distributed in the hope that it will be useful,
34* but WITHOUT ANY WARRANTY; without even the implied warranty of
35* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
36* GNU Affero General Public License for more details.
37*
38* You should have received a copy of the GNU Affero General Public License
39* along with this program.  If not, see <http://www.gnu.org/licenses/>.
40*
41* Consult LICENSE file for details
42************************************************/
43
44class ZPushAdmin {
45    /**
46     * //TODO resync of a foldertype for all users (e.g. Appointment)
47     */
48
49    /**
50     * List devices known to Z-Push.
51     * If no user is given, all devices are listed
52     *
53     * @param string    $user       devices of that user, if false all devices of all users
54     *
55     * @return array
56     * @access public
57     */
58    static public function ListDevices($user = false) {
59        return ZPush::GetStateMachine()->GetAllDevices($user);
60    }
61
62    /**
63     * List users of a device known to Z-Push.
64     *
65     * @param string    $devid      users of that device
66     *
67     * @return array
68     * @access public
69     */
70    static public function ListUsers($devid) {
71        try {
72            $devState = ZPush::GetStateMachine()->GetState($devid, IStateMachine::DEVICEDATA);
73
74            if ($devState instanceof StateObject && isset($devState->devices) && is_array($devState->devices))
75                return array_keys($devState->devices);
76            else
77                return array();
78        }
79        catch (StateNotFoundException $stnf) {
80            return array();
81        }
82    }
83
84    /**
85     * Returns details of a device like synctimes,
86     * policy and wipe status, synched folders etc
87     *
88     * @param string    $devid      device id
89     * @param string    $user       user to be looked up
90     *
91     * @return ASDevice object
92     * @access public
93     */
94    static public function GetDeviceDetails($devid, $user) {
95
96        try {
97            $device = new ASDevice($devid, ASDevice::UNDEFINED, $user, ASDevice::UNDEFINED);
98            $device->SetData(ZPush::GetStateMachine()->GetState($devid, IStateMachine::DEVICEDATA), false);
99            $device->StripData();
100
101            try {
102                $lastsync = SyncCollections::GetLastSyncTimeOfDevice($device);
103                if ($lastsync)
104                    $device->SetLastSyncTime($lastsync);
105            }
106            catch (StateInvalidException $sive) {
107                ZLog::Write(LOGLEVEL_WARN, sprintf("ZPushAdmin::GetDeviceDetails(): device '%s' of user '%s' has invalid states. Please sync to solve this issue.", $devid, $user));
108                $device->SetDeviceError("Invalid states. Please force synchronization!");
109            }
110
111            return $device;
112        }
113        catch (StateNotFoundException $e) {
114            ZLog::Write(LOGLEVEL_ERROR, sprintf("ZPushAdmin::GetDeviceDetails(): device '%s' of user '%s' can not be found", $devid, $user));
115            return false;
116        }
117    }
118
119    /**
120     * Wipes 'a' or all devices of a user.
121     * If no user is set, the device is generally wiped.
122     * If no device id is set, all devices of the user will be wiped.
123     * Device id or user must be set!
124     *
125     * @param string    $requestedBy    user which requested this operation
126     * @param string    $user           (opt)user of the device
127     * @param string    $devid          (opt) device id which should be wiped
128     *
129     * @return boolean
130     * @access public
131     */
132    static public function WipeDevice($requestedBy, $user, $devid = false) {
133        if ($user === false && $devid === false)
134            return false;
135
136        if ($devid === false) {
137            $devicesIds = ZPush::GetStateMachine()->GetAllDevices($user);
138            ZLog::Write(LOGLEVEL_DEBUG, sprintf("ZPushAdmin::WipeDevice(): all '%d' devices for user '%s' found to be wiped", count($devicesIds), $user));
139            foreach ($devicesIds as $deviceid) {
140                if (!self::WipeDevice($requestedBy, $user, $deviceid)) {
141                    ZLog::Write(LOGLEVEL_ERROR, sprintf("ZPushAdmin::WipeDevice(): wipe devices failed for device '%s' of user '%s'. Aborting.", $deviceid, $user));
142                    return false;
143                }
144            }
145        }
146
147        // wipe a device completely (for connected users to this device)
148        else if ($devid !== false && $user === false) {
149            $users = self::ListUsers($devid);
150            ZLog::Write(LOGLEVEL_DEBUG, sprintf("ZPushAdmin::WipeDevice(): device '%d' is used by '%d' users and will be wiped", $devid, count($users)));
151            if (count($users) == 0)
152                ZLog::Write(LOGLEVEL_ERROR, sprintf("ZPushAdmin::WipeDevice(): no user found on device '%s'. Aborting.", $devid));
153
154            return self::WipeDevice($requestedBy, $users[0], $devid);
155        }
156
157        else {
158            // load device data
159            $device = new ASDevice($devid, ASDevice::UNDEFINED, $user, ASDevice::UNDEFINED);
160            try {
161                $device->SetData(ZPush::GetStateMachine()->GetState($devid, IStateMachine::DEVICEDATA), false);
162            }
163            catch (StateNotFoundException $e) {
164                ZLog::Write(LOGLEVEL_ERROR, sprintf("ZPushAdmin::WipeDevice(): device '%s' of user '%s' can not be found", $devid, $user));
165                return false;
166            }
167
168            // set wipe status
169            if ($device->GetWipeStatus() == SYNC_PROVISION_RWSTATUS_WIPED)
170                ZLog::Write(LOGLEVEL_INFO, sprintf("ZPushAdmin::WipeDevice(): device '%s' of user '%s' was alread sucessfully remote wiped on %s", $devid , $user, strftime("%Y-%m-%d %H:%M", $device->GetWipeActionOn())));
171            else
172                $device->SetWipeStatus(SYNC_PROVISION_RWSTATUS_PENDING, $requestedBy);
173
174            // save device data
175            try {
176                if ($device->IsNewDevice()) {
177                    ZLog::Write(LOGLEVEL_ERROR, sprintf("ZPushAdmin::WipeDevice(): data of user '%s' not synchronized on device '%s'. Aborting.", $user, $devid));
178                    return false;
179                }
180
181                ZPush::GetStateMachine()->SetState($device->GetData(), $devid, IStateMachine::DEVICEDATA);
182                ZLog::Write(LOGLEVEL_DEBUG, sprintf("ZPushAdmin::WipeDevice(): device '%s' of user '%s' marked to be wiped", $devid, $user));
183            }
184            catch (StateNotFoundException $e) {
185                ZLog::Write(LOGLEVEL_ERROR, sprintf("ZPushAdmin::WipeDevice(): state for device '%s' of user '%s' can not be saved", $devid, $user));
186                return false;
187            }
188        }
189        return true;
190    }
191
192
193    /**
194     * Removes device details from the z-push directory.
195     * If device id is not set, all devices of a user are removed.
196     * If the user is not set, the details of the device (independently if used by several users) is removed.
197     * Device id or user must be set!
198     *
199     * @param string    $user           (opt) user of the device
200     * @param string    $devid          (opt) device id which should be wiped
201     *
202     * @return boolean
203     * @access public
204     */
205    static public function RemoveDevice($user = false, $devid = false) {
206        if ($user === false && $devid === false)
207            return false;
208
209        // remove all devices for user
210        if ($devid === false && $user !== false) {
211            $devicesIds = ZPush::GetStateMachine()->GetAllDevices($user);
212            ZLog::Write(LOGLEVEL_DEBUG, sprintf("ZPushAdmin::RemoveDevice(): all '%d' devices for user '%s' found to be removed", count($devicesIds), $user));
213            foreach ($devicesIds as $deviceid) {
214                if (!self::RemoveDevice($user, $deviceid)) {
215                    ZLog::Write(LOGLEVEL_ERROR, sprintf("ZPushAdmin::RemoveDevice(): removing devices failed for device '%s' of user '%s'. Aborting", $deviceid, $user));
216                    return false;
217                }
218            }
219        }
220        // remove a device completely (for connected users to this device)
221        else if ($devid !== false && $user === false) {
222            $users = self::ListUsers($devid);
223            ZLog::Write(LOGLEVEL_DEBUG, sprintf("ZPushAdmin::RemoveDevice(): device '%d' is used by '%d' users and will be removed", $devid, count($users)));
224            foreach ($users as $aUser) {
225                if (!self::RemoveDevice($aUser, $devid)) {
226                    ZLog::Write(LOGLEVEL_ERROR, sprintf("ZPushAdmin::RemoveDevice(): removing user '%s' from device '%s' failed. Aborting", $aUser, $devid));
227                    return false;
228                }
229            }
230        }
231
232        // user and deviceid set
233        else {
234            // load device data
235            $device = new ASDevice($devid, ASDevice::UNDEFINED, $user, ASDevice::UNDEFINED);
236            $devices = array();
237            try {
238                $devicedata = ZPush::GetStateMachine()->GetState($devid, IStateMachine::DEVICEDATA);
239                $device->SetData($devicedata, false);
240                $devices = $devicedata->devices;
241            }
242            catch (StateNotFoundException $e) {
243                ZLog::Write(LOGLEVEL_ERROR, sprintf("ZPushAdmin::RemoveDevice(): device '%s' of user '%s' can not be found", $devid, $user));
244                return false;
245            }
246
247            // remove all related states
248            foreach ($device->GetAllFolderIds() as $folderid)
249                StateManager::UnLinkState($device, $folderid);
250
251            // remove hierarchcache
252            StateManager::UnLinkState($device, false);
253
254            // remove backend storage permanent data
255            ZPush::GetStateMachine()->CleanStates($device->GetDeviceId(), IStateMachine::BACKENDSTORAGE, false, 99999999999);
256
257            // remove devicedata and unlink user from device
258            unset($devices[$user]);
259            if (isset($devicedata->devices))
260                $devicedata->devices = $devices;
261            ZPush::GetStateMachine()->UnLinkUserDevice($user, $devid);
262
263            // no more users linked for device - remove device data
264            if (count($devices) == 0)
265                ZPush::GetStateMachine()->CleanStates($devid, IStateMachine::DEVICEDATA, false);
266
267            // save data if something left
268            else
269                ZPush::GetStateMachine()->SetState($devicedata, $devid, IStateMachine::DEVICEDATA);
270
271            ZLog::Write(LOGLEVEL_DEBUG, sprintf("ZPushAdmin::RemoveDevice(): data of device '%s' of user '%s' removed", $devid, $user));
272        }
273        return true;
274    }
275
276
277    /**
278     * Marks a folder of a device of a user for re-synchronization
279     *
280     * @param string    $user           user of the device
281     * @param string    $devid          device id which should be wiped
282     * @param string    $folderid       if not set, hierarchy state is linked
283     *
284     * @return boolean
285     * @access public
286     */
287    static public function ResyncFolder($user, $devid, $folderid) {
288        // load device data
289        $device = new ASDevice($devid, ASDevice::UNDEFINED, $user, ASDevice::UNDEFINED);
290        try {
291            $device->SetData(ZPush::GetStateMachine()->GetState($devid, IStateMachine::DEVICEDATA), false);
292
293            if ($device->IsNewDevice()) {
294                ZLog::Write(LOGLEVEL_ERROR, sprintf("ZPushAdmin::ResyncFolder(): data of user '%s' not synchronized on device '%s'. Aborting.",$user, $devid));
295                return false;
296            }
297
298            // remove folder state
299            StateManager::UnLinkState($device, $folderid);
300
301            ZPush::GetStateMachine()->SetState($device->GetData(), $devid, IStateMachine::DEVICEDATA);
302            ZLog::Write(LOGLEVEL_DEBUG, sprintf("ZPushAdmin::ResyncFolder(): folder '%s' on device '%s' of user '%s' marked to be re-synchronized.", $devid, $user));
303        }
304        catch (StateNotFoundException $e) {
305            ZLog::Write(LOGLEVEL_ERROR, sprintf("ZPushAdmin::ResyncFolder(): state for device '%s' of user '%s' can not be found or saved", $devid, $user));
306            return false;
307        }
308    }
309
310
311    /**
312     * Marks a all folders synchronized to a device for re-synchronization
313     * If no user is set all user which are synchronized for a device are marked for re-synchronization.
314     * If no device id is set all devices of that user are marked for re-synchronization.
315     * If no user and no device are set then ALL DEVICES are marked for resynchronization (use with care!).
316     *
317     * @param string    $user           (opt) user of the device
318     * @param string    $devid          (opt)device id which should be wiped
319     *
320     * @return boolean
321     * @access public
322     */
323    static public function ResyncDevice($user, $devid = false) {
324
325        // search for target devices
326        if ($devid === false) {
327            $devicesIds = ZPush::GetStateMachine()->GetAllDevices($user);
328            ZLog::Write(LOGLEVEL_DEBUG, sprintf("ZPushAdmin::ResyncDevice(): all '%d' devices for user '%s' found to be re-synchronized", count($devicesIds), $user));
329            foreach ($devicesIds as $deviceid) {
330                if (!self::ResyncDevice($user, $deviceid)) {
331                    ZLog::Write(LOGLEVEL_ERROR, sprintf("ZPushAdmin::ResyncDevice(): wipe devices failed for device '%s' of user '%s'. Aborting", $deviceid, $user));
332                    return false;
333                }
334            }
335        }
336        else {
337            // get devicedata
338            try {
339                $devicedata = ZPush::GetStateMachine()->GetState($devid, IStateMachine::DEVICEDATA);
340            }
341            catch (StateNotFoundException $e) {
342                ZLog::Write(LOGLEVEL_ERROR, sprintf("ZPushAdmin::ResyncDevice(): state for device '%s' can not be found", $devid));
343                return false;
344
345            }
346
347            // loop through all users which currently use this device
348            if ($user === false && $devicedata instanceof StateObject && isset($devicedata->devices) &&
349                is_array($devicedata->devices) && count($devicedata->devices) > 1) {
350                foreach (array_keys($devicedata) as $aUser) {
351                    if (!self::ResyncDevice($aUser, $devid)) {
352                        ZLog::Write(LOGLEVEL_ERROR, sprintf("ZPushAdmin::ResyncDevice(): re-synchronization failed for device '%s' of user '%s'. Aborting", $devid, $aUser));
353                        return false;
354                    }
355                }
356            }
357
358            // load device data
359            $device = new ASDevice($devid, ASDevice::UNDEFINED, $user, ASDevice::UNDEFINED);
360            try {
361                $device->SetData($devicedata, false);
362
363                if ($device->IsNewDevice()) {
364                    ZLog::Write(LOGLEVEL_ERROR, sprintf("ZPushAdmin::ResyncDevice(): data of user '%s' not synchronized on device '%s'. Aborting.",$user, $devid));
365                    return false;
366                }
367
368                // delete all uuids
369                foreach ($device->GetAllFolderIds() as $folderid)
370                    StateManager::UnLinkState($device, $folderid);
371
372                // remove hierarchcache
373                StateManager::UnLinkState($device, false);
374
375                ZPush::GetStateMachine()->SetState($device->GetData(), $devid, IStateMachine::DEVICEDATA);
376
377                ZLog::Write(LOGLEVEL_DEBUG, sprintf("ZPushAdmin::ResyncDevice(): all folders synchronized to device '%s' of user '%s' marked to be re-synchronized.", $devid, $user));
378            }
379            catch (StateNotFoundException $e) {
380                ZLog::Write(LOGLEVEL_ERROR, sprintf("ZPushAdmin::ResyncDevice(): state for device '%s' of user '%s' can not be found or saved", $devid, $user));
381                return false;
382            }
383        }
384        return true;
385    }
386
387    /**
388     * Clears loop detection data
389     *
390     * @param string    $user           (opt) user which data should be removed - user may not be specified without device id
391     * @param string    $devid          (opt) device id which data to be removed
392     *
393     * @return boolean
394     * @access public
395     */
396    static public function ClearLoopDetectionData($user = false, $devid = false) {
397        $loopdetection = new LoopDetection();
398        return $loopdetection->ClearData($user, $devid);
399    }
400
401    /**
402     * Returns loop detection data of a user & device
403     *
404     * @param string    $user
405     * @param string    $devid
406     *
407     * @return array/boolean            returns false if data is not available
408     * @access public
409     */
410    static public function GetLoopDetectionData($user, $devid) {
411        $loopdetection = new LoopDetection();
412        return $loopdetection->GetCachedData($user, $devid);
413    }
414
415
416}
417
418?>
Note: See TracBrowser for help on using the repository browser.