PageRenderTime 64ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

/z-push-admin.php

http://github.com/xbgmsharp/sogosync
PHP | 604 lines | 399 code | 59 blank | 146 comment | 74 complexity | 9350b8c55f2faea946dd0597ad42f68d MD5 | raw file
Possible License(s): AGPL-3.0
  1. #!/usr/bin/php
  2. <?php
  3. /***********************************************
  4. * File : z-push-admin.php
  5. * Project : Z-Push
  6. * Descr : This is a small command line
  7. * client to see and modify the
  8. * wipe status of Zarafa users.
  9. *
  10. * Created : 14.05.2010
  11. *
  12. * Copyright 2007 - 2012 Zarafa Deutschland GmbH
  13. *
  14. * This program is free software: you can redistribute it and/or modify
  15. * it under the terms of the GNU Affero General Public License, version 3,
  16. * as published by the Free Software Foundation with the following additional
  17. * term according to sec. 7:
  18. *
  19. * According to sec. 7 of the GNU Affero General Public License, version 3,
  20. * the terms of the AGPL are supplemented with the following terms:
  21. *
  22. * "Zarafa" is a registered trademark of Zarafa B.V.
  23. * "Z-Push" is a registered trademark of Zarafa Deutschland GmbH
  24. * The licensing of the Program under the AGPL does not imply a trademark license.
  25. * Therefore any rights, title and interest in our trademarks remain entirely with us.
  26. *
  27. * However, if you propagate an unmodified version of the Program you are
  28. * allowed to use the term "Z-Push" to indicate that you distribute the Program.
  29. * Furthermore you may use our trademarks where it is necessary to indicate
  30. * the intended purpose of a product or service provided you use it in accordance
  31. * with honest practices in industrial or commercial matters.
  32. * If you want to propagate modified versions of the Program under the name "Z-Push",
  33. * you may only do so if you have a written permission by Zarafa Deutschland GmbH
  34. * (to acquire a permission please contact Zarafa at trademark@zarafa.com).
  35. *
  36. * This program is distributed in the hope that it will be useful,
  37. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  38. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  39. * GNU Affero General Public License for more details.
  40. *
  41. * You should have received a copy of the GNU Affero General Public License
  42. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  43. *
  44. * Consult LICENSE file for details
  45. ************************************************/
  46. include('lib/core/zpushdefs.php');
  47. include('lib/core/zpush.php');
  48. include('lib/core/stateobject.php');
  49. include('lib/core/syncparameters.php');
  50. include('lib/core/bodypreference.php');
  51. include('lib/core/contentparameters.php');
  52. include('lib/core/synccollections.php');
  53. include('lib/core/zlog.php');
  54. include('lib/core/statemanager.php');
  55. include('lib/core/streamer.php');
  56. include('lib/core/asdevice.php');
  57. include('lib/core/interprocessdata.php');
  58. include('lib/core/loopdetection.php');
  59. include('lib/exceptions/exceptions.php');
  60. include('lib/utils/utils.php');
  61. include('lib/utils/zpushadmin.php');
  62. include('lib/request/request.php');
  63. include('lib/request/requestprocessor.php');
  64. include('lib/interface/ibackend.php');
  65. include('lib/interface/ichanges.php');
  66. include('lib/interface/iexportchanges.php');
  67. include('lib/interface/iimportchanges.php');
  68. include('lib/interface/isearchprovider.php');
  69. include('lib/interface/istatemachine.php');
  70. include('lib/syncobjects/syncobject.php');
  71. include('lib/syncobjects/syncbasebody.php');
  72. include('lib/syncobjects/syncbaseattachment.php');
  73. include('lib/syncobjects/syncmailflags.php');
  74. include('lib/syncobjects/syncrecurrence.php');
  75. include('lib/syncobjects/syncappointment.php');
  76. include('lib/syncobjects/syncappointmentexception.php');
  77. include('lib/syncobjects/syncattachment.php');
  78. include('lib/syncobjects/syncattendee.php');
  79. include('lib/syncobjects/syncmeetingrequestrecurrence.php');
  80. include('lib/syncobjects/syncmeetingrequest.php');
  81. include('lib/syncobjects/syncmail.php');
  82. include('lib/syncobjects/syncnote.php');
  83. include('lib/syncobjects/synccontact.php');
  84. include('lib/syncobjects/syncfolder.php');
  85. include('lib/syncobjects/syncprovisioning.php');
  86. include('lib/syncobjects/synctaskrecurrence.php');
  87. include('lib/syncobjects/synctask.php');
  88. include('lib/syncobjects/syncoofmessage.php');
  89. include('lib/syncobjects/syncoof.php');
  90. include('lib/syncobjects/syncuserinformation.php');
  91. include('lib/syncobjects/syncdeviceinformation.php');
  92. include('lib/syncobjects/syncdevicepassword.php');
  93. include('lib/syncobjects/syncitemoperationsattachment.php');
  94. include('config.php');
  95. include('version.php');
  96. /**
  97. * //TODO resync of single folders of a users device
  98. */
  99. /************************************************
  100. * MAIN
  101. */
  102. define('BASE_PATH_CLI', dirname(__FILE__) ."/");
  103. set_include_path(get_include_path() . PATH_SEPARATOR . BASE_PATH_CLI);
  104. try {
  105. ZPush::CheckConfig();
  106. ZPushAdminCLI::CheckEnv();
  107. ZPushAdminCLI::CheckOptions();
  108. if (! ZPushAdminCLI::SureWhatToDo()) {
  109. // show error message if available
  110. if (ZPushAdminCLI::GetErrorMessage())
  111. echo "ERROR: ". ZPushAdminCLI::GetErrorMessage() . "\n";
  112. echo ZPushAdminCLI::UsageInstructions();
  113. exit(1);
  114. }
  115. ZPushAdminCLI::RunCommand();
  116. }
  117. catch (ZPushException $zpe) {
  118. die(get_class($zpe) . ": ". $zpe->getMessage() . "\n");
  119. }
  120. /************************************************
  121. * Z-Push-Admin CLI
  122. */
  123. class ZPushAdminCLI {
  124. const COMMAND_SHOWALLDEVICES = 1;
  125. const COMMAND_SHOWDEVICESOFUSER = 2;
  126. const COMMAND_SHOWUSERSOFDEVICE = 3;
  127. const COMMAND_WIPEDEVICE = 4;
  128. const COMMAND_REMOVEDEVICE = 5;
  129. const COMMAND_RESYNCDEVICE = 6;
  130. const COMMAND_CLEARLOOP = 7;
  131. static private $command;
  132. static private $user = false;
  133. static private $device = false;
  134. static private $errormessage;
  135. /**
  136. * Returns usage instructions
  137. *
  138. * @return string
  139. * @access public
  140. */
  141. static public function UsageInstructions() {
  142. return "Usage:\n\tz-push-admin.php -a ACTION [options]\n\n" .
  143. "Parameters:\n\t-a list/wipe/remove/resync/clearloop\n\t[-u] username\n\t[-d] deviceid\n\n" .
  144. "Actions:\n\tlist\t\t\t\t Lists all devices and synchronized users\n" .
  145. "\tlist -u USER\t\t\t Lists all devices of user USER\n" .
  146. "\tlist -d DEVICE\t\t\t Lists all users of device DEVICE\n" .
  147. "\twipe -u USER\t\t\t Remote wipes all devices of user USER\n" .
  148. "\twipe -d DEVICE\t\t\t Remote wipes device DEVICE\n" .
  149. "\twipe -u USER -d DEVICE\t\t Remote wipes device DEVICE of user USER\n" .
  150. "\tremove -u USER\t\t\t Removes all state data of all devices of user USER\n" .
  151. "\tremove -d DEVICE\t\t Removes all state data of all users synchronized on device DEVICE\n" .
  152. "\tremove -u USER -d DEVICE\t Removes all related state data of device DEVICE of user USER\n" .
  153. "\tresync -u USER -d DEVICE\t Resynchronizes all data of device DEVICE of user USER\n" .
  154. "\tclearloop\t\t\t Clears system wide loop detection data\n" .
  155. "\tclearloop -d DEVICE -u USER\t Clears all loop detection data of a device DEVICE and an optional user USER\n" .
  156. "\n";
  157. }
  158. /**
  159. * Checks the environment
  160. *
  161. * @return
  162. * @access public
  163. */
  164. static public function CheckEnv() {
  165. if (!isset($_SERVER["TERM"]) || !isset($_SERVER["LOGNAME"]))
  166. self::$errormessage = "This script should not be called in a browser.";
  167. if (!function_exists("getopt"))
  168. self::$errormessage = "PHP Function getopt not found. Please check your PHP version and settings.";
  169. }
  170. /**
  171. * Checks the options from the command line
  172. *
  173. * @return
  174. * @access public
  175. */
  176. static public function CheckOptions() {
  177. if (self::$errormessage)
  178. return;
  179. $options = getopt("u:d:a:");
  180. // get 'user'
  181. if (isset($options['u']) && !empty($options['u']))
  182. self::$user = trim($options['u']);
  183. else if (isset($options['user']) && !empty($options['user']))
  184. self::$user = trim($options['user']);
  185. // get 'device'
  186. if (isset($options['d']) && !empty($options['d']))
  187. self::$device = trim($options['d']);
  188. else if (isset($options['device']) && !empty($options['device']))
  189. self::$device = trim($options['device']);
  190. // get 'action'
  191. $action = false;
  192. if (isset($options['a']) && !empty($options['a']))
  193. $action = strtolower(trim($options['a']));
  194. elseif (isset($options['action']) && !empty($options['action']))
  195. $action = strtolower(trim($options['action']));
  196. // get a command for the requested action
  197. switch ($action) {
  198. // list data
  199. case "list":
  200. if (self::$user === false && self::$device === false)
  201. self::$command = self::COMMAND_SHOWALLDEVICES;
  202. if (self::$user !== false)
  203. self::$command = self::COMMAND_SHOWDEVICESOFUSER;
  204. if (self::$device !== false)
  205. self::$command = self::COMMAND_SHOWUSERSOFDEVICE;
  206. break;
  207. // remove wipe device
  208. case "wipe":
  209. if (self::$user === false && self::$device === false)
  210. self::$errormessage = "Not possible to execute remote wipe. Device, user or both must be specified.";
  211. else
  212. self::$command = self::COMMAND_WIPEDEVICE;
  213. break;
  214. // remove device data of user
  215. case "remove":
  216. if (self::$user === false && self::$device === false)
  217. self::$errormessage = "Not possible to remove data. Device, user or both must be specified.";
  218. else
  219. self::$command = self::COMMAND_REMOVEDEVICE;
  220. break;
  221. // resync a device
  222. case "resync":
  223. case "re-sync":
  224. case "sync":
  225. case "resynchronize":
  226. case "re-synchronize":
  227. case "synchronize":
  228. if (self::$user === false || self::$device === false)
  229. self::$errormessage = "Not possible to resynchronize device. Device and user must be specified.";
  230. else
  231. self::$command = self::COMMAND_RESYNCDEVICE;
  232. break;
  233. // clear loop detection data
  234. case "clearloop":
  235. case "clearloopdetection":
  236. self::$command = self::COMMAND_CLEARLOOP;
  237. break;
  238. default:
  239. self::UsageInstructions();
  240. }
  241. }
  242. /**
  243. * Indicates if the options from the command line
  244. * could be processed correctly
  245. *
  246. * @return boolean
  247. * @access public
  248. */
  249. static public function SureWhatToDo() {
  250. return isset(self::$command);
  251. }
  252. /**
  253. * Returns a errormessage of things which could have gone wrong
  254. *
  255. * @return string
  256. * @access public
  257. */
  258. static public function GetErrorMessage() {
  259. return (isset(self::$errormessage))?self::$errormessage:"";
  260. }
  261. /**
  262. * Runs a command requested from an action of the command line
  263. *
  264. * @return
  265. * @access public
  266. */
  267. static public function RunCommand() {
  268. echo "\n";
  269. switch(self::$command) {
  270. case self::COMMAND_SHOWALLDEVICES:
  271. self::CommandShowDevices();
  272. break;
  273. case self::COMMAND_SHOWDEVICESOFUSER:
  274. self::CommandShowDevices();
  275. break;
  276. case self::COMMAND_SHOWUSERSOFDEVICE:
  277. self::CommandDeviceUsers();
  278. break;
  279. case self::COMMAND_WIPEDEVICE:
  280. if (self::$device)
  281. echo sprintf("Are you sure you want to REMOTE WIPE device '%s' [y/N]: ", self::$device);
  282. else
  283. echo sprintf("Are you sure you want to REMOTE WIPE all devices of user '%s' [y/N]: ", self::$user);
  284. $confirm = strtolower(trim(fgets(STDIN)));
  285. if ( $confirm === 'y' || $confirm === 'yes')
  286. self::CommandWipeDevice();
  287. else
  288. echo "Aborted!\n";
  289. break;
  290. case self::COMMAND_REMOVEDEVICE:
  291. self::CommandRemoveDevice();
  292. break;
  293. case self::COMMAND_RESYNCDEVICE:
  294. if (self::$device == false) {
  295. echo sprintf("Are you sure you want to re-synchronize all devices of user '%s' [y/N]: ", self::$user);
  296. $confirm = strtolower(trim(fgets(STDIN)));
  297. if ( !($confirm === 'y' || $confirm === 'yes'))
  298. echo "Aborted!\n";
  299. exit(1);
  300. }
  301. self::CommandResyncDevices();
  302. break;
  303. case self::COMMAND_CLEARLOOP:
  304. self::CommandClearLoopDetectionData();
  305. break;
  306. }
  307. echo "\n";
  308. }
  309. /**
  310. * Command "Show all devices" and "Show devices of user"
  311. * Prints the device id of/and connected users
  312. *
  313. * @return
  314. * @access public
  315. */
  316. static public function CommandShowDevices() {
  317. $devicelist = ZPushAdmin::ListDevices(self::$user);
  318. if (empty($devicelist))
  319. echo "\tno devices found\n";
  320. else {
  321. if (self::$user === false) {
  322. echo "All synchronized devices\n\n";
  323. echo str_pad("Device id", 36). "Synchronized users\n";
  324. echo "-----------------------------------------------------\n";
  325. }
  326. else
  327. echo "Synchronized devices of user: ". self::$user. "\n";
  328. }
  329. foreach ($devicelist as $deviceId) {
  330. if (self::$user === false) {
  331. echo str_pad($deviceId, 36) . implode (",", ZPushAdmin::ListUsers($deviceId)) ."\n";
  332. }
  333. else
  334. self::printDeviceData($deviceId, self::$user);
  335. }
  336. }
  337. /**
  338. * Command "Show users of device"
  339. * Prints informations about all users which use a device
  340. *
  341. * @return
  342. * @access public
  343. */
  344. static public function CommandDeviceUsers() {
  345. $users = ZPushAdmin::ListUsers(self::$device);
  346. if (empty($users))
  347. echo "\tno user data synchronized to device\n";
  348. foreach ($users as $user) {
  349. echo "Synchronized by user: ". $user. "\n";
  350. self::printDeviceData(self::$device, $user);
  351. }
  352. }
  353. /**
  354. * Command "Wipe device"
  355. * Marks a device of that user to be remotely wiped
  356. *
  357. * @return
  358. * @access public
  359. */
  360. static public function CommandWipeDevice() {
  361. $stat = ZPushAdmin::WipeDevice($_SERVER["LOGNAME"], self::$user, self::$device);
  362. if (self::$user !== false && self::$device !== false) {
  363. echo sprintf("Mark device '%s' of user '%s' to be wiped: %s", self::$device, self::$user, ($stat)?'OK':ZLog::GetLastMessage(LOGLEVEL_ERROR)). "\n";
  364. if ($stat) {
  365. echo "Updated information about this device:\n";
  366. self::printDeviceData(self::$device, self::$user);
  367. }
  368. }
  369. elseif (self::$user !== false) {
  370. echo sprintf("Mark devices of user '%s' to be wiped: %s", self::$user, ($stat)?'OK':ZLog::GetLastMessage(LOGLEVEL_ERROR)). "\n";
  371. self::CommandShowDevices();
  372. }
  373. }
  374. /**
  375. * Command "Remove device"
  376. * Remove a device of that user from the device list
  377. *
  378. * @return
  379. * @access public
  380. */
  381. static public function CommandRemoveDevice() {
  382. $stat = ZPushAdmin::RemoveDevice(self::$user, self::$device);
  383. if (self::$user === false)
  384. echo sprintf("State data of device '%s' removed: %s", self::$device, ($stat)?'OK':ZLog::GetLastMessage(LOGLEVEL_ERROR)). "\n";
  385. elseif (self::$device === false)
  386. echo sprintf("State data of all devices of user '%s' removed: %s", self::$user, ($stat)?'OK':ZLog::GetLastMessage(LOGLEVEL_ERROR)). "\n";
  387. else
  388. echo sprintf("State data of device '%s' of user '%s' removed: %s", self::$device, self::$user, ($stat)?'OK':ZLog::GetLastMessage(LOGLEVEL_ERROR)). "\n";
  389. }
  390. /**
  391. * Command "Resync device(s)"
  392. * Resyncs one or all devices of that user
  393. *
  394. * @return
  395. * @access public
  396. */
  397. static public function CommandResyncDevices() {
  398. $stat = ZPushAdmin::ResyncDevice(self::$user, self::$device);
  399. echo sprintf("Resync of device '%s' of user '%s': %s", self::$device, self::$user, ($stat)?'Requested':ZLog::GetLastMessage(LOGLEVEL_ERROR)). "\n";
  400. }
  401. static public function CommandClearLoopDetectionData() {
  402. $stat = false;
  403. $stat = ZPushAdmin::ClearLoopDetectionData(self::$user, self::$device);
  404. if (self::$user === false && self::$device === false)
  405. echo sprintf("System wide loop detection data removed: %s", ($stat)?'OK':ZLog::GetLastMessage(LOGLEVEL_ERROR)). "\n";
  406. elseif (self::$user === false)
  407. echo sprintf("Loop detection data of device '%s' removed: %s", self::$device, ($stat)?'OK':ZLog::GetLastMessage(LOGLEVEL_ERROR)). "\n";
  408. elseif (self::$device === false && self::$user !== false)
  409. echo sprintf("Error: %s", ($stat)?'OK':ZLog::GetLastMessage(LOGLEVEL_WARN)). "\n";
  410. else
  411. echo sprintf("Loop detection data of device '%s' of user '%s' removed: %s", self::$device, self::$user, ($stat)?'OK':ZLog::GetLastMessage(LOGLEVEL_ERROR)). "\n";
  412. }
  413. /**
  414. * Prints detailed informations about a device
  415. *
  416. * @param string $deviceId the id of the device
  417. *
  418. * @return
  419. * @access private
  420. */
  421. static private function printDeviceData($deviceId, $user) {
  422. $device = ZPushAdmin::GetDeviceDetails($deviceId, $user);
  423. if (! $device instanceof ASDevice)
  424. return false;
  425. // Gather some statistics about synchronized folders
  426. $folders = $device->GetAllFolderIds();
  427. $synchedFolders = 0;
  428. $synchedFolderTypes = array();
  429. foreach ($folders as $folderid) {
  430. if ($device->GetFolderUUID($folderid)) {
  431. $synchedFolders++;
  432. $type = $device->GetFolderType($folderid);
  433. switch($type) {
  434. case SYNC_FOLDER_TYPE_APPOINTMENT:
  435. case SYNC_FOLDER_TYPE_USER_APPOINTMENT:
  436. $gentype = "Calendars";
  437. break;
  438. case SYNC_FOLDER_TYPE_CONTACT:
  439. case SYNC_FOLDER_TYPE_USER_CONTACT:
  440. $gentype = "Contacts";
  441. break;
  442. case SYNC_FOLDER_TYPE_TASK:
  443. case SYNC_FOLDER_TYPE_USER_TASK:
  444. $gentype = "Tasks";
  445. break;
  446. case SYNC_FOLDER_TYPE_NOTE:
  447. case SYNC_FOLDER_TYPE_USER_NOTE:
  448. $gentype = "Notes";
  449. break;
  450. default:
  451. $gentype = "Emails";
  452. break;
  453. }
  454. if (!isset($synchedFolderTypes[$gentype]))
  455. $synchedFolderTypes[$gentype] = 0;
  456. $synchedFolderTypes[$gentype]++;
  457. }
  458. }
  459. $folderinfo = "";
  460. foreach ($synchedFolderTypes as $gentype=>$count) {
  461. $folderinfo .= $gentype;
  462. if ($count>1) $folderinfo .= "($count)";
  463. $folderinfo .= " ";
  464. }
  465. if (!$folderinfo) $folderinfo = "None available";
  466. echo "-----------------------------------------------------\n";
  467. echo "DeviceId:\t\t$deviceId\n";
  468. echo "Device type:\t\t". ($device->GetDeviceType() !== ASDevice::UNDEFINED ? $device->GetDeviceType() : "unknown") ."\n";
  469. echo "UserAgent:\t\t".($device->GetDeviceUserAgent()!== ASDevice::UNDEFINED ? $device->GetDeviceUserAgent() : "unknown") ."\n";
  470. // TODO implement $device->GetDeviceUserAgentHistory()
  471. // device information transmitted during Settings command
  472. if ($device->GetDeviceModel())
  473. echo "Device Model:\t\t". $device->GetDeviceModel(). "\n";
  474. if ($device->GetDeviceIMEI())
  475. echo "Device IMEI:\t\t". $device->GetDeviceIMEI(). "\n";
  476. if ($device->GetDeviceFriendlyName())
  477. echo "Device friendly name:\t". $device->GetDeviceFriendlyName(). "\n";
  478. if ($device->GetDeviceOS())
  479. echo "Device OS:\t\t". $device->GetDeviceOS(). "\n";
  480. if ($device->GetDeviceOSLanguage())
  481. echo "Device OS Language:\t". $device->GetDeviceOSLanguage(). "\n";
  482. if ($device->GetDevicePhoneNumber())
  483. echo "Device Phone nr:\t". $device->GetDevicePhoneNumber(). "\n";
  484. if ($device->GetDeviceMobileOperator())
  485. echo "Device Operator:\t\t". $device->GetDeviceMobileOperator(). "\n";
  486. if ($device->GetDeviceEnableOutboundSMS())
  487. echo "Device Outbound SMS:\t". $device->GetDeviceEnableOutboundSMS(). "\n";
  488. echo "ActiveSync version:\t".($device->GetASVersion() ? $device->GetASVersion() : "unknown") ."\n";
  489. echo "First sync:\t\t". strftime("%Y-%m-%d %H:%M", $device->GetFirstSyncTime()) ."\n";
  490. echo "Last sync:\t\t". ($device->GetLastSyncTime() ? strftime("%Y-%m-%d %H:%M", $device->GetLastSyncTime()) : "never")."\n";
  491. echo "Total folders:\t\t". count($folders). "\n";
  492. echo "Synchronized folders:\t". $synchedFolders . "\n";
  493. echo "Synchronized data:\t$folderinfo\n";
  494. echo "Status:\t\t\t";
  495. switch ($device->GetWipeStatus()) {
  496. case SYNC_PROVISION_RWSTATUS_OK:
  497. echo "OK\n";
  498. break;
  499. case SYNC_PROVISION_RWSTATUS_PENDING:
  500. echo "Pending wipe\n";
  501. break;
  502. case SYNC_PROVISION_RWSTATUS_REQUESTED:
  503. echo "Wipe requested on device\n";
  504. break;
  505. case SYNC_PROVISION_RWSTATUS_WIPED:
  506. echo "Wiped\n";
  507. break;
  508. default:
  509. echo "Not available\n";
  510. break;
  511. }
  512. echo "WipeRequest on:\t\t". ($device->GetWipeRequestedOn() ? strftime("%Y-%m-%d %H:%M", $device->GetWipeRequestedOn()) : "not set")."\n";
  513. echo "WipeRequest by:\t\t". ($device->GetWipeRequestedBy() ? $device->GetWipeRequestedBy() : "not set")."\n";
  514. echo "Wiped on:\t\t". ($device->GetWipeActionOn() ? strftime("%Y-%m-%d %H:%M", $device->GetWipeActionOn()) : "not set")."\n";
  515. echo "Attention needed:\t";
  516. if ($device->GetDeviceError())
  517. echo $device->GetDeviceError() ."\n";
  518. else if (!isset($device->ignoredmessages) || empty($device->ignoredmessages)) {
  519. echo "No errors known\n";
  520. }
  521. else {
  522. printf("%d messages need attention because they could not be synchronized\n", count($device->ignoredmessages));
  523. foreach ($device->ignoredmessages as $im) {
  524. $info = "";
  525. if (isset($im->asobject->subject))
  526. $info .= sprintf("Subject: '%s'", $im->asobject->subject);
  527. if (isset($im->asobject->fileas))
  528. $info .= sprintf("FileAs: '%s'", $im->asobject->fileas);
  529. if (isset($im->asobject->from))
  530. $info .= sprintf(" - From: '%s'", $im->asobject->from);
  531. if (isset($im->asobject->starttime))
  532. $info .= sprintf(" - On: '%s'", strftime("%Y-%m-%d %H:%M", $im->asobject->starttime));
  533. $reason = $im->reasonstring;
  534. if ($im->reasoncode == 2)
  535. $reason = "Message was causing loop";
  536. printf("\tBroken object:\t'%s' ignored on '%s'\n", $im->asclass, strftime("%Y-%m-%d %H:%M", $im->timestamp));
  537. printf("\tInformation:\t%s\n", $info);
  538. printf("\tReason: \t%s (%s)\n", $reason, $im->reasoncode);
  539. printf("\tItem/Parent id: %s/%s\n", $im->id, $im->folderid);
  540. echo "\n";
  541. }
  542. }
  543. }
  544. }
  545. ?>