Commit 7615d604 authored by Sebastian Kummer's avatar Sebastian Kummer

Merge pull request #248 in ZP/z-push from develop to release/2.3

* commit 'df6fc45e':
  ZP-891 Show folderstats log in LOGLEVEL_DEBUG.
  ZP-939 Now with file.
  ZP-939 ZPushAdmin::GetDeviceDetails() should load all states (also the hierarchy cache), mark the KOE GAB folder as gab in the overview of folders of z-push-admin, show folder name of currently synchronizing folders.
  ZP-937 Warn on mutex block only if it takes longer than 50ms.
  ZP-936 Only read 4 additional bytes when we need to truncate and are at end of stream.
  ZP-933 Now with file.
  ZP-933 Fixed wording in ZPushAdmin::ResyncFolder() if no folderid has been submitted for resynching, removed always false check, always strtolower() the searchFor as well.
  ZP-934 Use is_resource() to check the stream, check if categories are set before intersecting.
  ZP-935 Check if ASDevice changed before saving it.
  ZP-933 Added "gab" option for resync type, lookup gab folderid in configuration or device data, fixed resynching long and short folderids, to lookup folderids from backendIds stripdata should not unset backend2folderidCache.
  ZP-250 Fixed typo in Terminate output message.
parents 4ca1d4f0 df6fc45e
...@@ -193,7 +193,7 @@ class IpcMemcachedProvider implements IIpcProvider { ...@@ -193,7 +193,7 @@ class IpcMemcachedProvider implements IIpcProvider {
return false; return false;
} }
} }
if ($n) { if ($n*MEMCACHED_BLOCK_WAIT > 50) {
ZLog::Write(LOGLEVEL_WARN, sprintf("IpcMemcachedProvider->BlockMutex() mutex aquired after waiting for %sms for type: %s", ($n*MEMCACHED_BLOCK_WAIT), $this->type)); ZLog::Write(LOGLEVEL_WARN, sprintf("IpcMemcachedProvider->BlockMutex() mutex aquired after waiting for %sms for type: %s", ($n*MEMCACHED_BLOCK_WAIT), $this->type));
} }
return true; return true;
......
...@@ -1417,7 +1417,7 @@ class BackendKopano implements IBackend, ISearchProvider { ...@@ -1417,7 +1417,7 @@ class BackendKopano implements IBackend, ISearchProvider {
ZLog::Write(LOGLEVEL_DEBUG, sprintf("KopanoBackend->GetFolderStat() fetched status information of %d folders for store '%s'", count($this->folderStatCache[$user]), $user)); ZLog::Write(LOGLEVEL_DEBUG, sprintf("KopanoBackend->GetFolderStat() fetched status information of %d folders for store '%s'", count($this->folderStatCache[$user]), $user));
// TODO remove logging // TODO remove logging
foreach($this->folderStatCache[$user] as $fid => $stat) { foreach($this->folderStatCache[$user] as $fid => $stat) {
ZLog::Write(LOGLEVEL_INFO, sprintf("FolderStat: %s %s %s\t%s", $user, $fid, $stat, $this->nameCache[$fid])); ZLog::Write(LOGLEVEL_DEBUG, sprintf("FolderStat: %s %s %s\t%s", $user, $fid, $stat, $this->nameCache[$fid]));
} }
} }
......
...@@ -2459,7 +2459,7 @@ class MAPIProvider { ...@@ -2459,7 +2459,7 @@ class MAPIProvider {
$addrbook = $this->getAddressbook(); $addrbook = $this->getAddressbook();
$stream = mapi_inetmapi_imtoinet($this->session, $addrbook, $mapimessage, array('use_tnef' => -1)); $stream = mapi_inetmapi_imtoinet($this->session, $addrbook, $mapimessage, array('use_tnef' => -1));
if (isset($stream)) { if (is_resource($stream)) {
$mstreamstat = mapi_stream_stat($stream); $mstreamstat = mapi_stream_stat($stream);
$streamsize = $mstreamstat["cb"]; $streamsize = $mstreamstat["cb"];
if (isset($streamsize)) { if (isset($streamsize)) {
......
...@@ -100,8 +100,9 @@ class MAPIStreamWrapper { ...@@ -100,8 +100,9 @@ class MAPIStreamWrapper {
$len = ($this->position + $len > $this->streamlength) ? ($this->streamlength - $this->position) : $len; $len = ($this->position + $len > $this->streamlength) ? ($this->streamlength - $this->position) : $len;
// read 4 additional bytes from the stream so we can always truncate correctly // read 4 additional bytes from the stream so we can always truncate correctly
if ($this->toTruncate) if ($this->toTruncate && $this->position+$len >= $this->streamlength) {
$len += 4; $len += 4;
}
if ($this->mapistream) { if ($this->mapistream) {
$data = mapi_stream_read($this->mapistream, $len); $data = mapi_stream_read($this->mapistream, $len);
} }
...@@ -165,7 +166,7 @@ class MAPIStreamWrapper { ...@@ -165,7 +166,7 @@ class MAPIStreamWrapper {
* @param int $new_size * @param int $new_size
* @return boolean * @return boolean
*/ */
public function stream_truncate ($new_size) { public function stream_truncate($new_size) {
$this->streamlength = $new_size; $this->streamlength = $new_size;
$this->toTruncate = true; $this->toTruncate = true;
......
...@@ -204,7 +204,6 @@ class ASDevice extends StateObject { ...@@ -204,7 +204,6 @@ class ASDevice extends StateObject {
unset($this->forceSave); unset($this->forceSave);
unset($this->newdevice); unset($this->newdevice);
unset($this->ignoredMessageIds); unset($this->ignoredMessageIds);
unset($this->backend2folderidCache);
if (isset($this->ignoredmessages) && is_array($this->ignoredmessages)) { if (isset($this->ignoredmessages) && is_array($this->ignoredmessages)) {
$imessages = $this->ignoredmessages; $imessages = $this->ignoredmessages;
......
...@@ -127,10 +127,12 @@ class SyncNote extends SyncObject { ...@@ -127,10 +127,12 @@ class SyncNote extends SyncObject {
// is a color other than yellow set // is a color other than yellow set
if (isset($this->Color) && $this->Color != 3 && $this->Color > -1 && $this->Color < 5) { if (isset($this->Color) && $this->Color != 3 && $this->Color > -1 && $this->Color < 5) {
// check existing categories - do not rewrite category if the category is already a supported or unsupported color // check existing categories - do not rewrite category if the category is already a supported or unsupported color
$insecUnsupp = array_intersect($this->categories, array_values(self::$unsupportedColors)); if (!empty($this->categories)) {
$insecColors = array_intersect($this->categories, array_values(self::$colors)); $insecUnsupp = array_intersect($this->categories, array_values(self::$unsupportedColors));
if (!empty($this->categories) && (!empty($insecUnsupp) || !empty($insecColors))) { $insecColors = array_intersect($this->categories, array_values(self::$colors));
return false; if (!empty($insecUnsupp) || !empty($insecColors)) {
return false;
}
} }
if(!isset($this->categories)) { if(!isset($this->categories)) {
$this->categories = array(); $this->categories = array();
......
...@@ -106,8 +106,8 @@ class ZPushAdmin { ...@@ -106,8 +106,8 @@ class ZPushAdmin {
$sc = new SyncCollections(); $sc = new SyncCollections();
$sc->SetStateManager($stateManager); $sc->SetStateManager($stateManager);
// load all collections of device without loading states, checking permissions or loading the hierarchy // load all collections of device also loading states and loading hierarchy, but not checking permissions
$sc->LoadAllCollections(true, false, false, false); $sc->LoadAllCollections(true, true, false, true);
if ($sc->GetLastSyncTime()) if ($sc->GetLastSyncTime())
$device->SetLastSyncTime($sc->GetLastSyncTime()); $device->SetLastSyncTime($sc->GetLastSyncTime());
...@@ -326,7 +326,7 @@ class ZPushAdmin { ...@@ -326,7 +326,7 @@ class ZPushAdmin {
} }
if (!$folderid || (is_array($folderid) && empty($folderid))) { if (!$folderid || (is_array($folderid) && empty($folderid))) {
ZLog::Write(LOGLEVEL_ERROR, sprintf("ZPushAdmin::ResyncFolder(): no folders synchronized for user '%s' on device '%s'. Aborting.",$user, $devid)); ZLog::Write(LOGLEVEL_ERROR, sprintf("ZPushAdmin::ResyncFolder(): no folders requested for user '%s' on device '%s'. Aborting.",$user, $devid));
return false; return false;
} }
...@@ -342,6 +342,10 @@ class ZPushAdmin { ...@@ -342,6 +342,10 @@ class ZPushAdmin {
ZLog::Write(LOGLEVEL_DEBUG, sprintf("ZPushAdmin::ResyncFolder(): folder '%s' on device '%s' of user '%s' marked to be re-synchronized.", $folderid, $devid, $user)); ZLog::Write(LOGLEVEL_DEBUG, sprintf("ZPushAdmin::ResyncFolder(): folder '%s' on device '%s' of user '%s' marked to be re-synchronized.", $folderid, $devid, $user));
} }
if ($device->GetData() === false) {
ZLog::Write(LOGLEVEL_DEBUG, sprintf("ZPushAdmin::ResyncFolder(): nothing changed for device '%s' of user '%s'", $devid, $user));
return false;
}
ZPush::GetStateMachine()->SetState($device->GetData(), $devid, IStateMachine::DEVICEDATA); ZPush::GetStateMachine()->SetState($device->GetData(), $devid, IStateMachine::DEVICEDATA);
ZLog::Write(LOGLEVEL_DEBUG, sprintf("ZPushAdmin::ResyncFolder(): saved updated device data of device '%s' of user '%s'", $devid, $user)); ZLog::Write(LOGLEVEL_DEBUG, sprintf("ZPushAdmin::ResyncFolder(): saved updated device data of device '%s' of user '%s'", $devid, $user));
} }
......
...@@ -101,6 +101,7 @@ class ZPushAdminCLI { ...@@ -101,6 +101,7 @@ class ZPushAdminCLI {
const TYPE_OPTION_TASK = "task"; const TYPE_OPTION_TASK = "task";
const TYPE_OPTION_NOTE = "note"; const TYPE_OPTION_NOTE = "note";
const TYPE_OPTION_HIERARCHY = "hierarchy"; const TYPE_OPTION_HIERARCHY = "hierarchy";
const TYPE_OPTION_GAB = "gab";
static private $command; static private $command;
static private $user = false; static private $user = false;
...@@ -115,7 +116,6 @@ class ZPushAdminCLI { ...@@ -115,7 +116,6 @@ class ZPushAdminCLI {
* @access public * @access public
*/ */
static public function UsageInstructions() { static public function UsageInstructions() {
$types = "'".self::TYPE_OPTION_EMAIL."', '".self::TYPE_OPTION_CALENDAR."', '".self::TYPE_OPTION_CONTACT."', '".self::TYPE_OPTION_TASK."' or '".self::TYPE_OPTION_NOTE."'";
return "Usage:\n\tz-push-admin.php -a ACTION [options]\n\n" . return "Usage:\n\tz-push-admin.php -a ACTION [options]\n\n" .
"Parameters:\n\t-a list/wipe/remove/resync/clearloop\n\t[-u] username\n\t[-d] deviceid\n\n" . "Parameters:\n\t-a list/wipe/remove/resync/clearloop\n\t[-u] username\n\t[-d] deviceid\n\n" .
"Actions:\n" . "Actions:\n" .
...@@ -130,14 +130,16 @@ class ZPushAdminCLI { ...@@ -130,14 +130,16 @@ class ZPushAdminCLI {
"\tremove -d DEVICE\t\t\t Removes all state data of all users synchronized on device DEVICE\n" . "\tremove -d DEVICE\t\t\t Removes all state data of all users synchronized on device DEVICE\n" .
"\tremove -u USER -d DEVICE\t\t Removes all related state data of device DEVICE of user USER\n" . "\tremove -u USER -d DEVICE\t\t Removes all related state data of device DEVICE of user USER\n" .
"\tresync -u USER -d DEVICE\t\t Resynchronizes all data of device DEVICE of user USER\n" . "\tresync -u USER -d DEVICE\t\t Resynchronizes all data of device DEVICE of user USER\n" .
"\tresync -t TYPE \t\t\t\t Resynchronizes all folders of type $types for all devices and users.\n" . "\tresync -t TYPE \t\t\t\t Resynchronizes all folders of type (possible values below) for all devices and users.\n" .
"\tresync -t TYPE -u USER \t\t\t Resynchronizes all folders of type $types for the user USER.\n" . "\tresync -t TYPE -u USER \t\t\t Resynchronizes all folders of type (possible values below) for the user USER.\n" .
"\tresync -t TYPE -u USER -d DEVICE\t Resynchronizes all folders of type $types for a specified device and user.\n" . "\tresync -t TYPE -u USER -d DEVICE\t Resynchronizes all folders of type (possible values below) for a specified device and user.\n" .
"\tresync -t FOLDERID -u USER\t\t Resynchronize the specified folder id only. The USER should be specified for better performance.\n" . "\tresync -t FOLDERID -u USER\t\t Resynchronize the specified folder id only. The USER should be specified for better performance.\n" .
"\tresync -t hierarchy -u USER -d DEVICE\t Resynchronize the folder hierarchy data for an optional USER and optional DEVICE.\n" . "\tresync -t hierarchy -u USER -d DEVICE\t Resynchronize the folder hierarchy data for an optional USER and optional DEVICE.\n" .
"\tclearloop\t\t\t\t Clears system wide loop detection data\n" . "\tclearloop\t\t\t\t Clears system wide loop detection data\n" .
"\tclearloop -d DEVICE -u USER\t\t Clears all loop detection data of a device DEVICE and an optional user USER\n" . "\tclearloop -d DEVICE -u USER\t\t Clears all loop detection data of a device DEVICE and an optional user USER\n" .
"\tfixstates\t\t\t\t Checks the states for integrity and fixes potential issues\n" . "\tfixstates\t\t\t\t Checks the states for integrity and fixes potential issues\n" .
"\n" .
"\tPossible values for type:\n\t '".self::TYPE_OPTION_EMAIL."', '".self::TYPE_OPTION_CALENDAR."', '".self::TYPE_OPTION_CONTACT."', '".self::TYPE_OPTION_TASK."', '".self::TYPE_OPTION_NOTE."', '".self::TYPE_OPTION_HIERARCHY."' of '".self::TYPE_OPTION_GAB."' (for KOE)\n" .
"\n"; "\n";
} }
...@@ -200,11 +202,13 @@ class ZPushAdminCLI { ...@@ -200,11 +202,13 @@ class ZPushAdminCLI {
self::$type !== self::TYPE_OPTION_TASK && self::$type !== self::TYPE_OPTION_TASK &&
self::$type !== self::TYPE_OPTION_NOTE && self::$type !== self::TYPE_OPTION_NOTE &&
self::$type !== self::TYPE_OPTION_HIERARCHY && self::$type !== self::TYPE_OPTION_HIERARCHY &&
self::$type !== self::TYPE_OPTION_GAB &&
strlen(self::$type) !== 6 && // like U1f38d
strlen(self::$type) !== 44 && strlen(self::$type) !== 44 &&
strlen(self::$type) !== 48) { strlen(self::$type) !== 48) {
self::$errormessage = "Wrong 'type'. Possible values are: ". self::$errormessage = "Wrong 'type'. Possible values are: ".
"'".self::TYPE_OPTION_EMAIL."', '".self::TYPE_OPTION_CALENDAR."', '".self::TYPE_OPTION_CONTACT."', '".self::TYPE_OPTION_TASK."', '".self::TYPE_OPTION_NOTE."', ".self::TYPE_OPTION_HIERARCHY."' ". "'".self::TYPE_OPTION_EMAIL."', '".self::TYPE_OPTION_CALENDAR."', '".self::TYPE_OPTION_CONTACT."', '".self::TYPE_OPTION_TASK."', '".self::TYPE_OPTION_NOTE."', '".self::TYPE_OPTION_HIERARCHY."', '".self::TYPE_OPTION_GAB."' ".
"or a 44 or 48 byte long folder id (as hex)."; "or a 6, 44 or 48 byte long folder id (as hex).";
return; return;
} }
} }
...@@ -632,9 +636,27 @@ class ZPushAdminCLI { ...@@ -632,9 +636,27 @@ class ZPushAdminCLI {
} }
$folders = array(); $folders = array();
$searchFor = $type;
// get the KOE gab folderid
if ($type == self::TYPE_OPTION_GAB) {
if (@constant('KOE_GAB_FOLDERID') !== '') {
$gab = KOE_GAB_FOLDERID;
}
else {
$gab = $device->GetKoeGabBackendFolderId();
}
if (!$gab) {
printf("Could not find KOE GAB folderid for device '%s' of user '%s'\n", $deviceId, $user);
return false;
}
$searchFor = $gab;
}
// potential long ids are converted to folderids here, incl. the gab id
$searchFor = strtolower($device->GetFolderIdForBackendId($searchFor, false, false, null));
foreach ($device->GetAllFolderIds() as $folderid) { foreach ($device->GetAllFolderIds() as $folderid) {
// if submitting a folderid as type to resync a specific folder. // if submitting a folderid as type to resync a specific folder.
if ($folderid == $type || $device->GetFolderBackendId($folderid) === $type) { if (strtolower($folderid) === $searchFor) {
printf("Found and resynching requested folderid '%s' on device '%s' of user '%s'\n", $folderid, $deviceId, $user); printf("Found and resynching requested folderid '%s' on device '%s' of user '%s'\n", $folderid, $deviceId, $user);
$folders[] = $folderid; $folders[] = $folderid;
break; break;
...@@ -645,26 +667,26 @@ class ZPushAdminCLI { ...@@ -645,26 +667,26 @@ class ZPushAdminCLI {
switch($foldertype) { switch($foldertype) {
case SYNC_FOLDER_TYPE_APPOINTMENT: case SYNC_FOLDER_TYPE_APPOINTMENT:
case SYNC_FOLDER_TYPE_USER_APPOINTMENT: case SYNC_FOLDER_TYPE_USER_APPOINTMENT:
if ($type == "calendar") if ($searchFor == "calendar")
$folders[] = $folderid; $folders[] = $folderid;
break; break;
case SYNC_FOLDER_TYPE_CONTACT: case SYNC_FOLDER_TYPE_CONTACT:
case SYNC_FOLDER_TYPE_USER_CONTACT: case SYNC_FOLDER_TYPE_USER_CONTACT:
if ($type == "contact") if ($searchFor == "contact")
$folders[] = $folderid; $folders[] = $folderid;
break; break;
case SYNC_FOLDER_TYPE_TASK: case SYNC_FOLDER_TYPE_TASK:
case SYNC_FOLDER_TYPE_USER_TASK: case SYNC_FOLDER_TYPE_USER_TASK:
if ($type == "task") if ($searchFor == "task")
$folders[] = $folderid; $folders[] = $folderid;
break; break;
case SYNC_FOLDER_TYPE_NOTE: case SYNC_FOLDER_TYPE_NOTE:
case SYNC_FOLDER_TYPE_USER_NOTE: case SYNC_FOLDER_TYPE_USER_NOTE:
if ($type == "note") if ($searchFor == "note")
$folders[] = $folderid; $folders[] = $folderid;
break; break;
default: default:
if ($type == "email") if ($searchFor == "email")
$folders[] = $folderid; $folders[] = $folderid;
break; break;
} }
...@@ -672,7 +694,7 @@ class ZPushAdminCLI { ...@@ -672,7 +694,7 @@ class ZPushAdminCLI {
} }
$stat = ZPushAdmin::ResyncFolder($user, $deviceId, $folders); $stat = ZPushAdmin::ResyncFolder($user, $deviceId, $folders);
echo sprintf("Resync of %d folders of type %s on device '%s' of user '%s': %s\n", count($folders), $type, $deviceId, $user, ($stat)?'Requested':ZLog::GetLastMessage(LOGLEVEL_ERROR)); echo sprintf("Resync of %d folders of type '%s' on device '%s' of user '%s': %s\n", count($folders), $type, $deviceId, $user, ($stat)?'Requested':ZLog::GetLastMessage(LOGLEVEL_ERROR));
} }
/** /**
...@@ -750,10 +772,16 @@ class ZPushAdminCLI { ...@@ -750,10 +772,16 @@ class ZPushAdminCLI {
if ($device->GetFolderUUID($folderid)) { if ($device->GetFolderUUID($folderid)) {
$synchedFolders++; $synchedFolders++;
$type = $device->GetFolderType($folderid); $type = $device->GetFolderType($folderid);
$name = $device->GetHierarchyCache()->GetFolder($folderid)->displayname;
switch($type) { switch($type) {
case SYNC_FOLDER_TYPE_APPOINTMENT: case SYNC_FOLDER_TYPE_APPOINTMENT:
case SYNC_FOLDER_TYPE_USER_APPOINTMENT: case SYNC_FOLDER_TYPE_USER_APPOINTMENT:
$gentype = "Calendars"; if (KOE_GAB_NAME != "" && $name == KOE_GAB_NAME) {
$gentype = "GAB";
}
else {
$gentype = "Calendars";
}
break; break;
case SYNC_FOLDER_TYPE_CONTACT: case SYNC_FOLDER_TYPE_CONTACT:
case SYNC_FOLDER_TYPE_USER_CONTACT: case SYNC_FOLDER_TYPE_USER_CONTACT:
...@@ -778,8 +806,7 @@ class ZPushAdminCLI { ...@@ -778,8 +806,7 @@ class ZPushAdminCLI {
// set the folder name for all folders which are not fully synchronized yet // set the folder name for all folders which are not fully synchronized yet
$fstatus = $device->GetFolderSyncStatus($folderid); $fstatus = $device->GetFolderSyncStatus($folderid);
if ($fstatus !== false && is_array($fstatus)) { if ($fstatus !== false && is_array($fstatus)) {
// TODO would be nice if we could see the real name of the folder, right now we use the folder type as name $fstatus['name'] = $name ? $name : $gentype;
$fstatus['name'] = $gentype;
$device->SetFolderSyncStatus($folderid, $fstatus); $device->SetFolderSyncStatus($folderid, $fstatus);
$syncedFoldersInProgress++; $syncedFoldersInProgress++;
} }
...@@ -837,7 +864,10 @@ class ZPushAdminCLI { ...@@ -837,7 +864,10 @@ class ZPushAdminCLI {
$percent = round($d['done']*100/$d['total']); $percent = round($d['done']*100/$d['total']);
$status = sprintf("Status: %s%d%% (%d/%d)", ($percent < 10)?" ":"", $percent, $d['done'], $d['total']); $status = sprintf("Status: %s%d%% (%d/%d)", ($percent < 10)?" ":"", $percent, $d['done'], $d['total']);
} }
printf("\tFolder: %s%s Sync: %s %s\n", $d['name'], str_repeat(" ", 12-strlen($d['name'])), $d['status'], $status); if (strlen($d['name']) > 20) {
$d['name'] = substr($d['name'], 0, 18) . "..";
}
printf("\tFolder: %s Sync: %s %s\n", str_pad($d['name'], 20), str_pad($d['status'], 13), $status);
} }
} }
} }
......
...@@ -549,7 +549,7 @@ class Kopano extends SyncWorker { ...@@ -549,7 +549,7 @@ class Kopano extends SyncWorker {
$parentfolder = mapi_msgstore_openentry($this->store, $parentfentryid); $parentfolder = mapi_msgstore_openentry($this->store, $parentfentryid);
if (!$parentfolder) if (!$parentfolder)
$this->Terminate(sprintf("Kopano->CreateHiddenPublicFolder(): Error, unable to open parent folder (open entry): 0x%08X", mapi_last_hresult())); $this->Terminate(sprintf("Kopano->getRootFolder(): Error, unable to open parent folder (open entry): 0x%08X", mapi_last_hresult()));
$this->folderCache[$rootId] = $parentfolder; $this->folderCache[$rootId] = $parentfolder;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment