diff --git a/src/app/Backends/DAV.php b/src/app/Backends/DAV.php --- a/src/app/Backends/DAV.php +++ b/src/app/Backends/DAV.php @@ -75,8 +75,14 @@ $principal_href = substr($principal_href, strlen($path)); } + $ns = [ + 'xmlns:d="DAV:"', + 'xmlns:cal="urn:ietf:params:xml:ns:caldav"', + 'xmlns:card="urn:ietf:params:xml:ns:carddav"', + ]; + $body = '' - . '' + . '' . '' . '' . '' @@ -222,7 +228,13 @@ { $headers = ['Content-Type' => $object->contentType]; - $response = $this->request($object->href, 'PUT', $object, $headers); + $content = (string) $object; + + if (!strlen($content)) { + throw new \Exception("Cannot PUT an empty DAV object"); + } + + $response = $this->request($object->href, 'PUT', $content, $headers); if ($response !== false) { if (!empty($this->responseHeaders['ETag'])) { @@ -352,9 +364,9 @@ * * @param string $location Folder location * @param DAV\Search $search Search request parameters - * @param ?callable $callback Callback to execute on every object + * @param callable $callback A callback to execute on every item * - * @return false|array Objects metadata on success, False on error + * @return false|array List of objects on success, False on error */ public function search(string $location, DAV\Search $search, $callback = null) { @@ -376,7 +388,13 @@ $object = $callback($object); } - $objects[] = $object; + if ($object) { + if (is_array($object)) { + $objects[$object[0]] = $object[1]; + } else { + $objects[] = $object; + } + } } return $objects; @@ -387,7 +405,7 @@ * * @param string $location Folder location * @param string $component Object type (VEVENT, VTODO, VCARD) - * @param array $hrefs List of objects' locations to fetch (empty for all objects) + * @param array $hrefs List of objects' locations to fetch * * @return false|array Objects metadata on success, False on error */ diff --git a/src/app/Backends/DAV/Opaque.php b/src/app/Backends/DAV/Opaque.php --- a/src/app/Backends/DAV/Opaque.php +++ b/src/app/Backends/DAV/Opaque.php @@ -6,9 +6,13 @@ { protected $content; - public function __construct($filename) + public function __construct($content, $is_file = false) { - $this->content = file_get_contents($filename); + if ($is_file) { + $this->content = file_get_contents($content); + } else { + $this->content = $content; + } } /** diff --git a/src/app/Backends/DAV/Search.php b/src/app/Backends/DAV/Search.php --- a/src/app/Backends/DAV/Search.php +++ b/src/app/Backends/DAV/Search.php @@ -14,10 +14,13 @@ public $properties = []; + public $withContent = false; - public function __construct($component) + + public function __construct($component, $withContent = false) { $this->component = $component; + $this->withContent = $withContent; } /** @@ -55,6 +58,12 @@ . '' . implode('', $more_props) . '' . ''; } + } elseif ($this->withContent) { + if ($this->component == DAV::TYPE_VCARD) { + $props[] = ''; + } else { + $props[] = ''; + } } // Search filter @@ -63,8 +72,10 @@ $query = 'addressbook-query'; } else { $query = 'calendar-query'; - $filter = ''; - $filter = "{$filter}"; + $filter = '' + . '' + . '' + . ''; } if (empty($props)) { diff --git a/src/app/Backends/DAV/Vcard.php b/src/app/Backends/DAV/Vcard.php --- a/src/app/Backends/DAV/Vcard.php +++ b/src/app/Backends/DAV/Vcard.php @@ -5,14 +5,24 @@ use Illuminate\Support\Str; use Sabre\VObject\Reader; use Sabre\VObject\Property; +use Sabre\VObject\Writer; class Vcard extends CommonObject { /** @var string Object content type (of the string representation) */ public $contentType = 'text/vcard; charset=utf-8'; + public $class; + public $email = []; public $fn; + public $kind; + public $note; + public $members = []; + public $prodid; public $rev; + public $version; + + private $vobject; /** @@ -48,10 +58,18 @@ return; } + $this->vobject = $vobject; + $this->members = []; + $string_properties = [ + 'CLASS', 'FN', + 'KIND', + 'NOTE', + 'PRODID', 'REV', 'UID', + 'VERSION', ]; foreach ($vobject->children() as $prop) { @@ -62,6 +80,26 @@ switch ($prop->name) { // TODO: Map all vCard properties to class properties + case 'EMAIL': + $props = []; + foreach ($prop->parameters() as $name => $value) { + $key = Str::camel(strtolower($name)); + $props[$key] = (string) $value; + } + + $props['email'] = (string) $prop; + $this->email[] = $props; + break; + + case 'MEMBER': + foreach ($prop as $member) { + $value = (string) $member; + if (preg_match('/^mailto:/', $value)) { + $this->members[] = $value; + } + } + break; + default: // map string properties if (in_array($prop->name, $string_properties)) { @@ -75,6 +113,10 @@ } } } + + if (!empty($this->custom['X-ADDRESSBOOKSERVER-KIND']) && empty($this->kind)) { + $this->kind = strtolower($this->custom['X-ADDRESSBOOKSERVER-KIND']); + } } /** @@ -84,7 +126,11 @@ */ public function __toString() { - // TODO: This will be needed when we want to create/update objects - return ''; + if (!$this->vobject) { + // TODO we currently can only serialize a message back that we just read + throw new \Exception("Writing from properties is not implemented"); + } + + return Writer::write($this->vobject); } } diff --git a/src/app/Backends/DAV/Vevent.php b/src/app/Backends/DAV/Vevent.php --- a/src/app/Backends/DAV/Vevent.php +++ b/src/app/Backends/DAV/Vevent.php @@ -3,7 +3,10 @@ namespace App\Backends\DAV; use Illuminate\Support\Str; -use Sabre\VObject; +use Sabre\VObject\Component; +use Sabre\VObject\Reader; +use Sabre\VObject\Property; +use Sabre\VObject\Writer; class Vevent extends CommonObject { @@ -11,11 +14,16 @@ public $contentType = 'text/calendar; charset=utf-8'; public $attendees = []; + public $class; public $comment; public $description; + public $exdate = []; public $location; public $organizer; - public $recurrence = []; + public $priority; + public $prodid; + public $rdate = []; + public $rrule = []; public $sequence; public $status; public $summary; @@ -25,7 +33,6 @@ public $dtstart; public $dtend; - public $due; public $created; public $lastModified; public $dtstamp; @@ -59,8 +66,7 @@ */ protected function fromIcal(string $ical): void { - $options = VObject\Reader::OPTION_FORGIVING | VObject\Reader::OPTION_IGNORE_INVALID_LINES; - $this->vobject = VObject\Reader::read($ical, $options); + $this->vobject = Reader::read($ical, Reader::OPTION_FORGIVING | Reader::OPTION_IGNORE_INVALID_LINES); if ($this->vobject->name != 'VCALENDAR') { return; @@ -68,6 +74,10 @@ $selfType = strtoupper(class_basename(get_class($this))); + if (!empty($this->vobject->PRODID)) { + $this->prodid = (string) $this->vobject->PRODID; + } + foreach ($this->vobject->getComponents() as $component) { if ($component->name == $selfType) { $this->fromVObject($component); @@ -79,14 +89,16 @@ /** * Set object properties from a Sabre/VObject component object * - * @param VObject\Component $vobject Sabre/VObject component + * @param Component $vobject Sabre/VObject component */ - protected function fromVObject(VObject\Component $vobject): void + protected function fromVObject(Component $vobject): void { $string_properties = [ + 'CLASS', 'COMMENT', 'DESCRIPTION', 'LOCATION', + 'PRIORITY', 'SEQUENCE', 'STATUS', 'SUMMARY', @@ -105,14 +117,13 @@ // map other properties foreach ($vobject->children() as $prop) { - if (!($prop instanceof VObject\Property)) { + if (!($prop instanceof Property)) { continue; } switch ($prop->name) { case 'DTSTART': case 'DTEND': - case 'DUE': case 'CREATED': case 'LAST-MODIFIED': case 'DTSTAMP': @@ -122,7 +133,7 @@ break; case 'RRULE': - $params = !empty($this->recurrence) ? $this->recurrence : []; + $params = []; foreach ($prop->getParts() as $k => $v) { $params[Str::camel(strtolower($k))] = is_array($v) ? implode(',', $v) : $v; @@ -136,20 +147,14 @@ $params['interval'] = 1; } - $this->recurrence = array_filter($params); + $this->rrule = array_filter($params); break; case 'EXDATE': case 'RDATE': $key = strtolower($prop->name); - $dates = []; // TODO - - if (!empty($this->recurrence[$key])) { - $this->recurrence[$key] = array_merge($this->recurrence[$key], $dates); - } else { - $this->recurrence[$key] = $dates; - } + // TODO break; case 'ATTENDEE': @@ -166,14 +171,14 @@ $key = Str::camel(strtolower($name)); switch ($name) { case 'RSVP': - $params[$key] = strtolower($value) == 'true'; + $attendee[$key] = strtolower($value) == 'true'; break; case 'CN': - $params[$key] = str_replace('\,', ',', strval($value)); + $attendee[$key] = str_replace('\,', ',', strval($value)); break; default: if (in_array($name, $attendeeProps)) { - $params[$key] = strval($value); + $attendee[$key] = strval($value); } break; } @@ -281,9 +286,9 @@ public function __toString() { if (!$this->vobject) { - //TODO we currently can only serialize a message back that we just read + // TODO we currently can only serialize a message back that we just read throw new \Exception("Writing from properties is not implemented"); } - return VObject\Writer::write($this->vobject); + return Writer::write($this->vobject); } } diff --git a/src/app/Backends/DAV/Vtodo.php b/src/app/Backends/DAV/Vtodo.php --- a/src/app/Backends/DAV/Vtodo.php +++ b/src/app/Backends/DAV/Vtodo.php @@ -2,6 +2,52 @@ namespace App\Backends\DAV; +use Illuminate\Support\Str; +use Sabre\VObject\Component; +use Sabre\VObject\Property; + class Vtodo extends Vevent { + public $due; + public $percentComplete; + + /** + * Set object properties from a Sabre/VObject component object + * + * @param Component $vobject Sabre/VObject component + */ + protected function fromVObject(Component $vobject): void + { + // Handle common properties with VEVENT + parent::fromVObject($vobject); + + $string_properties = [ + ]; + + // map string properties + foreach ($string_properties as $prop) { + if (isset($vobject->{$prop})) { + $key = Str::camel(strtolower($prop)); + $this->{$key} = (string) $vobject->{$prop}; + } + } + + // map other properties + foreach ($vobject->children() as $prop) { + if (!($prop instanceof Property)) { + continue; + } + + switch ($prop->name) { + case 'DUE': + // This is of type Sabre\VObject\Property\ICalendar\DateTime + $this->due = $prop; + break; + + case 'PERCENT-COMPLETE': + $this->percentComplete = $prop->getValue(); + break; + } + } + } } diff --git a/src/app/Console/Commands/Data/MigrateCommand.php b/src/app/Console/Commands/Data/MigrateCommand.php --- a/src/app/Console/Commands/Data/MigrateCommand.php +++ b/src/app/Console/Commands/Data/MigrateCommand.php @@ -3,7 +3,6 @@ namespace App\Console\Commands\Data; use App\DataMigrator; - use Illuminate\Console\Command; /** @@ -13,7 +12,7 @@ * * ``` * php artisan data:migrate \ - * "ews://$user:$pass@$server?client_id=$client_id&client_secret=$client_secret&tenant_id=$tenant_id" \ + * "ews://$user@$server?client_id=$client_id&client_secret=$client_secret&tenant_id=$tenant_id" \ * "dav://$dest_user:$dest_pass@$dest_server" * ``` * diff --git a/src/app/DataMigrator/Account.php b/src/app/DataMigrator/Account.php --- a/src/app/DataMigrator/Account.php +++ b/src/app/DataMigrator/Account.php @@ -44,16 +44,19 @@ * Input can be a valid URI or ":". * For proxy authentication use: "**" as username. * - * @param string $input Account specification + * @param string $input Account specification (URI) */ public function __construct(string $input) { + if (!preg_match('|^[a-z]+://.*|', $input)) { + throw new \Exception("Invalid URI specified"); + } + $url = parse_url($input); - // Not valid URI, try the other form of input - if ($url === false || !array_key_exists('scheme', $url)) { - list($user, $password) = explode(':', $input, 2); - $url = ['user' => $user, 'pass' => $password]; + // Not valid URI + if (!is_array($url) || empty($url)) { + throw new \Exception("Invalid URI specified"); } if (isset($url['user'])) { diff --git a/src/app/DataMigrator/DAV.php b/src/app/DataMigrator/DAV.php --- a/src/app/DataMigrator/DAV.php +++ b/src/app/DataMigrator/DAV.php @@ -27,6 +27,8 @@ /** @var Engine Data migrator engine */ protected $engine; + /** @var array Folder paths cache */ + protected $folderPaths = []; /** * Object constructor @@ -65,24 +67,13 @@ */ public function createItem(Item $item): void { - // TODO: For now we do DELETE + PUT. It's because the UID might have changed (which - // is the case with e.g. contacts from EWS) causing a discrepancy between UID and href. - // This is not necessarily a problem and would not happen to calendar events. - // So, maybe we could improve that so DELETE is not needed. if ($item->existing) { - try { - $this->client->delete($item->existing); - } catch (\Illuminate\Http\Client\RequestException $e) { - // ignore 404 response, item removed in meantime? - if ($e->getCode() != 404) { - throw $e; - } - } + $href = $item->existing; + } else { + $href = $this->getFolderPath($item->folder) . '/' . pathinfo($item->filename, PATHINFO_BASENAME); } - $href = $this->getFolderPath($item->folder) . '/' . pathinfo($item->filename, PATHINFO_BASENAME); - - $object = new DAVOpaque($item->filename); + $object = new DAVOpaque($item->filename, true); $object->href = $href; switch ($item->folder->type) { @@ -180,25 +171,41 @@ // Get existing messages' headers from the destination mailbox $existing = $importer->getItems($folder); - $set = new ItemSet(); - $dav_type = $this->type2DAV($folder->type); $location = $this->getFolderPath($folder); - $search = new DAVSearch($dav_type); + $search = new DAVSearch($dav_type, false); // TODO: We request only properties relevant to incremental migration, // i.e. to find that something exists and its last update time. // Some servers (iRony) do ignore that and return full VCARD/VEVENT/VTODO // content, if there's many objects we'll have a memory limit issue. // Also, this list should be controlled by the exporter. - $search->dataProperties = ['UID', 'REV']; + $search->dataProperties = ['UID', 'REV', 'DTSTAMP']; + + $set = new ItemSet(); $result = $this->client->search( $location, $search, - function ($item) use (&$set, $folder, $callback) { - // TODO: Skip an item that exists and did not change - $exists = false; + function ($item) use (&$set, $dav_type, $folder, $existing, $callback) { + // Skip an item that exists and did not change + $exists = null; + if (!empty($existing[$item->uid])) { + $exists = $existing[$item->uid]['href']; + switch ($dav_type) { + case DAVClient::TYPE_VCARD: + if ($existing[$item->uid]['rev'] == $item->rev) { + return null; + } + break; + case DAVClient::TYPE_VEVENT: + case DAVClient::TYPE_VTODO: + if ($existing[$item->uid]['dtstamp'] == (string) $item->dtstamp) { + return null; + } + break; + } + } $set->items[] = Item::fromArray([ 'id' => $item->href, @@ -210,22 +217,24 @@ $callback($set); $set = new ItemSet(); } + + return null; } ); - if ($result === false) { - throw new \Exception("Failed to get items from a DAV folder {$location}"); - } - if (count($set->items)) { $callback($set); } + if ($result === false) { + throw new \Exception("Failed to get items from a DAV folder {$location}"); + } + // TODO: Delete items that do not exist anymore? } /** - * Get a list of folder items, limited to their essential propeties + * Get a list of items, limited to their essential propeties * used in incremental migration. * * @param Folder $folder Folder data @@ -244,28 +253,33 @@ // Some servers (iRony) do ignore that and return full VCARD/VEVENT/VTODO // content, if there's many objects we'll have a memory limit issue. // Also, this list should be controlled by the exporter. - $search->dataProperties = ['UID', 'X-MS-ID', 'REV']; + $search->dataProperties = ['UID', 'X-MS-ID', 'REV', 'DTSTAMP']; $items = $this->client->search( $location, $search, - // @phpstan-ignore-next-line function ($item) use ($dav_type) { // Slim down the result to properties we might need - $result = [ + $object = [ 'href' => $item->href, 'uid' => $item->uid, - 'x-ms-id' => $item->custom['X-MS-ID'] ?? null, ]; - /* + + if (!empty($item->custom['X-MS-ID'])) { + $object['x-ms-id'] = $item->custom['X-MS-ID']; + } + switch ($dav_type) { case DAVClient::TYPE_VCARD: - $result['rev'] = $item->rev; + $object['rev'] = $item->rev; + break; + case DAVClient::TYPE_VEVENT: + case DAVClient::TYPE_VTODO: + $object['dtstamp'] = (string) $item->dtstamp; break; } - */ - return $result; + return [$item->uid, $object]; } ); @@ -290,13 +304,16 @@ continue; } - // TODO: Skip other users folders - $folders = $this->client->listFolders($component); foreach ($folders as $folder) { + // Skip other users/shared folders + if ($this->shouldSkip($folder)) { + continue; + } + $result[$folder->href] = Folder::fromArray([ - 'fullname' => $folder->name, + 'fullname' => str_replace(' » ', '/', $folder->name), 'href' => $folder->href, 'type' => $type, ]); @@ -311,6 +328,11 @@ */ protected function getFolderPath(Folder $folder): string { + $cache_key = $folder->type . '!' . $folder->fullname; + if (isset($this->folderPaths[$cache_key])) { + return $this->folderPaths[$cache_key]; + } + $folders = $this->client->listFolders($this->type2DAV($folder->type)); if ($folders === false) { @@ -322,7 +344,7 @@ // hierarchies support is not full in Kolab 4. foreach ($folders as $dav_folder) { if (str_replace(' » ', '/', $dav_folder->name) === $folder->fullname) { - return rtrim($dav_folder->href, '/'); + return $this->folderPaths[$cache_key] = rtrim($dav_folder->href, '/'); } } @@ -364,4 +386,26 @@ throw new \Exception("Cannot map type '{$type}' from DAV"); } } + + /** + * Check if the folder should not be migrated + */ + private function shouldSkip($folder): bool + { + // When dealing with iRony DAV other user folders names have distinct names + // there's no other way to recognize them than by the name pattern. + // ;et's hope that users do not have personal folders with names starting with a bracket. + + if (preg_match('~\(.*\) .*~', $folder->name)) { + return true; + } + + if (str_starts_with($folder->name, 'shared » ')) { + return true; + } + + // TODO: Cyrus DAV shared folders + + return false; + } } diff --git a/src/app/DataMigrator/EWS.php b/src/app/DataMigrator/EWS.php --- a/src/app/DataMigrator/EWS.php +++ b/src/app/DataMigrator/EWS.php @@ -173,9 +173,13 @@ /** * Authenticate with OAuth2 (Office365) - get the token */ - protected function authenticateWithOAuth2(string $server, - string $user, string $client_id, string $client_secret, string $tenant_id) - { + protected function authenticateWithOAuth2( + string $server, + string $user, + string $client_id, + string $client_secret, + string $tenant_id + ) { // See https://github.com/Garethp/php-ews/blob/master/examples/basic/authenticatingWithOAuth.php // See https://github.com/Garethp/php-ews/issues/236#issuecomment-1292521527 // To register OAuth2 app goto https://entra.microsoft.com > Applications > App registrations @@ -382,7 +386,7 @@ protected function toItem(Type $item, Folder $folder, $existing, $existingIndex): ?Item { $id = $item->getItemId()->toArray(); - $exists = false; + $exists = null; // Detect an existing item, skip if nothing changed if (isset($existingIndex[$id['Id']])) { @@ -420,18 +424,20 @@ $options['version'] = API\ExchangeWebServices::VERSION_2013; } - // If you want to inject your own GuzzleClient for the requests - // $options['httpClient]' = $client; - // In debug mode record all responses - /* if (\config('app.debug')) { $options['httpPlayback'] = [ 'mode' => 'record', 'recordLocation' => \storage_path('ews'), ]; } - */ + + // Options for testing + foreach (['httpClient', 'httpPlayback'] as $opt) { + if (($val = $this->engine->getOption($opt)) !== null) { + $options[$opt] = $val; + } + } return $options; } diff --git a/src/app/DataMigrator/EWS/Appointment.php b/src/app/DataMigrator/EWS/Appointment.php --- a/src/app/DataMigrator/EWS/Appointment.php +++ b/src/app/DataMigrator/EWS/Appointment.php @@ -37,6 +37,9 @@ */ protected function processItem(Type $item) { + // Initialize $this->itemId (for some unit tests) + $this->getUID($item); + // Decode MIME content $ical = base64_decode((string) $item->getMimeContent()); @@ -90,11 +93,10 @@ */ protected function getUID(Type $item): string { - if ($this->uid === null) { - // Only appointments have UID property - $this->uid = $item->getUID(); - } + // Only appointments have UID property + $this->uid = $item->getUID(); - return $this->uid; + // This also sets $this->itemId; + return parent::getUID($item); } } diff --git a/src/app/DataMigrator/EWS/Contact.php b/src/app/DataMigrator/EWS/Contact.php --- a/src/app/DataMigrator/EWS/Contact.php +++ b/src/app/DataMigrator/EWS/Contact.php @@ -41,11 +41,46 @@ $uid = $this->getUID($item); $itemId = implode("\r\n ", str_split($this->itemId, 75 - strlen('X-MS-ID:'))); + // TODO: Use DAV\Vcard instead of string matching and replacement + $vcard = str_replace("BEGIN:VCARD", "BEGIN:VCARD\r\nUID:{$uid}\r\nX-MS-ID:{$itemId}", $vcard); // Note: Looks like PHOTO property is exported properly, so we // don't have to handle attachments as we do for calendar items + // TODO: Use vCard v4 for anniversary and spouse? Roundcube works with what's below + + // Spouse: X-MS-SPOUSE;TYPE=N:Partner Name + if (preg_match('/(X-MS-SPOUSE[;:][^\r\n]+)/', $vcard, $matches)) { + $spouse = preg_replace('/^[^:]+:/', '', $matches[1]); + $vcard = str_replace($matches[1], "X-SPOUSE:{$spouse}", $vcard); + } + + // TODO: X-MS-ANNIVERSARY;VALUE=DATE:2020-11-12 + if (preg_match('/(X-MS-ANNIVERSARY[;:][^\r\n]+)/', $vcard, $matches)) { + $date = preg_replace('/^[^:]+:/', '', $matches[1]); + $vcard = str_replace($matches[1], "X-ANNIVERSARY:{$date}", $vcard); + } + + // Exchange 2010 for some reason do not include email addresses in the vCard + if (!preg_match('/\nEMAIL[^:]*:[^\r\n]+/', $vcard) && ($emailEntries = $item->getEmailAddresses())) { + $emails = []; + + // Note that the Entry property is either an array (multiple addresses) + // or an object (single address). Not a great API design. + if (!is_array($emailEntries->Entry)) { + $emailEntries->Entry = [$emailEntries->Entry]; + } + + foreach ($emailEntries->Entry as $email) { + $emails[] = 'EMAIL;TYPE=internet:' . strval($email); + } + + if ($emails) { + $vcard = str_replace("BEGIN:VCARD\r\n", "BEGIN:VCARD\r\n" . implode("\r\n", $emails) . "\r\n", $vcard); + } + } + return $vcard; } } diff --git a/src/app/DataMigrator/EWS/DistList.php b/src/app/DataMigrator/EWS/DistList.php --- a/src/app/DataMigrator/EWS/DistList.php +++ b/src/app/DataMigrator/EWS/DistList.php @@ -34,23 +34,34 @@ $vcard .= $this->formatProp($key, $prop[0], isset($prop[1]) ? $prop[1] : []); } + // TODO: The group description property in Exchange is not available via EWS XML, + // at least not at outlook.office.com (Exchange 2010). It is available in the + // MimeContent which is in email message format. + + // TODO: mailto: members are not supported by Kolab Webclient + // We need to use MEMBER:urn:uuid:9bd97510-9dbb-4810-a144-6180962df5e0 syntax + // But do not forget lists can have members that are not contacts + // Process list members - // Note: The fact that getMembers() returns stdClass is probably a bug in php-ews - foreach ($item->getMembers()->Member as $member) { - $mailbox = $member->getMailbox(); - $mailto = $mailbox->getEmailAddress(); - $name = $mailbox->getName(); - - // FIXME: Investigate if mailto: members are handled properly by Kolab - // or we need to use MEMBER:urn:uuid:9bd97510-9dbb-4810-a144-6180962df5e0 syntax - // But do not forget lists can have members that are not contacts - - if ($mailto) { - if ($name && $name != $mailto) { - $mailto = urlencode(sprintf('"%s" <%s>', addcslashes($name, '"'), $mailto)); - } + if ($members = $item->getMembers()) { + // The Member property is either array (multiple members) or Type\MemberType + // object (a group with just a one member). + if (!is_array($members->Member)) { + $members->Member = [$members->Member]; + } - $vcard .= $this->formatProp('MEMBER', "mailto:{$mailto}"); + foreach ($members->Member as $member) { + $mailbox = $member->getMailbox(); + $mailto = $mailbox->getEmailAddress(); + $name = $mailbox->getName(); + + if ($mailto) { + if ($name && $name != $mailto) { + $mailto = urlencode(sprintf('"%s" <%s>', addcslashes($name, '"'), $mailto)); + } + + $vcard .= $this->formatProp('MEMBER', "mailto:{$mailto}"); + } } } diff --git a/src/app/DataMigrator/EWS/Item.php b/src/app/DataMigrator/EWS/Item.php --- a/src/app/DataMigrator/EWS/Item.php +++ b/src/app/DataMigrator/EWS/Item.php @@ -57,16 +57,14 @@ $itemId = $item->id; // Fetch the item - $item = $this->driver->api->getItem($itemId, $this->getItemRequest()); + $ewsItem = $this->driver->api->getItem($itemId, $this->getItemRequest()); - $this->itemId = implode('!', $itemId); - - $uid = $this->getUID($item); + $uid = $this->getUID($ewsItem); \Log::debug("[EWS] Saving item {$uid}..."); // Apply type-specific format converters - $content = $this->processItem($item); + $content = $this->processItem($ewsItem); if (!is_string($content)) { return; @@ -134,15 +132,18 @@ */ protected function getUID(Type $item): string { + $itemId = $item->getItemId()->toArray(); + if ($this->uid === null) { - // We should generate an UID for objects that do not have it - // and inject it into the output file - // FIXME: Should we use e.g. md5($itemId->getId()) instead? - // It looks that ItemId on EWS consists of three parts separated with a slash, - // maybe using the last part as UID would be a solution - $this->uid = \App\Utils::uuidStr(); + // Tasks, contacts, distlists do not have an UID. We have to generate one + // and inject it into the output file. + // We'll use the ItemId (excluding the ChangeKey part) as a base for the UID. + $this->uid = sha1($itemId['Id']); + // $this->uid = \App\Utils::uuidStr(); } + $this->itemId = implode('!', $itemId); + return $this->uid; } diff --git a/src/app/DataMigrator/EWS/Task.php b/src/app/DataMigrator/EWS/Task.php --- a/src/app/DataMigrator/EWS/Task.php +++ b/src/app/DataMigrator/EWS/Task.php @@ -34,7 +34,7 @@ // Tasks are exported as Email messages in useless format // (does not contain all relevant properties) // We'll build the iCalendar using properties directly - // TODO: This probably should be done with sabre-vobject + // TODO: This probably should be done with sabre-vobject and our DAV client // FIXME: Looks like tasks do not have timezone specified in EWS // and dates are in UTC, shall we remove the 'Z' from dates to make them floating? @@ -47,7 +47,6 @@ 'SUMMARY' => [$item->getSubject()], 'DESCRIPTION' => [(string) $item->getBody()], 'PERCENT-COMPLETE' => [intval($item->getPercentComplete())], - 'STATUS' => [strtoupper($item->getStatus())], 'X-MS-ID' => [$this->itemId], ]; @@ -59,6 +58,21 @@ $data['DTSTART'] = [$this->formatDate($startDate), ['VALUE' => 'DATE-TIME']]; } + if ($status = $item->getStatus()) { + $status = strtoupper($status); + $status_map = [ + 'COMPLETED' => 'COMPLETED', + 'INPROGRESS' => 'IN-PROGRESS', + 'DEFERRED' => 'X-DEFERRED', + 'NOTSTARTED' => 'X-NOTSTARTED', + 'WAITINGONOTHERS' => 'X-WAITINGFOROTHERS', + ]; + + if (isset($status_map[$status])) { + $data['STATUS'] = [$status_map[$status]]; + } + } + if (($categories = $item->getCategories()) && $categories->String) { $data['CATEGORIES'] = [$categories->String]; } diff --git a/src/app/DataMigrator/Engine.php b/src/app/DataMigrator/Engine.php --- a/src/app/DataMigrator/Engine.php +++ b/src/app/DataMigrator/Engine.php @@ -50,7 +50,7 @@ $this->options = $options; // Create a unique identifier for the migration request - $queue_id = md5(strval($source) . strval($destination) . $options['type']); + $queue_id = md5(strval($source) . strval($destination) . ($options['type'] ?? '')); // TODO: When running in 'sync' mode we shouldn't create a queue at all @@ -84,9 +84,6 @@ $this->importer = $this->initDriver($destination, ImporterInterface::class); $this->importer->authenticate(); - // $this->debug("Source/destination user credentials verified."); - $this->debug("Fetching folders hierarchy..."); - // Create a queue $this->createQueue($queue_id); @@ -97,7 +94,9 @@ mkdir($location, 0740, true); } - $types = preg_split('/\s*,\s*/', strtolower($this->options['type'] ?? '')); + $types = preg_split('/\s*,\s*/', strtolower($options['type'] ?? '')); + + $this->debug("Fetching folders hierarchy..."); $folders = $this->exporter->getFolders($types); $count = 0; @@ -240,6 +239,14 @@ } } + /** + * Get migration option value. + */ + public function getOption(string $name) + { + return $this->options[$name] ?? null; + } + /** * Set migration queue option. Use this if you need to pass * some data between queue processes. diff --git a/src/app/DataMigrator/IMAP.php b/src/app/DataMigrator/IMAP.php --- a/src/app/DataMigrator/IMAP.php +++ b/src/app/DataMigrator/IMAP.php @@ -73,6 +73,8 @@ throw new \Exception("Failed to create an IMAP folder {$folder->fullname}"); } } + + // TODO: Migrate folder subscription state } /** @@ -86,17 +88,41 @@ { $mailbox = $item->folder->fullname; - // TODO: When updating an email we have to just update flags - if ($item->filename) { $result = $this->imap->appendFromFile( - $mailbox, $item->filename, null, $item->data['flags'], $item->data['internaldate'], true + $mailbox, + $item->filename, + null, + $item->data['flags'], + $item->data['internaldate'], + true ); if ($result === false) { throw new \Exception("Failed to append IMAP message into {$mailbox}"); } } + + // When updating an existing email message we have to... + if ($item->existing) { + if (!empty($result)) { + // Remove the old one + $this->imap->flag($mailbox, $item->existing['uid'], 'DELETED'); + $this->imap->expunge($mailbox, $item->existing['uid']); + } else { + // Update flags + foreach ($item->existing['flags'] as $flag) { + if (!in_array($flag, $item->data['flags'])) { + $this->imap->unflag($mailbox, $item->existing['uid'], $flag); + } + } + foreach ($item->data['flags'] as $flag) { + if (!in_array($flag, $item->existing['flags'])) { + $this->imap->flag($mailbox, $item->existing['uid'], $flag); + } + } + } + } } /** @@ -118,43 +144,50 @@ // Remove flags that we can't append (e.g. RECENT) $flags = $this->filterImapFlags(array_keys($header->flags)); - // TODO: If message already exists in the destination account we should update flags + // If message already exists in the destination account we should update only flags // and be done with it. On the other hand for Drafts it's not unusual to get completely // different body for the same Message-ID. Same can happen not only in Drafts, I suppose. + // So, we compare size and INTERNALDATE timestamp. + if ( + !$item->existing + || $header->timestamp != $item->existing['timestamp'] + || $header->size != $item->existing['size'] + ) { + // Save the message content to a file + $location = $item->folder->location; + + if (!file_exists($location)) { + mkdir($location, 0740, true); + } - // Save the message content to a file - $location = $item->folder->location; + // TODO: What if parent folder not yet exists? + $location .= '/' . $uid . '.eml'; - if (!file_exists($location)) { - mkdir($location, 0740, true); - } + // TODO: We should consider streaming the message, it should be possible + // with append() and handlePartBody(), but I don't know if anyone tried that. - // TODO: What if parent folder not yet exists? - $location .= '/' . $uid . '.eml'; + $fp = fopen($location, 'w'); - // TODO: We should consider streaming the message, it should be possible - // with append() and handlePartBody(), but I don't know if anyone tried that. + if (!$fp) { + throw new \Exception("Failed to write to {$location}"); + } - $fp = fopen($location, 'w'); + $result = $this->imap->handlePartBody($mailbox, $uid, true, '', null, null, $fp); - if (!$fp) { - throw new \Exception("Failed to write to {$location}"); - } + if ($result === false) { + fclose($fp); + throw new \Exception("Failed to fetch IMAP message for {$mailbox}/{$uid}"); + } - $result = $this->imap->handlePartBody($mailbox, $uid, true, '', null, null, $fp); + $item->filename = $location; - if ($result === false) { fclose($fp); - throw new \Exception("Failed to fetch IMAP message for {$mailbox}/{$uid}"); } - $item->filename = $location; $item->data = [ 'flags' => $flags, 'internaldate' => $header->internaldate, ]; - - fclose($fp); } /** @@ -168,6 +201,7 @@ $mailbox = $folder->fullname; // TODO: We should probably first use SEARCH/SORT to skip messages marked as \Deleted + // It would also allow us to get headers in chunks 200 messages at a time, or so. // TODO: fetchHeaders() fetches too many headers, we should slim-down, here we need // only UID FLAGS INTERNALDATE BODY.PEEK[HEADER.FIELDS (DATE FROM MESSAGE-ID)] $messages = $this->imap->fetchHeaders($mailbox, '1:*', true, false, ['Message-Id']); @@ -184,17 +218,26 @@ $set = new ItemSet(); foreach ($messages as $message) { - // TODO: If Message-Id header does not exist create it based on internaldate/From/Date + // If Message-Id header does not exist create it based on internaldate/From/Date + $id = $this->getMessageId($message, $mailbox); // Skip message that exists and did not change - $exists = false; - if (isset($existing[$message->messageID])) { - // TODO: Compare flags (compare message size, internaldate?) - continue; + $exists = null; + if (isset($existing[$id])) { + $flags = $this->filterImapFlags(array_keys($message->flags)); + if ( + $flags == $existing[$id]['flags'] + && $message->timestamp == $existing[$id]['timestamp'] + && $message->size == $existing[$id]['size'] + ) { + continue; + } + + $exists = $existing[$id]; } $set->items[] = Item::fromArray([ - 'id' => $message->uid . ':' . $message->messageID, + 'id' => $message->uid . ':' . $id, 'folder' => $folder, 'existing' => $exists, ]); @@ -223,6 +266,8 @@ throw new \Exception("Failed to get list of IMAP folders"); } + // TODO: Migrate folder subscription state + $result = []; foreach ($folders as $folder) { @@ -263,10 +308,14 @@ // Remove flags that we can't append (e.g. RECENT) $flags = $this->filterImapFlags(array_keys($message->flags)); - // TODO: Generate message ID if the header does not exist - $result[$message->messageID] = [ + // Generate message ID if the header does not exist + $id = $this->getMessageId($message, $mailbox); + + $result[$id] = [ 'uid' => $message->uid, 'flags' => $flags, + 'size' => $message->size, + 'timestamp' => $message->timestamp, ]; } @@ -355,7 +404,7 @@ return array_filter( $flags, function ($flag) { - return in_array($flag, $this->imap->flags); + return isset($this->imap->flags[$flag]); } ); } @@ -366,12 +415,23 @@ private function shouldSkip($folder): bool { // TODO: This should probably use NAMESPACE information - // TODO: This should also skip other user folders - if (preg_match("/Shared Folders\/.*/", $folder)) { + if (preg_match('~(Shared Folders|Other Users)/.*~', $folder)) { return true; } return false; } + + /** + * Return Message-Id, generate unique identifier if Message-Id does not exist + */ + private function getMessageId($message, $folder): string + { + if (!empty($message->messageID)) { + return $message->messageID; + } + + return md5($folder . $message->from . ($message->date ?: $message->timestamp)); + } } diff --git a/src/app/DataMigrator/Interface/Item.php b/src/app/DataMigrator/Interface/Item.php --- a/src/app/DataMigrator/Interface/Item.php +++ b/src/app/DataMigrator/Interface/Item.php @@ -16,8 +16,13 @@ /** @var string Object class */ public $class; - /** @var false|string Identifier/Location of the item if exists in the destination folder */ - public $existing = false; + /** + * Identifier/Location of the item if exists in the destination folder. + * And/or some metadata on the existing item. This information is driver specific. + * + * @var string|array|null + */ + public $existing; /** @var ?string Exported object location in the local storage */ public $filename; diff --git a/src/bootstrap/app.php b/src/bootstrap/app.php --- a/src/bootstrap/app.php +++ b/src/bootstrap/app.php @@ -5,15 +5,15 @@ define('RCUBE_CHARSET', 'UTF-8'); } -// This function is defined by phpunit as well -if (!function_exists("array_first")) { +if (!function_exists('array_first')) { + /** - * Get first element from an array - * - * @param array $array Input array - * - * @return mixed First element if found, Null otherwise - */ + * Get first element from an array + * + * @param array $array Input array + * + * @return mixed First element if found, Null otherwise + */ function array_first($array) { // @phpstan-ignore-next-line diff --git a/src/tests/BackendsTrait.php b/src/tests/BackendsTrait.php new file mode 100644 --- /dev/null +++ b/src/tests/BackendsTrait.php @@ -0,0 +1,395 @@ + DAV::TYPE_VEVENT, + Engine::TYPE_TASK => DAV::TYPE_VTODO, + Engine::TYPE_CONTACT => DAV::TYPE_VCARD, + Engine::TYPE_GROUP => DAV::TYPE_VCARD, + ]; + + + /** + * Append an DAV object to a DAV folder + */ + protected function davAppend(Account $account, $foldername, $filenames, $type): void + { + $dav = $this->getDavClient($account); + + $folder = $this->davFindFolder($account, $foldername, $type); + + if (empty($folder)) { + throw new \Exception("Failed to find folder {$account}/{$foldername}"); + } + + foreach ((array) $filenames as $filename) { + $path = __DIR__ . '/data/' . $filename; + + if (!file_exists($path)) { + throw new \Exception("File does not exist: {$path}"); + } + + $content = file_get_contents($path); + $uid = preg_match('/\nUID:(?:urn:uuid:)?([a-z0-9-]+)/', $content, $m) ? $m[1] : null; + + if (empty($uid)) { + throw new \Exception("Filed to find UID in {$path}"); + } + + $location = rtrim($folder->href, '/') . '/' . $uid . '.' . pathinfo($filename, \PATHINFO_EXTENSION); + + $content = new DAV\Opaque($content); + $content->href = $location; + $content->contentType = $type == Engine::TYPE_CONTACT + ? 'text/vcard; charset=utf-8' + : 'text/calendar; charset=utf-8'; + + if ($dav->create($content) === false) { + throw new \Exception("Failed to append object into {$account}/{$location}"); + } + } + } + + /** + * Delete a DAV folder + */ + protected function davCreateFolder(Account $account, $foldername, $type): void + { + if ($this->davFindFolder($account, $foldername, $type)) { + return; + } + + $dav = $this->getDavClient($account); + + $dav_type = $this->davTypes[$type]; + $home = $dav->getHome($dav_type); + $folder_id = Utils::uuidStr(); + $collection_type = $dav_type == DAV::TYPE_VCARD ? 'addressbook' : 'calendar'; + + // We create all folders on the top-level + $folder = new DAV\Folder(); + $folder->name = $foldername; + $folder->href = rtrim($home, '/') . '/' . $folder_id; + $folder->components = [$dav_type]; + $folder->types = ['collection', $collection_type]; + + if ($dav->folderCreate($folder) === false) { + throw new \Exception("Failed to create folder {$account}/{$folder->href}"); + } + } + + /** + * Create a DAV folder + */ + protected function davDeleteFolder(Account $account, $foldername, $type): void + { + $folder = $this->davFindFolder($account, $foldername, $type); + + if (empty($folder)) { + return; + } + + $dav = $this->getDavClient($account); + + if ($dav->folderDelete($folder->href) === false) { + throw new \Exception("Failed to delete folder {$account}/{$foldername}"); + } + } + + /** + * Remove all objects from a DAV folder + */ + protected function davEmptyFolder(Account $account, $foldername, $type): void + { + $dav = $this->getDavClient($account); + + foreach ($this->davList($account, $foldername, $type) as $object) { + if ($dav->delete($object->href) === false) { + throw new \Exception("Failed to delete {$account}/{object->href}"); + } + } + } + + /** + * Find a DAV folder + */ + protected function davFindFolder(Account $account, $foldername, $type) + { + $dav = $this->getDavClient($account); + + $list = $dav->listFolders($this->davTypes[$type]); + + if ($list === false) { + throw new \Exception("Failed to list '{$type}' folders on {$account}"); + } + + foreach ($list as $folder) { + if (str_replace(' » ', '/', $folder->name) === $foldername) { + return $folder; + } + } + + return null; + } + + /** + * List objects in a DAV folder + */ + protected function davList(Account $account, $foldername, $type): array + { + $folder = $this->davFindFolder($account, $foldername, $type); + + if (empty($folder)) { + throw new \Exception("Failed to find folder {$account}/{$foldername}"); + } + + $dav = $this->getDavClient($account); + + $search = new DAV\Search($this->davTypes[$type], true); + + $searchResult = $dav->search($folder->href, $search); + + if ($searchResult === false) { + throw new \Exception("Failed to get items from a DAV folder {$account}/{$folder->href}"); + } + + $result = []; + foreach ($searchResult as $item) { + $result[] = $item; + } + + return $result; + } + + /** + * List DAV folders + */ + protected function davListFolders(Account $account, $type): array + { + $dav = $this->getDavClient($account); + + $list = $dav->listFolders($this->davTypes[$type]); + + if ($list === false) { + throw new \Exception("Failed to list '{$type}' folders on {$account}"); + } + + $result = []; + + foreach ($list as $folder) { + // skip shared folders (iRony) + if (str_starts_with($folder->name, 'shared » ') || $folder->name[0] == '(') { + continue; + } + + $result[$folder->href] = str_replace(' » ', '/', $folder->name); + } + + return $result; + } + + /** + * Get configured/initialized DAV client + */ + protected function getDavClient(Account $account): DAV + { + $clientId = (string) $account; + + if (empty($this->clients[$clientId])) { + $uri = preg_replace('/^dav/', 'http', $account->uri); + $this->clients[$clientId] = new DAV($account->username, $account->password, $uri); + } + + return $this->clients[$clientId]; + } + + /** + * Get configured/initialized IMAP client + */ + protected function getImapClient(Account $account): \rcube_imap_generic + { + $clientId = (string) $account; + + if (empty($this->clients[$clientId])) { + $class = new \ReflectionClass(IMAP::class); + + $initIMAP = $class->getMethod('initIMAP'); + $getConfig = $class->getMethod('getConfig'); + $initIMAP->setAccessible(true); + $getConfig->setAccessible(true); + + $config = [ + 'user' => $account->username, + 'password' => $account->password, + ]; + + $config = array_merge($getConfig->invoke(null), $config); + + $this->clients[$clientId] = $initIMAP->invokeArgs(null, [$config]); + } + + return $this->clients[$clientId]; + } + + /** + * Initialize an account + */ + protected function initAccount(Account $account): void + { + // Remove all objects from all (personal) folders + if ($account->scheme == 'dav' || $account->scheme == 'davs') { + foreach (['event', 'task', 'contact'] as $type) { + foreach ($this->davListFolders($account, $type) as $folder) { + $this->davEmptyFolder($account, $folder, $type); + } + } + } else { + // TODO: Delete all folders except the default ones? + foreach ($this->imapListFolders($account) as $folder) { + $this->imapEmptyFolder($account, $folder); + } + } + } + + /** + * Append an email message to the IMAP folder + */ + protected function imapAppend(Account $account, $folder, $filename, $flags = [], $date = null): string + { + $imap = $this->getImapClient($account); + + $source = __DIR__ . '/data/' . $filename; + + if (!file_exists($source)) { + throw new \Exception("File does not exist: {$source}"); + } + + $uid = $imap->appendFromFile($folder, $source, '', $flags, $date, true); + + if ($uid === false) { + throw new \Exception("Failed to append mail into {$account}/{$folder}"); + } + + return $uid; + } + + /** + * Create an IMAP folder + */ + protected function imapCreateFolder(Account $account, $folder): void + { + $imap = $this->getImapClient($account); + + if (!$imap->createFolder($folder)) { + if (str_contains($imap->error, "Mailbox already exists")) { + // Not an error + } else { + throw new \Exception("Failed to create an IMAP folder {$account}/{$folder}"); + } + } + } + + /** + * Delete an IMAP folder + */ + protected function imapDeleteFolder(Account $account, $folder): void + { + $imap = $this->getImapClient($account); + + if (!$imap->deleteFolder($folder)) { + if (str_contains($imap->error, "Mailbox does not exist")) { + // Ignore + } else { + throw new \Exception("Failed to delete an IMAP folder {$account}/{$folder}"); + } + } + + $imap->unsubscribe($folder); + } + + /** + * Remove all objects from a folder + */ + protected function imapEmptyFolder(Account $account, $folder): void + { + $imap = $this->getImapClient($account); + + $deleted = $imap->flag($folder, '1:*', 'DELETED'); + + if (!$deleted) { + throw new \Exception("Failed to empty an IMAP folder {$account}/{$folder}"); + } + + // send expunge command in order to have the deleted message really deleted from the folder + $imap->expunge($folder, '1:*'); + } + + /** + * List emails over IMAP + */ + protected function imapList(Account $account, $folder): array + { + $imap = $this->getImapClient($account); + + $messages = $imap->fetchHeaders($folder, '1:*', true, false, ['Message-Id']); + + if ($messages === false) { + throw new \Exception("Failed to get all IMAP message headers for {$account}/{$folder}"); + } + + return $messages; + } + + /** + * List IMAP folders + */ + protected function imapListFolders(Account $account): array + { + $imap = $this->getImapClient($account); + + $folders = $imap->listMailboxes('', ''); + + if ($folders === false) { + throw new \Exception("Failed to list IMAP folders for {$account}"); + } + + $folders = array_filter( + $folders, + function ($folder) { + return !preg_match('~(Shared Folders|Other Users)/.*~', $folder); + } + ); + + return $folders; + } + + /** + * Mark an email message as read over IMAP + */ + protected function imapFlagAs(Account $account, $folder, $uids, $flags): void + { + $imap = $this->getImapClient($account); + + foreach ($flags as $flag) { + if (strpos($flag, 'UN') === 0) { + $flagged = $imap->unflag($folder, $uids, substr($flag, 2)); + } else { + $flagged = $imap->flag($folder, $uids, $flag); + } + + if (!$flagged) { + throw new \Exception("Failed to flag an IMAP messages as SEEN in {$account}/{$folder}"); + } + } + } +} diff --git a/src/tests/Feature/DataMigrator/DAVTest.php b/src/tests/Feature/DataMigrator/DAVTest.php new file mode 100644 --- /dev/null +++ b/src/tests/Feature/DataMigrator/DAVTest.php @@ -0,0 +1,119 @@ +initAccount($src); + $this->initAccount($dst); + + // Add some items to the source account + $this->davAppend($src, 'Calendar', ['event/1.ics', 'event/2.ics'], Engine::TYPE_EVENT); + $this->davCreateFolder($src, 'DavDataMigrator', Engine::TYPE_CONTACT); + $this->davCreateFolder($src, 'DavDataMigrator/Test', Engine::TYPE_CONTACT); + $this->davAppend($src, 'DavDataMigrator/Test', ['contact/1.vcf', 'contact/2.vcf'], Engine::TYPE_CONTACT); + + // Clean up the destination folders structure + $this->davDeleteFolder($dst, 'DavDataMigrator', Engine::TYPE_CONTACT); + $this->davDeleteFolder($dst, 'DavDataMigrator/Test', Engine::TYPE_CONTACT); + + // Run the migration + $migrator = new Engine(); + $migrator->migrate($src, $dst, ['force' => true, 'sync' => true, 'type' => 'event,contact']); + + // Assert the destination account + $dstFolders = $this->davListFolders($dst, Engine::TYPE_CONTACT); + $this->assertContains('DavDataMigrator', $dstFolders); + $this->assertContains('DavDataMigrator/Test', $dstFolders); + + // Assert the migrated events + $dstObjects = $this->davList($dst, 'Calendar', Engine::TYPE_EVENT); + $events = \collect($dstObjects)->keyBy('uid')->all(); + $this->assertCount(2, $events); + $this->assertSame('Party', $events['abcdef']->summary); + $this->assertSame('Meeting', $events['123456']->summary); + + // Assert the migrated contacts and contact folders + $dstObjects = $this->davList($dst, 'DavDataMigrator/Test', Engine::TYPE_CONTACT); + $contacts = \collect($dstObjects)->keyBy('uid')->all(); + $this->assertCount(2, $contacts); + $this->assertSame('Jane Doe', $contacts['uid1']->fn); + $this->assertSame('Jack Strong', $contacts['uid2']->fn); + } + + /** + * Test DAV to DAV incremental migration run + * + * @group dav + * @depends testInitialMigration + */ + public function testIncrementalMigration(): void + { + $uri = \config('services.dav.uri'); + + $src = new Account(preg_replace('|^[a-z]+://|', 'dav://john%40kolab.org:simple123@', $uri)); + $dst = new Account(preg_replace('|^[a-z]+://|', 'dav://jack%40kolab.org:simple123@', $uri)); + + // Add an event and modify another one + $srcEvents = $this->davList($src, 'Calendar', Engine::TYPE_EVENT); + $this->davAppend($src, 'Calendar', ['event/3.ics', 'event/1.1.ics'], Engine::TYPE_EVENT); + + // Run the migration + $migrator = new Engine(); + $migrator->migrate($src, $dst, ['force' => true, 'sync' => true, 'type' => Engine::TYPE_EVENT]); + + // Assert the migrated events + $dstObjects = $this->davList($dst, 'Calendar', Engine::TYPE_EVENT); + $events = \collect($dstObjects)->keyBy('uid')->all(); + $this->assertCount(3, $events); + $this->assertSame('Party Update', $events['abcdef']->summary); + $this->assertSame('Meeting', $events['123456']->summary); + $this->assertSame('Test Summary', $events['aaa-aaa']->summary); + + // TODO: Assert that unmodified objects aren't migrated again + } +} diff --git a/src/tests/Feature/DataMigrator/EWSTest.php b/src/tests/Feature/DataMigrator/EWSTest.php new file mode 100644 --- /dev/null +++ b/src/tests/Feature/DataMigrator/EWSTest.php @@ -0,0 +1,208 @@ +davEmptyFolder($dst, 'Calendar', Engine::TYPE_EVENT); + $this->davEmptyFolder($dst, 'Tasks', Engine::TYPE_TASK); + $this->davDeleteFolder($dst, 'Kontakty', Engine::TYPE_CONTACT); + + $options = [ + 'force' => true, + 'sync' => true, + 'type' => 'event,contact,task', + // Mocking, use HTTP responses from the playback file + 'httpPlayback' => [ + 'mode' => 'playback', + 'recordLocation' => $this->buildPlaybackFile('initial'), + ], + ]; + + // Run the migration + $migrator = new Engine(); + $migrator->migrate($src, $dst, $options); + + // Assert the migrated events + $dstObjects = $this->davList($dst, 'Calendar', Engine::TYPE_EVENT); + $events = \collect($dstObjects)->keyBy('uid')->all(); + $this->assertCount(2, $events); + $this->assertSame('test to ms', $events[self::EVENT1]->summary); + $this->assertSame('test ms3', $events[self::EVENT2]->summary); + + // Assert the migrated tasks + // Note: Tasks do not have UID in Exchange so it's generated + $tasks = $this->davList($dst, 'Tasks', Engine::TYPE_TASK); + $this->assertCount(1, $tasks); + $this->assertSame('Nowe zadanie', $tasks[0]->summary); + + // Assert the migrated contacts and contact folders + // Note: Contacts do not have UID in Exchange so it's generated + $dstObjects = $this->davList($dst, 'Kontakty', Engine::TYPE_CONTACT); + $contacts = \collect($dstObjects)->keyBy('fn')->all(); + + $this->assertCount(3, $contacts); + $this->assertSame(null, $contacts['Nowy Kontakt']->kind); + $this->assertSame(null, $contacts['Test Surname']->kind); + $this->assertSame('group', $contacts['nowa lista']->kind); + } + + /** + * Test EWS to DAV incremental migration run + * + * @group ews dav + * @depends testInitialMigration + */ + public function testIncrementalMigration(): void + { + $uri = \config('services.dav.uri'); + + // TODO: Test OAuth2 authentication + + $src = new Account('ews://user%40outlook.com:pass@office.outlook.com'); + $dst = new Account(preg_replace('|^[a-z]+://|', 'dav://jack%40kolab.org:simple123@', $uri)); + + $options = [ + 'force' => true, + 'sync' => true, + 'type' => 'event,contact', + // Mocking, use HTTP responses from the playback file + 'httpPlayback' => [ + 'mode' => 'playback', + 'recordLocation' => $this->buildPlaybackFile('incremental'), + ], + ]; + + // We added a new contact and modified another one + // Run the migration + $migrator = new Engine(); + $migrator->migrate($src, $dst, $options); + + $dstObjects = $this->davList($dst, 'Calendar', Engine::TYPE_EVENT); + $events = \collect($dstObjects)->keyBy('uid')->all(); + $this->assertCount(2, $events); + $this->assertSame('test to ms', $events[self::EVENT1]->summary); + $this->assertSame('test ms3', $events[self::EVENT2]->summary); + + // Assert the migrated contacts + // Note: Contacts do not have UID in Exchange so it's generated + $dstObjects = $this->davList($dst, 'Kontakty', Engine::TYPE_CONTACT); + $contacts = \collect($dstObjects)->keyBy('fn')->all(); + + $this->assertCount(4, $contacts); + $this->assertSame(null, $contacts['Nowy Kontakt']->kind); + $this->assertSame(null, $contacts['Test Surname 1']->kind); + $this->assertSame(null, $contacts['Test New']->kind); + $this->assertSame('group', $contacts['nowa lista']->kind); + + // TODO: Assert that unmodified objects aren't migrated again, + // although our httpPlayback makes that it would fail otherwise. + + // TODO: Test migrating a task/event with attachments + } + + /** + * Test OAuth2 use + * + * @group ews dav + * @depends testIncrementalMigration + */ + public function testOAuth2(): void + { + // TODO: Test OAuth2 authentication with HTTP client fake + + $this->markTestIncomplete(); + } + + /** + * Build a playback file for EWS client to mock communication with Exchange. + */ + private function buildPlaybackFile($type) + { + /* The .json and .xml files were produced with the follwoing script + having saveState.json produced by httpPlayback in 'record' mode. + Separated and formatted for better understanding and modification ability. + + $file = file_get_contents('saveState.json'); + + $data = json_decode($file, true); + + foreach ($data as $idx => $record) { + file_put_contents("a{$idx}.xml", $record['body']); + unset($record['body']); + file_put_contents("$idx.json", json_encode($record, JSON_PRETTY_PRINT)); + exec("xmllint --format a{$idx}.xml >> $idx.xml"); + unlink("a{$idx}.xml"); + } + */ + + $dir = __DIR__ . '/../../data/ews/' . $type; + $playback = []; + + foreach (glob("{$dir}/[0-9].json") as $file) { + $id = basename($file, '.json'); + + $response = json_decode(file_get_contents($file), true); + $response['body'] = file_get_contents(str_replace('.json', '.xml', $file)); + + $playback[(int) $id] = $response; + } + + ksort($playback); + + file_put_contents($dir . '/' . 'saveState.json', json_encode($playback)); + + return $dir; + } +} diff --git a/src/tests/Feature/DataMigrator/EngineTest.php b/src/tests/Feature/DataMigrator/EngineTest.php new file mode 100644 --- /dev/null +++ b/src/tests/Feature/DataMigrator/EngineTest.php @@ -0,0 +1,47 @@ +markTestIncomplete(); + } + + /** + * Test synchronous migration + */ + public function testSyncMigration(): void + { + $this->markTestIncomplete(); + } +} diff --git a/src/tests/Feature/DataMigrator/IMAPTest.php b/src/tests/Feature/DataMigrator/IMAPTest.php new file mode 100644 --- /dev/null +++ b/src/tests/Feature/DataMigrator/IMAPTest.php @@ -0,0 +1,143 @@ +initAccount($src); + $this->initAccount($dst); + + // Add some mail to the source account + $this->imapAppend($src, 'INBOX', 'mail/1.eml'); + $this->imapAppend($src, 'INBOX', 'mail/2.eml', ['SEEN']); + $this->imapCreateFolder($src, 'ImapDataMigrator'); + $this->imapCreateFolder($src, 'ImapDataMigrator/Test'); + $this->imapAppend($src, 'ImapDataMigrator/Test', 'mail/1.eml'); + $this->imapAppend($src, 'ImapDataMigrator/Test', 'mail/2.eml'); + + // Clean up the destination folders structure + $this->imapDeleteFolder($dst, 'ImapDataMigrator'); + $this->imapDeleteFolder($dst, 'ImapDataMigrator/Test'); + + // Run the migration + $migrator = new Engine(); + $migrator->migrate($src, $dst, ['force' => true, 'sync' => true]); + + // Assert the destination mailbox + $dstFolders = $this->imapListFolders($dst); + $this->assertContains('ImapDataMigrator', $dstFolders); + $this->assertContains('ImapDataMigrator/Test', $dstFolders); + + // Assert the migrated messages + $dstMessages = $this->imapList($dst, 'INBOX'); + $this->assertCount(2, $dstMessages); + $msg = array_shift($dstMessages); + $this->assertSame('', $msg->messageID); + $this->assertSame([], $msg->flags); + $msg = array_shift($dstMessages); + $this->assertSame('', $msg->messageID); + $this->assertSame(['SEEN'], array_keys($msg->flags)); + + $dstMessages = $this->imapList($dst, 'ImapDataMigrator/Test'); + $this->assertCount(2, $dstMessages); + $msg = array_shift($dstMessages); + $this->assertSame('', $msg->messageID); + $this->assertSame([], $msg->flags); + $msg = array_shift($dstMessages); + $this->assertSame('', $msg->messageID); + $this->assertSame([], $msg->flags); + + // TODO: Test INTERNALDATE migration + } + + /** + * Test IMAP to IMAP incremental migration run + * + * @group imap + * @depends testInitialMigration + */ + public function testIncrementalMigration(): void + { + $uri = \config('imap.uri'); + + $src = new Account(str_replace('://', '://john%40kolab.org:simple123@', $uri)); + $dst = new Account(str_replace('://', '://jack%40kolab.org:simple123@', $uri)); + + // Add some mails to the source account + $srcMessages = $this->imapList($src, 'INBOX'); + $msg1 = array_shift($srcMessages); + $msg2 = array_shift($srcMessages); + $this->imapAppend($src, 'INBOX', 'mail/3.eml'); + $this->imapAppend($src, 'INBOX', 'mail/4.eml'); + $this->imapFlagAs($src, 'INBOX', $msg1->uid, ['SEEN']); + $this->imapFlagAs($src, 'INBOX', $msg2->uid, ['UNSEEN', 'FLAGGED']); + + // Run the migration + $migrator = new Engine(); + $migrator->migrate($src, $dst, ['force' => true, 'sync' => true]); + + // In INBOX two new messages and two old ones with changed flags + // The order of messages tells us that there was no redundant APPEND+DELETE + $dstMessages = $this->imapList($dst, 'INBOX'); + $this->assertCount(4, $dstMessages); + $msg = array_shift($dstMessages); + $this->assertSame('', $msg->messageID); + $this->assertSame(['SEEN'], array_keys($msg->flags)); + $msg = array_shift($dstMessages); + $this->assertSame('', $msg->messageID); + $this->assertSame(['FLAGGED'], array_keys($msg->flags)); + $ids = array_map(fn ($msg) => $msg->messageID, $dstMessages); + $this->assertSame(['',''], $ids); + + // Nothing changed in the other folder + $dstMessages = $this->imapList($dst, 'ImapDataMigrator/Test'); + $this->assertCount(2, $dstMessages); + $msg = array_shift($dstMessages); + $this->assertSame('', $msg->messageID); + $this->assertSame([], $msg->flags); + $msg = array_shift($dstMessages); + $this->assertSame('', $msg->messageID); + $this->assertSame([], $msg->flags); + } +} diff --git a/src/tests/Unit/DataMigrator/AccountTest.php b/src/tests/Unit/DataMigrator/AccountTest.php new file mode 100644 --- /dev/null +++ b/src/tests/Unit/DataMigrator/AccountTest.php @@ -0,0 +1,33 @@ +assertSame($uri, (string) $account); + $this->assertSame('user', $account->username); + $this->assertSame('pass@word', $account->password); + $this->assertSame('host.tld', $account->host); + $this->assertSame('imap', $account->scheme); + $this->assertSame(143, $account->port); + $this->assertSame('imap://host.tld:143', $account->uri); + $this->assertSame(['client_id' => '123', 'client_secret' => '456'], $account->params); + $this->assertNull($account->email); + $this->assertNull($account->loginas); + + // Invalid input + $this->expectException(\Exception::class); + $account = new Account(str_replace('imap://', '', $uri)); + } +} diff --git a/src/tests/Unit/DataMigrator/EWS/AppointmentTest.php b/src/tests/Unit/DataMigrator/EWS/AppointmentTest.php new file mode 100644 --- /dev/null +++ b/src/tests/Unit/DataMigrator/EWS/AppointmentTest.php @@ -0,0 +1,112 @@ + 'test']); + $appointment = new EWS\Appointment($ews, $folder); + + $ical = file_get_contents(__DIR__ . '/../../../data/ews/event/1.ics'); + + // FIXME: I haven't found a way to convert xml content into a Type instance + // therefore we create it "manually", but it would be better to have both + // vcard and xml in a single data file that we could just get content from. + + $item = Type::buildFromArray([ + 'MimeContent' => base64_encode($ical), + 'ItemId' => new Type\ItemIdType( + 'AAMkAGEzOGRlODRiLTBkN2ItNDgwZS04ZDJmLTM5NDEyY2Q0NGQ0OABGAAAAAAC9tlDYSlG2TaxWBr' + . 'A1OzWtBwAs2ajhknXlRYN/pbC8JqblAAAAAAEOAAAs2ajhknXlRYN/pbC8JqblAAJnrWkBAAA=', + 'EQAAABYAAAAs2ajhknXlRYN/pbC8JqblAAJnqlKm', + ), + 'UID' => '1F3C13D7E99642A75ABE23D50487B454-8FE68B2E68E1B348', + 'Subject' => 'test subject', + 'HasAttachments' => false, + 'IsAssociated' => false, + 'Start' => '2023-11-21T11:00:00Z', + 'End' => '2023-11-21T11:30:00Z', + 'LegacyFreeBusyStatus' => 'Tentative', + 'CalendarItemType' => 'Single', + 'Organizer' => [ + 'Mailbox' => [ + 'Name' => 'Aleksander Machniak', + 'EmailAddress' => 'test@kolab.org', + 'RoutingType' => 'SMTP', + 'MailboxType' => 'Contact', + ], + ], + 'RequiredAttendees' => (object) [ + 'Attendee' => [ + Type\AttendeeType::buildFromArray([ + 'Mailbox' => [ + 'Name' => 'Aleksander Machniak', + 'EmailAddress' => 'test@kolab.org', + 'RoutingType' => 'SMTP', + 'MailboxType' => 'Contact', + ], + 'ResponseType' => 'Unknown', + ]), + Type\AttendeeType::buildFromArray([ + 'Mailbox' => [ + 'Name' => 'Alec Machniak', + 'EmailAddress' => 'test@outlook.com', + 'RoutingType' => 'SMTP', + 'MailboxType' => 'Mailbox', + ], + 'ResponseType' => 'Unknown', + ]), + ], + ], + ]); + + // Convert the Exchange item into iCalendar + $ical = $this->invokeMethod($appointment, 'processItem', [$item]); + + // Parse the iCalendar output + $event = new Vevent(); + $this->invokeMethod($event, 'fromIcal', [$ical]); + + $msId = implode('!', $item->getItemId()->toArray()); + $this->assertSame($msId, $event->custom['X-MS-ID']); + $this->assertSame($item->getUID(), $event->uid); + $this->assertSame('test description', $event->description); + $this->assertSame('test subject', $event->summary); + $this->assertSame('CONFIRMED', $event->status); + $this->assertSame('PUBLIC', $event->class); + $this->assertSame('Microsoft Exchange Server 2010', $event->prodid); + $this->assertSame('2023-11-20T14:50:05+00:00', $event->dtstamp->getDateTime()->format('c')); + $this->assertSame('2023-11-21T12:00:00+01:00', $event->dtstart->getDateTime()->format('c')); + $this->assertSame('2023-11-21T12:30:00+01:00', $event->dtend->getDateTime()->format('c')); + + // Organizer/attendees + $this->assertSame('test@kolab.org', $event->organizer['email']); + $this->assertSame('Aleksander Machniak', $event->organizer['cn']); + $this->assertSame('ORGANIZER', $event->organizer['role']); + $this->assertSame('ACCEPTED', $event->organizer['partstat']); + $this->assertSame(false, $event->organizer['rsvp']); + + $this->assertCount(1, $event->attendees); + $this->assertSame('alec@outlook.com', $event->attendees[0]['email']); + $this->assertSame('Alec Machniak', $event->attendees[0]['cn']); + $this->assertSame('REQ-PARTICIPANT', $event->attendees[0]['role']); + $this->assertSame('NEEDS-ACTION', $event->attendees[0]['partstat']); + $this->assertSame(true, $event->attendees[0]['rsvp']); + } +} diff --git a/src/tests/Unit/DataMigrator/EWS/ContactTest.php b/src/tests/Unit/DataMigrator/EWS/ContactTest.php new file mode 100644 --- /dev/null +++ b/src/tests/Unit/DataMigrator/EWS/ContactTest.php @@ -0,0 +1,140 @@ + 'test']); + $contact = new EWS\Contact($ews, $folder); + + $vcard = file_get_contents(__DIR__ . '/../../../data/ews/contact/1.vcf'); + + // FIXME: I haven't found a way to convert xml content into a Type instance + // therefore we create it "manually", but it would be better to have both + // vcard and xml in a single data file that we could just get content from. + + $item = Type::buildFromArray([ + 'MimeContent' => base64_encode($vcard), + 'ItemId' => new Type\ItemIdType( + 'AAMkAGEzOGRlODRiLTBkN2ItNDgwZS04ZDJmLTM5NDEyY2Q0NGQ0OABGAAAAAAC9tlDYSlG2TaxWBr' + . 'A1OzWtBwAs2ajhknXlRYN/pbC8JqblAAAAAAEOAAAs2ajhknXlRYN/pbC8JqblAAJnrWkBAAA=', + 'EQAAABYAAAAs2ajhknXlRYN/pbC8JqblAAJnqlKm', + ), + 'HasAttachments' => false, + 'LastModifiedTime' => '2024-07-15T11:17:39,701Z', + 'DisplayName' => 'Nowy Nazwisko', + 'GivenName' => 'Nowy', + 'Surname' => 'Nazwisko', + 'EmailAddresses' => (object) [ + 'Entry' => [ + Type\EmailAddressDictionaryEntryType::buildFromArray([ + 'Key' => 'EmailAddress1', + 'Name' => 'test1@outlook.com', + 'RoutingType' => 'SMTP', + 'MailboxType' => 'Contact', + '_value' => 'christian1@outlook.com', + ]), + Type\EmailAddressDictionaryEntryType::buildFromArray([ + 'Key' => 'EmailAddress2', + 'Name' => 'test2@outlook.com', + 'RoutingType' => 'SMTP', + 'MailboxType' => 'Contact', + '_value' => 'test2@outlook.com', + ]), + ], + ], + /* + + + + ContactPicture.jpg + image/jpeg + 2081 + 2024-07-15T11:17:38 + false + true + + + + category + + en-US + + + Mr + Nowy + Bartosz + Nazwisko + Jr. + Nowy Nazwisko + alec + + Company + + + Testowa + Warsaw + mazowickie + Poland + 00-001 + + + + + home123456 + 1234556679200 + + + + 2014-10-11T11:59:00Z + IT + Developer + Office Location + 2020-11-12T11:59:00Z + true + */ + ]); + + // Convert the Exchange item into vCard + $vcard = $this->invokeMethod($contact, 'processItem', [$item]); + + // Parse the vCard + $contact = new Vcard(); + $this->invokeMethod($contact, 'fromVcard', [$vcard]); + + $this->assertMatchesRegularExpression('/^[a-f0-9]{40}$/', $contact->uid); + $this->assertSame('PUBLIC', $contact->class); + $this->assertSame('Nowy Nazwisko', $contact->fn); + $this->assertSame(null, $contact->kind); + $this->assertSame('Microsoft Exchange', $contact->prodid); + $this->assertSame('2024-07-15T11:17:39,701Z', $contact->rev); + $this->assertSame('Notatki do kontaktu', $contact->note); + + // EWS Properties with special handling + $msId = implode('!', $item->getItemId()->toArray()); + $this->assertSame($msId, $contact->custom['X-MS-ID']); + $this->assertSame('Partner Name', $contact->custom['X-SPOUSE']); + $this->assertSame('2020-11-12', $contact->custom['X-ANNIVERSARY']); + $this->assertCount(2, $contact->email); + $this->assertSame('internet', $contact->email[0]['type']); + $this->assertSame('christian1@outlook.com', $contact->email[0]['email']); + $this->assertSame('internet', $contact->email[1]['type']); + $this->assertSame('test2@outlook.com', $contact->email[1]['email']); + } +} diff --git a/src/tests/Unit/DataMigrator/EWS/DistListTest.php b/src/tests/Unit/DataMigrator/EWS/DistListTest.php new file mode 100644 --- /dev/null +++ b/src/tests/Unit/DataMigrator/EWS/DistListTest.php @@ -0,0 +1,89 @@ + 'test']); + $distlist = new EWS\DistList($ews, $folder); + + // FIXME: I haven't found a way to convert xml content into a Type instance + // therefore we create it "manually", but it would be better to have both + // vcard and xml in a single data file that we could just get content from. + + $item = Type::buildFromArray([ + 'ItemId' => new Type\ItemIdType( + 'AAMkAGEzOGRlODRiLTBkN2ItNDgwZS04ZDJmLTM5NDEyY2Q0NGQ0OABGAAAAAAC9tlDYSlG2TaxWBr' + . 'A1OzWtBwAs2ajhknXlRYN/pbC8JqblAAAAAAEOAAAs2ajhknXlRYN/pbC8JqblAAJnrWkBAAA=', + 'EQAAABYAAAAs2ajhknXlRYN/pbC8JqblAAJnqlKm', + ), + 'Subject' => 'subject list', + 'LastModifiedTime' => '2024-06-27T13:44:32Z', + 'DisplayName' => 'Lista', + 'FileAs' => 'lista', + 'Members' => (object) [ + 'Member' => [ + Type\MemberType::buildFromArray([ + 'Key' => 'AAAAAIErH6S+oxAZnW4A3QEPVAIAAAGAYQBsAGUAYwBAAGEAbABlAGMALgBw' + . 'AGwAAABTAE0AVABQAAAAYQBsAGUAYwBAAGEAbABlAGMALgBwAGwAAAA=', + 'Mailbox' => [ + 'Name' => 'Alec', + 'EmailAddress' => 'alec@kolab.org', + 'RoutingType' => 'SMTP', + 'MailboxType' => 'OneOff', + ], + 'Status' => 'Normal', + ]), + Type\MemberType::buildFromArray([ + 'Key' => 'AAAAAIErH6S+oxAZnW4A3QEPVAIAAAGAYQBsAGUAYwBAAGEAbABlAGMALgBw' + . 'AGwAAABTAE0AVABQAAAAYQBsAGUAYwBAAGEAbABlAGMALgBwAGwAAAB=', + 'Mailbox' => [ + 'Name' => 'Christian', + 'EmailAddress' => 'christian@kolab.org', + 'RoutingType' => 'SMTP', + 'MailboxType' => 'OneOff', + ], + 'Status' => 'Normal', + ]), + ], + ], + ]); + + // Convert the Exchange item into vCard + $vcard = $this->invokeMethod($distlist, 'processItem', [$item]); + + // Parse the vCard + $distlist = new Vcard(); + $this->invokeMethod($distlist, 'fromVcard', [$vcard]); + + $msId = implode('!', $item->getItemId()->toArray()); + $this->assertSame(['X-MS-ID' => $msId], $distlist->custom); + $this->assertMatchesRegularExpression('/^[a-f0-9]{40}$/', $distlist->uid); + $this->assertSame('group', $distlist->kind); + $this->assertSame('Lista', $distlist->fn); + $this->assertSame('Kolab EWS Data Migrator', $distlist->prodid); + $this->assertSame('2024-06-27T13:44:32Z', $distlist->rev); + + $members = [ + 'mailto:%22Alec%22+%3Calec%40kolab.org%3E', + 'mailto:%22Christian%22+%3Cchristian%40kolab.org%3E', + ]; + $this->assertSame($members, $distlist->members); + } +} diff --git a/src/tests/Unit/DataMigrator/EWS/TaskTest.php b/src/tests/Unit/DataMigrator/EWS/TaskTest.php new file mode 100644 --- /dev/null +++ b/src/tests/Unit/DataMigrator/EWS/TaskTest.php @@ -0,0 +1,158 @@ +source = $source; + $engine->destination = $destination; + $ews = new EWS($source, $engine); + $folder = Folder::fromArray(['id' => 'test']); + $task = new EWS\Task($ews, $folder); + + // FIXME: I haven't found a way to convert xml content into a Type instance + // therefore we create it "manually", but it would be better to have it in XML. + + $html = '' + . '
task notes
'; + + $item = Type\TaskType::buildFromArray([ + 'ItemId' => new Type\ItemIdType( + 'AAMkAGEzOGRlODRiLTBkN2ItNDgwZS04ZDJmLTM5NDEyY2Q0NGQ0OABGAAAAAAC9tlDYSlG2TaxWBr' + . 'A1OzWtBwAs2ajhknXlRYN/pbC8JqblAAAAAAEOAAAs2ajhknXlRYN/pbC8JqblAAJnrWkBAAA=', + 'EQAAABYAAAAs2ajhknXlRYN/pbC8JqblAAJnqlKm', + ), + 'ItemClass' => 'IPM.Task', + 'Subject' => 'Nowe zadanie', + 'LastModifiedTime' => '2024-06-27T13:44:32Z', + 'Sensitivity' => 'Private', + // TODO: Looks like EWS has Body->IsTruncated property, but is it relevant? + 'Body' => new Type\BodyType($html, 'HTML'), + 'Importance' => 'High', + 'DateTimeCreated' => '2024-06-27T08:58:05Z', + 'ReminderDueBy' => '2024-07-17T07:00:00Z', + 'ReminderIsSet' => true, + 'ReminderNextTime' => '2024-07-17T07:00:00Z', + 'ReminderMinutesBeforeStart' => '0', + 'DueDate' => '2024-06-26T22:00:00Z', + 'IsComplete' => false, + 'IsRecurring' => true, + 'Owner' => 'Alec Machniak', + 'PercentComplete' => '10', + 'Recurrence' => Type\TaskRecurrenceType::buildFromArray([ + 'WeeklyRecurrence' => [ + 'Interval' => '1', + 'DaysOfWeek' => 'Thursday', + 'FirstDayOfWeek' => 'Sunday', + ], + 'NoEndRecurrence' => [ + 'StartDate' => '2024-06-27Z', + ], + ]), + 'Status' => 'NotStarted', + 'ChangeCount' => '2', + /* + + + + testdisk.log + application/octet-stream + 299368b3-06e4-42df-959e-d428046f55e6 + 249 + 2024-07-16T12:13:58 + false + false + + + 2024-06-27T08:58:05Z + 3041 + + Kategoria Niebieski + + false + false + false + false + false + 2024-06-27T08:58:05Z + + true + en-US + + false + false + false + true + true + true + true + + Alec Machniak + 2024-07-16T12:14:38Z + false + + + NotFlagged + + AQEAAAAAAAESAQAAAmjiC08AAAAA + + 1 + Not Started + */ + ]); + + // Convert the Exchange item into iCalendar + $ical = $this->invokeMethod($task, 'processItem', [$item]); + + // Parse the iCalendar output + $task = new Vtodo(); + $this->invokeMethod($task, 'fromIcal', [$ical]); + + $msId = implode('!', $item->getItemId()->toArray()); + $this->assertSame($msId, $task->custom['X-MS-ID']); + $this->assertMatchesRegularExpression('/^[a-f0-9]{40}$/', $task->uid); + $this->assertSame('Nowe zadanie', $task->summary); + $this->assertSame($html, $task->description); + $this->assertSame('Kolab EWS Data Migrator', $task->prodid); + $this->assertSame('2', $task->sequence); + $this->assertSame('9', $task->priority); + $this->assertSame('PRIVATE', $task->class); + $this->assertSame(10, $task->percentComplete); + $this->assertSame('X-NOTSTARTED', $task->status); + $this->assertSame('2024-06-27T13:44:32+00:00', $task->dtstamp->getDateTime()->format('c')); + $this->assertSame('2024-06-27T08:58:05+00:00', $task->created->getDateTime()->format('c')); + $this->assertSame('2024-06-26T22:00:00+00:00', $task->due->getDateTime()->format('c')); + $this->assertSame('test@kolab.org', $task->organizer['email']); + + $this->assertSame('WEEKLY', $task->rrule['freq']); + $this->assertSame('1', $task->rrule['interval']); + $this->assertSame('TH', $task->rrule['byday']); + $this->assertSame('SU', $task->rrule['wkst']); + + // TODO: Reminder + } + + /** + * Test processing Recurrence property + */ + public function testProcessItemRecurrence(): void + { + $this->markTestIncomplete(); + } +} diff --git a/src/tests/data/contact/1.vcf b/src/tests/data/contact/1.vcf new file mode 100644 --- /dev/null +++ b/src/tests/data/contact/1.vcf @@ -0,0 +1,6 @@ +BEGIN:VCARD +VERSION:3.0 +UID:uid1 +FN:Jane Doe +N:Doe;Jane;J.;; +END:VCARD diff --git a/src/tests/data/contact/2.vcf b/src/tests/data/contact/2.vcf new file mode 100644 --- /dev/null +++ b/src/tests/data/contact/2.vcf @@ -0,0 +1,6 @@ +BEGIN:VCARD +VERSION:3.0 +UID:uid2 +FN:Jack Strong +N:Strong;Jack;;; +END:VCARD diff --git a/src/tests/data/event/1.1.ics b/src/tests/data/event/1.1.ics new file mode 100644 --- /dev/null +++ b/src/tests/data/event/1.1.ics @@ -0,0 +1,12 @@ +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//test/test//NONSGML v1.0//EN +BEGIN:VEVENT +UID:abcdef +DTSTAMP:19970714T180000Z +ORGANIZER;CN=John Doe:MAILTO:john@kolab.org +DTSTART:20240714T170000Z +DTEND:20240714T180000Z +SUMMARY:Party Update +END:VEVENT +END:VCALENDAR diff --git a/src/tests/data/event/1.ics b/src/tests/data/event/1.ics new file mode 100644 --- /dev/null +++ b/src/tests/data/event/1.ics @@ -0,0 +1,12 @@ +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//test/test//NONSGML v1.0//EN +BEGIN:VEVENT +UID:abcdef +DTSTAMP:19970714T170000Z +ORGANIZER;CN=John Doe:MAILTO:john@kolab.org +DTSTART:20240714T170000Z +DTEND:20240714T180000Z +SUMMARY:Party +END:VEVENT +END:VCALENDAR diff --git a/src/tests/data/event/2.ics b/src/tests/data/event/2.ics new file mode 100644 --- /dev/null +++ b/src/tests/data/event/2.ics @@ -0,0 +1,12 @@ +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//test/test//NONSGML v1.0//EN +BEGIN:VEVENT +UID:123456 +DTSTAMP:19970714T170000Z +ORGANIZER;CN=John Doe:MAILTO:john@kolab.org +DTSTART:20240715T170000Z +DTEND:20240715T180000Z +SUMMARY:Meeting +END:VEVENT +END:VCALENDAR diff --git a/src/tests/data/event/3.ics b/src/tests/data/event/3.ics new file mode 100644 --- /dev/null +++ b/src/tests/data/event/3.ics @@ -0,0 +1,12 @@ +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//test/test//NONSGML v1.0//EN +BEGIN:VEVENT +UID:aaa-aaa +DTSTAMP:19970714T170000Z +ORGANIZER;CN=John Doe:MAILTO:john@kolab.org +DTSTART:20240715T170000Z +DTEND:20240715T180000Z +SUMMARY:Test Summary +END:VEVENT +END:VCALENDAR diff --git a/src/tests/data/ews/contact/1.vcf b/src/tests/data/ews/contact/1.vcf new file mode 100644 --- /dev/null +++ b/src/tests/data/ews/contact/1.vcf @@ -0,0 +1,59 @@ +BEGIN:VCARD +PROFILE:VCARD +VERSION:3.0 +MAILER:Microsoft Exchange +PRODID:Microsoft Exchange +FN:Nowy Nazwisko +N:Nazwisko;Nowy;Bartosz;Mr;Jr. +PHOTO;TYPE=JPEG;ENCODING=B:/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgICAgMCAgID + AwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/2w + BDAQMDAwQDBAgEBAgQCwkLEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQ + EBAQEBAQEBAQEBD/wAARCAA6ADoDAREAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAw + QFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0Kx + wRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3 + R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW + 19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQ + oL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAV + YnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eH + l6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna + 4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD87K+4PlwoAKACgAoAKACgAoAKACgD2D + 9mj9l/4iftQ+M5PC/gpIbSx09Fm1bV7oH7PYRMSFzjl5GwwSMctgnhQzDmxOKhhY80/kjahQlX + laJ992v/AARx+F66WIr34w+KZdR2YM8Vlbxw7vXyjubHtv8AxryHnFS+kVY9H+zoW+I+Kf2s/w + BjD4hfsqata3Gq3sWveFdVlaHTtctoTGplAJ8meMk+VLtBYDJVgCVJwwX1MJjYYpaaNdDhxGGl + QeuqPnquw5goAKACgAoA/ar/AIJa+ENF0D9kzRfEGnwRi98T6lqN9fyAfOzxXL2yKT6COBSB/t + E9zXzGaTcsQ0+lj3MDFKimup9eV5x2Hkn7Vnwhk+OXwD8X/Dqxsbe51O/sTLpQmcRhb6JhJAd5 + +5ll2k/3WYdCa6MLW9hWjN7GNen7Wm4n4g/HX9nr4h/s665p/hr4lJpNvqepWzXkVrZ6jHdOkO + 7aHcJ9wMQwXPXY3pX1NDEQxCcobHhVaMqLtI8yrcyCgAoAKAP0U/4Jh/tg+E/AFhc/AL4n63Bp + Njd3rXvh7UruQJbxyyY821kc8RhmAdGOFLM4JBK58bM8HKo/bU1fuelgcQoL2c/kfqfFLHPGs0 + MiujgMrKwIYHoQR1rwD1jE8deM/D/w78H6x448VXy2mkaHZS315MeqxxqSQB3Y9FHUkgDrVwhK + pJQjuyZSUIuT2R/Pn8dPi74g+OvxV8Q/FDxGStxrV0ZIbfduW1tlG2GBfZI1Vc9yCTyTX2FCjG + hTVOPQ+dq1HVm5s4OtTMKACgAoA6/4R/DPxD8Y/iT4e+GfhaLdqOv3qWqOVysKdZJnA/gjjDu3 + sprOrVjRg6ktkXTg6klBdT+hP4c+BNA+GHgTQvh/4YgaLSvD9hFYWoY5ZkRcbmPdmOWJ7ljXx1 + So6s3OW7Po4QUIqK6H54f8FaP2kMDTv2bfC9/y3lat4maNu33rW1b9JmB/6Yn1r2cpw29eXojz + cwrf8ul8z8zK9w8sKACgAoAKAP0F/wCCYl3+z/8ACqHXPjB8Vvir4R0bxHf50nSLC/1KKOe1tA + QZpmQnKmRgqrnB2xt2evHzNVqtqdOLa3Z6OBdOnec2rn298Qf26f2Z/B/gnWvE+lfFvwv4gvtN + spJ7XStP1KOW4vZgP3cKKuT8zFQT0AJJ4FeXTwNeclFxaO+eKpRi2nc/Dnx1408Q/EbxjrPjvx + Xem71fXb2W+vJT0MjsSQo7KOAo6BQAOlfUwhGnFQjsjwZyc5OT3ZhVZIUAFABQAUAFABQAUAFA + BQAUAfRn/CK+GP8AoXNL/wDAOP8Awr7/AOpYb/n3H7kfkn9pY3/n9L/wJ/5h/wAIr4Y/6FzS/w + DwDj/wo+pYb/n3H7kH9pY3/n9L/wACf+Yf8Ir4Y/6FzS//AADj/wAKPqWG/wCfcfuQf2ljf+f0 + v/An/mH/AAivhj/oXNL/APAOP/Cj6lhv+fcfuQf2ljf+f0v/AAJ/5h/wivhj/oXNL/8AAOP/AA + o+pYb/AJ9x+5B/aWN/5/S/8Cf+Yf8ACK+GP+hc0v8A8A4/8KPqWG/59x+5B/aWN/5/S/8AAn/m + H/CK+GP+hc0v/wAA4/8ACj6lhv8An3H7kH9pY3/n9L/wJ/5h/wAIr4Y/6FzS/wDwDj/wo+pYb/ + n3H7kH9pY3/n9L/wACf+Z//9k= +NOTE:Notatki do kontaktu +ORG:Company;IT +CLASS:PUBLIC +ADR;TYPE=WORK:;Office Location;;;;; +ADR;TYPE=HOME:;;Testowa;Warsaw;mazowickie;00-001;Poland +LABEL;TYPE=HOME:Testowa\n00-001 Warsaw mazowickie\nPoland +TEL;TYPE=HOME:home123456 +TEL;TYPE=CELL:1234556679200 +X-MS-SPOUSE;TYPE=N:Partner Name +NICKNAME:alec +TITLE:Developer +URL;TYPE=HOME:www.alec.pl +CATEGORIES:category +BDAY;VALUE=DATE:2014-10-11 +REV;VALUE=DATE-TIME:2024-07-15T11:17:39,701Z +X-MS-ANNIVERSARY;VALUE=DATE:2020-11-12 +END:VCARD diff --git a/src/tests/data/ews/event/1.ics b/src/tests/data/ews/event/1.ics new file mode 100644 --- /dev/null +++ b/src/tests/data/ews/event/1.ics @@ -0,0 +1,49 @@ +BEGIN:VCALENDAR +METHOD:PUBLISH +PRODID:Microsoft Exchange Server 2010 +VERSION:2.0 +BEGIN:VTIMEZONE +TZID:Central European Standard Time +BEGIN:STANDARD +DTSTART:16010101T030000 +TZOFFSETFROM:+0200 +TZOFFSETTO:+0100 +RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=-1SU;BYMONTH=10 +END:STANDARD +BEGIN:DAYLIGHT +DTSTART:16010101T020000 +TZOFFSETFROM:+0100 +TZOFFSETTO:+0200 +RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=-1SU;BYMONTH=3 +END:DAYLIGHT +END:VTIMEZONE +BEGIN:VEVENT +ORGANIZER;CN=Aleksander Machniak:mailto:test@kolab.org +ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN=Aleksander + Machniak:mailto:test@kolab.org +ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN=Alec Machn + iak:mailto:alec@outlook.com +DESCRIPTION:test description +UID:1F3C13D7E99642A75ABE23D50487B454-8FE68B2E68E1B348 +SUMMARY:test subject +DTSTART;TZID=Central European Standard Time:20231121T120000 +DTEND;TZID=Central European Standard Time:20231121T123000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20231120T145005Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-OWNERAPPTID:0 +X-MICROSOFT-CDO-BUSYSTATUS:TENTATIVE +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:0 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +X-MICROSOFT-REQUESTEDATTENDANCEMODE:DEFAULT +X-MICROSOFT-ISRESPONSEREQUESTED:TRUE +END:VEVENT +END:VCALENDAR diff --git a/src/tests/data/ews/incremental/0.json b/src/tests/data/ews/incremental/0.json new file mode 100644 --- /dev/null +++ b/src/tests/data/ews/incremental/0.json @@ -0,0 +1,96 @@ +{ + "error": false, + "statusCode": 200, + "headers": { + "Cache-Control": [ + "private" + ], + "Transfer-Encoding": [ + "chunked" + ], + "Content-Type": [ + "text\/xml; charset=utf-8" + ], + "Server": [ + "Microsoft-HTTPAPI\/2.0" + ], + "X-NanoProxy": [ + "1,1" + ], + "X-AspNet-Version": [ + "4.0.30319" + ], + "Request-Id": [ + "a4ce6838-81ac-65a7-4759-3d9294738779" + ], + "X-CalculatedFETarget": [ + "GV0P278CU004.internal.outlook.com" + ], + "Alt-Svc": [ + "h3=\":443\";ma=2592000,h3-29=\":443\";ma=2592000" + ], + "MS-CV": [ + "OGjOpKyBp2VHWT2SlHOHeQ.1.1" + ], + "Restrict-Access-Confirm": [ + "1" + ], + "X-BackEndHttpStatus": [ + "200,200" + ], + "X-BEServer": [ + "GVAP278MB0615" + ], + "X-BeSku": [ + "WCS6" + ], + "X-CalculatedBETarget": [ + "GVAP278MB0615.CHEP278.PROD.OUTLOOK.COM" + ], + "X-DiagInfo": [ + "GVAP278MB0615" + ], + "x-EwsHandler": [ + "FindFolder" + ], + "X-FEEFZInfo": [ + "GVA" + ], + "X-FEProxyInfo": [ + "GV0P278CA0060" + ], + "X-FEServer": [ + "WA0P291CA0004" + ], + "x-ms-appId": [ + "6ce1e52b-cd1d-4663-abc3-368fba0bfae7" + ], + "X-Proxy-BackendServerStatus": [ + "200" + ], + "X-Proxy-RoutingCorrectness": [ + "1" + ], + "X-RUM-NotUpdateQueriedPath": [ + "1" + ], + "X-RUM-NotUpdateQueriedDbCopy": [ + "1" + ], + "X-RUM-Validated": [ + "1" + ], + "X-FirstHopCafeEFZ": [ + "WAW" + ], + "Strict-Transport-Security": [ + "max-age=31536000; includeSubDomains" + ], + "Set-Cookie": [ + "exchangecookie=faf9d40d8bc14d53a013ecd1336e35b5; expires=Fri, 11-Jul-2025 12:51:36 GMT; path=\/; secure; HttpOnly" + ], + "Date": [ + "Thu, 11 Jul 2024 12:51:36 GMT" + ] + } +} \ No newline at end of file diff --git a/src/tests/data/ews/incremental/0.xml b/src/tests/data/ews/incremental/0.xml new file mode 100644 --- /dev/null +++ b/src/tests/data/ews/incremental/0.xml @@ -0,0 +1,7139 @@ + + + + + + + + + + NoError + + + + + + IPF.Note + AllCategorizedItems + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + AllContacts + 3 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + AllContactsExtended + 3 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF + AllItems + 230 + 0 + + true + true + true + true + true + true + true + + 110 + + + + + IPF.Note + AllPersonMetadata + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Task + AllTodoTasks + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + ApplicationDataRoot + 0 + 56 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 00000002-0000-0ff1-ce00-000000000000 + 0 + 3 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + HxNotificationSettings + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 00000006-0000-0ff1-ce00-000000000000 + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + GlobalSearchHistory + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 13937bba-652e-4c46-b222-3003f4d1ff97 + 0 + 3 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + ContextDataFast + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + ContextMetadata + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + UserInteractionsFast + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 1caee58f-eb14-4a6b-9339-1fe2ddf6692b + 0 + 2 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + Recent + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + Settings + 2 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 1e70cd27-4707-4589-8ec5-9bd20c472a46 + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 224fffa9-a547-4c78-ab95-3aacd66c3e99 + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + FeaturesManagementCollection_1 + 3 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 32d4b5e5-7d33-4e7f-b073-f8cffbbb47a1 + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + outlookfavorites + 3 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 33b68b23-a6c2-4684-99a0-fa3832792226 + 0 + 2 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + AggregationV2BackfillStateCollection + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + RelevanceDailyAggregation + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 34421fbe-f100-4e5b-9c46-2fea25aa7b88 + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + Contacts + 6 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 35d54a08-36c9-4847-9018-93934c62740c + 0 + 3 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + PeoplePredictions.FeedbackEntries + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + PeoplePredictions.RequestEntries + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + PeoplePredictions.UserProfile + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 3873c4f1-2162-4ddb-96e6-232e4eddeedc + 0 + 4 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SEED_PeopleIntegrityCheckerStateCollection_v2 + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SEED_ScdIntegrityCheckerStateCollection_v2 + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 394866fc-eedb-4f01-8536-3ff84b16be2a + 0 + 3 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + AssociationBackfillStatus + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + Favorites + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + InsightInstancesActions + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 3b2e5a14-128d-48aa-b581-482aac616d32 + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 3c896ded-22c5-450f-91f6-3d1ef0848f6e + 0 + 42 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + ActionExecutions + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + ActivitiesDaily + 58 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + ActivitiesWeekly + 8 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + AfterHoursEmailImpact + 50 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + AutomaticRepliesHistory + 105 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + ChatsInterruptionStatistics + 49 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + ComputeLogs + 38 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + CumulativeNetworkSnapshot + 3 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + CumulativeOutOfOfficeClustering + 106 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + DailyActivityTimeBins + 56 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + DailyAppointments + 85 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + DailyInteractions + 50 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + DailyNetworkSnapshot + 51 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + DelayedEmail + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + DeliverCardEvents + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + DetailedMeetings + 51 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + EmailActionStatistics + 50 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + EmailGrazerData + 50 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + EmfResponses + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + FoodForThoughtRanking + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + HeterogeneousItems + 10 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + ImportantContact + 3 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + InsightsEngagement + 10 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + MailActivityCompactSignalBatch + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + ManagementOperationExecutionRecords + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + MeetingActionStatistics + 9 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + MeetingResponseActivity + 6 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + OutcomeStates + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + OutOfOffice + 44 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + ProgramMetrics + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SegmentsStateRecord + 18 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SentMailLogs + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SigsChatsAndCallsCompactSignalBatch + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + UnifiedCardEngagements + 30 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + UserConfiguration + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + UserProgramInstances + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + WeeklyEmbeddingBasedUserTimePrediction + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + WeeklyInteractions + 27 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + WeeklyOutOfOfficeAndWorkingDay + 28 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + WeeklyOutOfRoutineMeetingScorePDF + 30 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + WeeklyOutOfRoutineMeetingTimes + 61 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + WeeklyWorkplaceActivityEmbedding + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 3e3c8645-20a6-4c6e-8355-c34cbbe04585 + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + PintSigsMsGraphState + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 42c2c67f-2760-4f42-b0c4-ef5c3854a0c2 + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + CollabObjects + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 43375d74-c6a5-4d4e-a0a3-de139860ea75 + 0 + 2 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + ElcArchiveProcessorStatsSdsCollection + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + OverallArchivingStatsSdsCollection + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 441509e5-a165-4363-8ee7-bcf0b7d26739 + 0 + 3 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + GenericWorkflowProcessor.SessionManager.Data + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + Idf + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + IdfMeeting + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 4787c7ff-7cea-43db-8d0d-919f15c6354b + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + VivaSales + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 48af08dc-f6d2-435f-b2a7-069abd99c086 + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + InsightsProvidersSettings + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 49499048-0129-47f5-b95e-f9d315b861a6 + 0 + 2 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + OutlookAccountCloudSettings + 3 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + OutlookCloudSettings + 5 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 497effe9-df71-4043-a8bb-14cf78c4b63b + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + EACUserPreferences + 5 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 4e445925-163e-42ca-b801-9073bfa46d17 + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + NewsSubscriptionSourcesv2 + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 59cc317d-5453-4fcd-ab98-60552b158926 + 0 + 6 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + AlgorithmRunStatus + 9 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + CDDS_SuggestionCheckpoint + 2 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + ContactFeedback + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + ContactMergeSuggestions + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + HiddenDuplicates + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + HideSettings + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 644c1b11-f63f-45fa-826b-a9d2801db711 + 0 + 3 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + _PolicyContainer + 3 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + YWxlY0BhcGhlbGVpYWl0Lm9ubWljcm9zb2Z0LmNvbQ==_LabelFile + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + YWxlY0BhcGhlbGVpYWl0Lm9ubWljcm9zb2Z0LmNvbQ==_PolicyContainer + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 66a88757-258c-4c72-893c-3e8bed4d6899 + 0 + 31 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + ScopeEntities + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.Apps + 3 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.CalendarEvents + 10 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.CollaborationNetworkEntities + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.ContentDomain + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.EmailEntities + 3 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.EmailTokens + 2 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.EntityServe + 2 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.EntityServe.Bookmarks + 2 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.EntityServe.Links + 4 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.EntityServe.Locations + 2 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.EntityServe.Qnas + 2 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.FreshHistory + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.FreshSharePointFiles + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.FreshSharePointSites + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.GroupsRoomsMiscIndex + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.Notes + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.People + 11 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.PeopleCache + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.PeopleIndex + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.RecentEmailItems + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.RecommendationsService + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.RecommendationsServiceProcessor + 2 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.Scope + 2 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.SearchHistory.Main + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.SearchHistoryState + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.SharePointDocuments + 5 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.SkillEntities + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.TeamsAndChannels + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.TeamsEntities + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.Topics + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 6cd5135b-7a07-43ec-acc2-b5e27dc628cb + 0 + 3 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + currentuser + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + neighbors + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + OfficeFeedSdsCacheCollection + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 766ef332-38e5-4cb4-920c-baa478e39fd9 + 0 + 3 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + CrawlerExecutionInfoCollection + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 7a5fbd1c-3e6d-461a-9075-83049393b3a7 + 0 + 7 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + AcronymAggregationState + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + AcronymService.SessionManager.Data + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + ConceptAggregationSessionManager.Data + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + NicknamesAllInbox + 2 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SimpleAcronymsIndex + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SimpleAcronymsIndexElysium + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SimpleUserContextIndex + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 7aadb841-2368-4d24-a373-94d0ba1f077a + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + outlookspaces + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 7ae974c5-1af7-4923-af3a-fb1fd14dcb7e + 0 + 9 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + AppBarTiles + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + FloodgateSurvey + 3 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + GetStartedStore + 20 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + lightning + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + LightningSharedStore + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + LightningStore + 67 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + OutlookEndpointDataCollection + 2 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + OutlookOptionsV3 + 7 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + WhatsNewStore + 97 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 7e02887d-df1d-45a4-af52-dcee2e585eee + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + UserEnablementStatus + 8 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 80723a00-368e-4d64-8281-210e49e593a8 + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + ActivityFeed_201905 + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 82d8ab62-be52-a567-14ea-1616c4ee06c4 + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + ActorAnalyticsProcessorState + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 8a18aa92-0a1e-4e06-abd0-e118fa4787b1 + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + GraphMetaColl + 26 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 8c22b648-ee54-4ece-a4ca-3015b6d24f8e + 0 + 20 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + DIF + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + Images + 2 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + source_contactsync + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + source_meetinginsightssetting + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + source_officegraphvisibilitysetting + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + source_sourceaad + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + source_sourceconnector + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + source_sourceemailaddressdisplaynames + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + source_sourcemanagerchain + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + source_sourcemsgraph + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + source_sourcenamepronunciation + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + source_sourcenone + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + source_sourceorganizationheadcount + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + source_sourcephotoetag + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + source_sourceupa + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + source_sourceuserdefined + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + source_userdefinedsettings + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SQI_FI + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + view_profilev2 + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + view_settingsv2 + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 94c63fef-13a3-47bc-8074-75af8c65887a + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + DelveCollection + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 97cb1f73-50df-47d1-8fb0-0271f2728514 + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + CleanupProcessorState + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + a3883eba-fbe9-48bd-9ed3-dca3e0e84250 + 0 + 4 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + AggregatedLinks + 9 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + EmailsIndexV1 + 65 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + LinkFiltersMetadataIndex + 3 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + LinksIndex + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + a6061a71-f529-4ca2-bc9d-c8085ecbf3ca + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + EdgeSettings + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + adcd8967-0799-4ec0-bfc8-dcf85fd84767 + 0 + 2 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + CssProcessingState + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + ae8e128e-080f-4086-b0e3-4c19301ada69 + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + Scheduling + 2 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + b669c6ea-1adf-453f-b8bc-6d526592b419 + 0 + 3 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + FocusedInboxMailboxData + 2 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + NudgeCandidates + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + ScenarioTracking + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + b6e65498-8dce-4d57-8de9-1269fcfcf6ce + 0 + 6 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + KeyphraseRelationshipsSessionManager.Data + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + UserDocKpeStats + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + UserDocWithKpes + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + UserKpes + 2 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + UserKpeState + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + UserStatistics + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + c9224372-5534-42cb-a48b-8db4f4a3892e + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + TeamsCalendar.SSMeetingPropsSync + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + c94eb245-f5ab-4fea-a534-841091469193 + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + ic3usersettings + 13 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + d297b9ff-5d5b-4bce-8ed4-eedb1431bf61 + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + NucleusProperties + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + d396de1f-10d4-4023-aae2-5bb3d724ba9a + 0 + 3 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + FolderGroups-DefaultCollection + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + settings + 6 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + TasksDataMarker_v9 + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + d71dfe16-1070-48f3-bd3a-c3ec919d34e7 + 0 + 2 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + TxpAutoblocking + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + TxpUserSettings + 10 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + d8cbf452-c2df-4756-95a5-8aa23fedc3ce + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + UserMigrationDetails + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + e69932cd-f814-4087-8ab1-5ab3f1ad18eb + 0 + 2 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + e7762c80-392b-4278-80fa-a8fda80b129c + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + CMUState + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + e7f049f2-9dc5-4301-88a2-121b268ad42f + 0 + 2 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + Common + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SharingSuggestion + 2 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + f08262d6-bf02-4e1e-bdef-e95e2f0a940f + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + GlowCollection + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + f164ee43-46e5-4f7c-b5ff-2d1abcd4ce7e + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + PersonalProfileVector_AnalyzerStates + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + f3f64fec-ecee-4e9a-9eed-a36a5e421300 + 0 + 10 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + IdfEmailPoi + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + IdfInboxPoi + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + IdfMeetingPoi + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + InferredLanguage + 2 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SlpJobs + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SpeechNGrams + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SpeechTrimmedLms + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SpeechUserDocumentNGrams + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SpeechUserDocumentSentences + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SpeechUserDocumentsHistory + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + BrokerSubscriptions + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + BulkActions + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + CalendarSharingCacheCollection + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + Common Views + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + ComplianceMetadata + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + Connectors + 0 + 2 + + true + true + true + true + true + true + true + + 0 + + + + + ConnectorConfigurations + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.StoreItem.CrawlerData + CrawlerData + 35 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + Deferred Action + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.StoreItem.DlpPolicyEvaluation + DlpPolicyEvaluation + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + Document Centric Conversations + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + ExchangeODataSyncData + 199 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + ExchangeSyncData + 0 + 3 + + true + true + true + true + true + true + true + + 0 + + + + + AirSync-iPhone-J97G80P7O916504POMJIHAJE70 + 10 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + AirSync-TestActiveSyncConnectivity-430847304 + 5 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + Hx-Outlook-B57C063B9A6C46ECAD4C159C1E161B14 + 0 + 2 + + true + true + true + true + true + true + true + + 0 + + + + + OutlookServiceActionQueue + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + Policy + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + Finder + 0 + 2 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + OwaFV15.1AllFocusedAQMkAGEzOGRlODRiLTBkN2ItNDgwZS04ZDJmLTM5NDEyY2Q0NABkNDgALgAAA722UNhKUbZNrFYGsDU7Na0BACzZqOGSdeVFg3+lsLwmpuUAAAIBDAAAAA== + 101 + 0 + + true + true + true + true + true + true + true + + 95 + + + + + IPF.Note + OwaFV15.1AllOtherAQMkAGEzOGRlODRiLTBkN2ItNDgwZS04ZDJmLTM5NDEyY2Q0NABkNDgALgAAA722UNhKUbZNrFYGsDU7Na0BACzZqOGSdeVFg3+lsLwmpuUAAAIBDAAAAA== + 15 + 0 + + true + true + true + true + true + true + true + + 15 + + + + + IPF.Task + Folder Memberships + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Task + Flagged Emails + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + Folder nadrzędny magazynu informacji + 0 + 19 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + Archiwum + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Configuration + Conversation Action Settings + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Journal + Dziennik + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + Elementy usunięte + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + Elementy wysłane + 5 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.StoreItem.EventCheckPoints + EventCheckPoints + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Contact + ExternalContacts + 0 + 0 + + true + true + true + true + true + true + true + + + + + + IPF + Folder główny usługi Yammer + 0 + 3 + + true + true + true + true + true + true + true + + 0 + + + + + IPF + Feeds + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF + Inbound + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF + Outbound + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + Historia konwersacji + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.SkypeTeams.Message + Czat zespołu + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Appointment + Calendar + 2 + 2 + + true + true + true + true + true + true + true + + + + + + IPF.Appointment + United States holidays + 97 + 0 + + true + true + true + true + true + true + true + + + + + + IPF.Appointment.Birthday + Urodziny + 0 + 0 + + true + true + true + true + true + true + true + + + + + + IPF.Contact + Kontakty + 4 + 7 + + true + true + true + true + true + true + true + + + + + + IPF.Contact.MOC.QuickContacts + {06967759-274D-40B2-A3EB-D7F9E73727D7} + 0 + 0 + + true + true + true + true + true + true + true + + + + + + IPF.Contact.MOC.ImContactList + {A9E2BC46-B3A0-4243-B315-60D991004455} + 0 + 0 + + true + true + true + true + true + true + true + + + + + + IPF.Contact.Company + Firmy + 0 + 0 + + true + true + true + true + true + true + true + + + + + + IPF.Contact.GalContacts + GAL Contacts + 0 + 0 + + true + true + true + true + true + true + true + + + + + + IPF.Contact.OrganizationalContacts + Organizational Contacts + 0 + 0 + + true + true + true + true + true + true + true + + + + + + IPF.Contact.PeopleCentricConversationBuddies + PeopleCentricConversation Buddies + 0 + 0 + + true + true + true + true + true + true + true + + + + + + IPF.Contact.RecipientCache + Recipient Cache + 0 + 0 + + true + true + true + true + true + true + true + + + + + + IPF.Contact.MeContact + MeContact + 0 + 0 + + true + true + true + true + true + true + true + + + + + + IPF.StickyNote + Notatki + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Files + Pliki + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + Skrzynka nadawcza + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + Skrzynka odbiorcza + 116 + 0 + + true + true + true + true + true + true + true + + 110 + + + + + IPF.Note + Wersje robocze + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + Wiadomości-śmieci + 0 + 0 + + true + true + true + true + true + true + true + + 3dbb5f39-dc76-4916-9db3-fa9191760a55 + 0 + + + + + IPF.Task + Tasks + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + Freebusy Data + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.StoreItem.FreeBusyCache + FreeBusyLocalCache + 2 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + FreeBusyLocalCacheSubscriptions + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + GraphFilesAndWorkingSetSearchFolder + 64 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + GraphStore + 0 + 2 + + true + true + true + true + true + true + true + + 0 + + + + + GraphRelations + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + Inference + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + MailboxAssociations + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + MailboxMoveHistory + 4 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + MailboxReplicationService Index + 4 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + MergedViewFolderCollection + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + MessageIngestion + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + Yammer + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + Moje kontakty + 3 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + O365 Suite Notifications + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF + OneDriveRoot + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + OneNotePagePreviews + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Task + Orion Notes + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + OutlookExtensions + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + PACE + 31 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + People I Know + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + PeopleConnect + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + PeoplePublicData + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + Outlook.Reminder + Przypomnienia + 21 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + QuarantinedEmail + 0 + 1 + + true + true + true + true + true + true + true + + cce0d6e6-b69b-410a-907d-06dc2071ab58 + 0 + + + + + QuarantinedEmailDefaultCategory + 0 + 4 + + true + true + true + true + true + true + true + + cce0d6e6-b69b-410a-907d-06dc2071ab58 + 0 + + + + + QedcDefaultRetention + 0 + 0 + + true + true + true + true + true + true + true + + cce0d6e6-b69b-410a-907d-06dc2071ab58 + 0 + + + + + QedcLongRetention + 0 + 0 + + true + true + true + true + true + true + true + + cce0d6e6-b69b-410a-907d-06dc2071ab58 + 0 + + + + + QedcMediumRetention + 0 + 0 + + true + true + true + true + true + true + true + + cce0d6e6-b69b-410a-907d-06dc2071ab58 + 0 + + + + + QedcShortRetention + 0 + 0 + + true + true + true + true + true + true + true + + cce0d6e6-b69b-410a-907d-06dc2071ab58 + 0 + + + + + Recoverable Items + 0 + 6 + + true + true + false + false + false + + + true + true + true + true + true + true + true + + 0 + + + + + Audits + 12 + 0 + + true + true + false + false + false + + + true + true + true + true + true + true + true + + 0 + + + + + Calendar Logging + 0 + 0 + + true + true + false + false + false + + + true + true + true + true + true + true + true + + 0 + + + + + Deletions + 0 + 0 + + true + true + false + false + false + + + true + true + true + true + true + true + true + + 0 + + + + + Purges + 2 + 0 + + true + true + false + false + false + + + true + true + true + true + true + true + true + + 0 + + + + + SubstrateHolds + 0 + 0 + + true + true + false + false + false + + + true + true + true + true + true + true + true + + 0 + + + + + Versions + 0 + 0 + + true + true + false + false + false + + + true + true + true + true + true + true + true + + 0 + + + + + IPF.StoreItem.RecoveryPoints + RecoveryPoints + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + RelevantContacts + 3 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + Schedule + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + SearchFoldersView + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.StoreItem.ShadowItems + ShadowItems + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + SharedFilesSearchFolder + 63 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + SharePointNotifications + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + Sharing + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + Shortcuts + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + ShortNotes + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + SkypeSpacesData + 0 + 3 + + true + true + true + true + true + true + true + + 0 + + + + + SkypeMessages + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + TeamsMeetings + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + TeamsMessages + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + Spooler Queue + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + SpoolsPresentSharedItemsSearchFolder + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + SpoolsSearchFolder + 8 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF + SubstrateFiles + 0 + 3 + + true + true + true + true + true + true + true + + 0 + + + + + ClassicAttachments + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.StoreItem.Signal + GraphWorkingSet + 64 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + SPOOLS + 8 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + SuggestedUserGroupAssociations + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.StoreItem.SwssItems + SwssItems + 0 + 10 + + true + true + true + true + true + true + true + + 0 + + + + + IPF + TeamChatHistory + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF + TeamsMessagesData + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + TemporarySaves + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Task + To-Do Search + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + Ulubione + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + UserCuratedContacts + 3 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + UserSocialActivityNotifications + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + Views + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + XrmActivityStream + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + XrmActivityStreamSearch + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + XrmCompanySearch + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + XrmDealSearch + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + XrmInsights + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + XrmProjects + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + XrmSearch + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + YammerData + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + + + + diff --git a/src/tests/data/ews/incremental/1.json b/src/tests/data/ews/incremental/1.json new file mode 100644 --- /dev/null +++ b/src/tests/data/ews/incremental/1.json @@ -0,0 +1,96 @@ +{ + "error": false, + "statusCode": 200, + "headers": { + "Cache-Control": [ + "private" + ], + "Transfer-Encoding": [ + "chunked" + ], + "Content-Type": [ + "text\/xml; charset=utf-8" + ], + "Server": [ + "Microsoft-HTTPAPI\/2.0" + ], + "X-NanoProxy": [ + "1,1" + ], + "X-AspNet-Version": [ + "4.0.30319" + ], + "Request-Id": [ + "0de708d9-ea99-409a-9a67-9c8506607510" + ], + "X-CalculatedFETarget": [ + "GV0P278CU003.internal.outlook.com" + ], + "Alt-Svc": [ + "h3=\":443\";ma=2592000,h3-29=\":443\";ma=2592000" + ], + "MS-CV": [ + "2QjnDZnqmkCaZ5yFBmB1EA.1.1" + ], + "Restrict-Access-Confirm": [ + "1" + ], + "X-BackEndHttpStatus": [ + "200,200" + ], + "X-BEServer": [ + "GV0P278MB1046" + ], + "X-BeSku": [ + "WCS7" + ], + "X-CalculatedBETarget": [ + "GV0P278MB1046.CHEP278.PROD.OUTLOOK.COM" + ], + "X-DiagInfo": [ + "GV0P278MB1046" + ], + "x-EwsHandler": [ + "FindItem" + ], + "X-FEEFZInfo": [ + "GVA" + ], + "X-FEProxyInfo": [ + "GV0P278CA0041" + ], + "X-FEServer": [ + "WA0P291CA0004" + ], + "x-ms-appId": [ + "6ce1e52b-cd1d-4663-abc3-368fba0bfae7" + ], + "X-Proxy-BackendServerStatus": [ + "200" + ], + "X-Proxy-RoutingCorrectness": [ + "1" + ], + "X-RUM-NotUpdateQueriedPath": [ + "1" + ], + "X-RUM-NotUpdateQueriedDbCopy": [ + "1" + ], + "X-RUM-Validated": [ + "1" + ], + "X-FirstHopCafeEFZ": [ + "WAW" + ], + "Strict-Transport-Security": [ + "max-age=31536000; includeSubDomains" + ], + "Set-Cookie": [ + "exchangecookie=69bae057f3b74f0fb7163f66ddd11493; expires=Fri, 11-Jul-2025 12:51:40 GMT; path=\/; secure; HttpOnly" + ], + "Date": [ + "Thu, 11 Jul 2024 12:51:39 GMT" + ] + } +} \ No newline at end of file diff --git a/src/tests/data/ews/incremental/1.xml b/src/tests/data/ews/incremental/1.xml new file mode 100644 --- /dev/null +++ b/src/tests/data/ews/incremental/1.xml @@ -0,0 +1,27 @@ + + + + + + + + + + NoError + + + + + IPM.Appointment + + + + IPM.Appointment + + + + + + + + diff --git a/src/tests/data/ews/incremental/4.json b/src/tests/data/ews/incremental/4.json new file mode 100644 --- /dev/null +++ b/src/tests/data/ews/incremental/4.json @@ -0,0 +1,96 @@ +{ + "error": false, + "statusCode": 200, + "headers": { + "Cache-Control": [ + "private" + ], + "Transfer-Encoding": [ + "chunked" + ], + "Content-Type": [ + "text\/xml; charset=utf-8" + ], + "Server": [ + "Microsoft-HTTPAPI\/2.0" + ], + "X-NanoProxy": [ + "1,1" + ], + "X-AspNet-Version": [ + "4.0.30319" + ], + "Request-Id": [ + "65d9caeb-2f07-ca8d-bd20-851f8dc232ed" + ], + "X-CalculatedFETarget": [ + "GV0P278CU002.internal.outlook.com" + ], + "Alt-Svc": [ + "h3=\":443\";ma=2592000,h3-29=\":443\";ma=2592000" + ], + "MS-CV": [ + "68rZZQcvjcq9IIUfjcIy7Q.1.1" + ], + "Restrict-Access-Confirm": [ + "1" + ], + "X-BackEndHttpStatus": [ + "200,200" + ], + "X-BEServer": [ + "GVAP278MB0389" + ], + "X-BeSku": [ + "WCS6" + ], + "X-CalculatedBETarget": [ + "GVAP278MB0389.CHEP278.PROD.OUTLOOK.COM" + ], + "X-DiagInfo": [ + "GVAP278MB0389" + ], + "x-EwsHandler": [ + "FindItem" + ], + "X-FEEFZInfo": [ + "GVA" + ], + "X-FEProxyInfo": [ + "GV0P278CA0020" + ], + "X-FEServer": [ + "WA0P291CA0004" + ], + "x-ms-appId": [ + "6ce1e52b-cd1d-4663-abc3-368fba0bfae7" + ], + "X-Proxy-BackendServerStatus": [ + "200" + ], + "X-Proxy-RoutingCorrectness": [ + "1" + ], + "X-RUM-NotUpdateQueriedPath": [ + "1" + ], + "X-RUM-NotUpdateQueriedDbCopy": [ + "1" + ], + "X-RUM-Validated": [ + "1" + ], + "X-FirstHopCafeEFZ": [ + "WAW" + ], + "Strict-Transport-Security": [ + "max-age=31536000; includeSubDomains" + ], + "Set-Cookie": [ + "exchangecookie=5ad29dedadde423c99430af280c2ae09; expires=Fri, 11-Jul-2025 12:51:49 GMT; path=\/; secure; HttpOnly" + ], + "Date": [ + "Thu, 11 Jul 2024 12:51:49 GMT" + ] + } +} \ No newline at end of file diff --git a/src/tests/data/ews/incremental/4.xml b/src/tests/data/ews/incremental/4.xml new file mode 100644 --- /dev/null +++ b/src/tests/data/ews/incremental/4.xml @@ -0,0 +1,35 @@ + + + + + + + + + + NoError + + + + + IPM.Contact + + + + IPM.DistList + + + + IPM.Contact + + + + IPM.Contact + + + + + + + + diff --git a/src/tests/data/ews/incremental/5.json b/src/tests/data/ews/incremental/5.json new file mode 100644 --- /dev/null +++ b/src/tests/data/ews/incremental/5.json @@ -0,0 +1,96 @@ +{ + "error": false, + "statusCode": 200, + "headers": { + "Cache-Control": [ + "private" + ], + "Transfer-Encoding": [ + "chunked" + ], + "Content-Type": [ + "text\/xml; charset=utf-8" + ], + "Server": [ + "Microsoft-HTTPAPI\/2.0" + ], + "X-NanoProxy": [ + "1,1" + ], + "X-AspNet-Version": [ + "4.0.30319" + ], + "Request-Id": [ + "75aec142-54d8-bfc0-c0e7-adc4e3f2ba14" + ], + "X-CalculatedFETarget": [ + "GV0P278CU005.internal.outlook.com" + ], + "Alt-Svc": [ + "h3=\":443\";ma=2592000,h3-29=\":443\";ma=2592000" + ], + "MS-CV": [ + "QsGuddhUwL\/A563E4\/K6FA.1.1" + ], + "Restrict-Access-Confirm": [ + "1" + ], + "X-BackEndHttpStatus": [ + "200,200" + ], + "X-BEServer": [ + "GV0P278MB0353" + ], + "X-BeSku": [ + "WCS6" + ], + "X-CalculatedBETarget": [ + "GV0P278MB0353.CHEP278.PROD.OUTLOOK.COM" + ], + "X-DiagInfo": [ + "GV0P278MB0353" + ], + "x-EwsHandler": [ + "GetItem" + ], + "X-FEEFZInfo": [ + "GVA" + ], + "X-FEProxyInfo": [ + "GV0P278CA0084" + ], + "X-FEServer": [ + "WA0P291CA0004" + ], + "x-ms-appId": [ + "6ce1e52b-cd1d-4663-abc3-368fba0bfae7" + ], + "X-Proxy-BackendServerStatus": [ + "200" + ], + "X-Proxy-RoutingCorrectness": [ + "1" + ], + "X-RUM-NotUpdateQueriedPath": [ + "1" + ], + "X-RUM-NotUpdateQueriedDbCopy": [ + "1" + ], + "X-RUM-Validated": [ + "1" + ], + "X-FirstHopCafeEFZ": [ + "WAW" + ], + "Strict-Transport-Security": [ + "max-age=31536000; includeSubDomains" + ], + "Set-Cookie": [ + "exchangecookie=08d3bd1184da4e9f8016984e26367d56; expires=Fri, 11-Jul-2025 12:51:50 GMT; path=\/; secure; HttpOnly" + ], + "Date": [ + "Thu, 11 Jul 2024 12:51:50 GMT" + ] + } +} \ No newline at end of file diff --git a/src/tests/data/ews/incremental/5.xml b/src/tests/data/ews/incremental/5.xml new file mode 100644 --- /dev/null +++ b/src/tests/data/ews/incremental/5.xml @@ -0,0 +1,49 @@ + + + + + + + + + + NoError + + + QkVHSU46VkNBUkQNClBST0ZJTEU6VkNBUkQNClZFUlNJT046My4wDQpNQUlMRVI6TWljcm9zb2Z0IEV4Y2hhbmdlDQpQUk9ESUQ6TWljcm9zb2Z0IEV4Y2hhbmdlDQpGTjpUZXN0IFN1cm5hbWUgMQ0KTjpTdXJuYW1lIDE7VGVzdDs7Ow0KTk9URToNCk9SRzo7DQpDTEFTUzpQVUJMSUMNCkFEUjtUWVBFPVdPUks6Ozs7Ozs7DQpBRFI7VFlQRT1IT01FOjs7Ozs7Ow0KQURSO1RZUEU9UE9TVEFMOjs7Ozs7Ow0KVEVMO1RZUEU9Q0VMTDoNClRFTDtUWVBFPVBBR0VSOg0KVEVMO1RZUEU9Q0FSOg0KVEVMO1RZUEU9Vk9JQ0U6DQpYLU1TLVNQT1VTRTtUWVBFPU46DQpYLU1TLU1BTkFHRVI7VFlQRT1OOg0KWC1NUy1BU1NJU1RBTlQ7VFlQRT1OOg0KVElUTEU6DQpVUkw7VFlQRT1IT01FOg0KVVJMO1RZUEU9V09SSzoNClJFVjtWQUxVRT1EQVRFLVRJTUU6MjAyNC0wNi0yNVQxMDo1NDo1NCwyMTRaDQpFTkQ6VkNBUkQNCg== + + false + en-US + 2024-06-25T09:54:54Z + + Test Surname 1 + Test + + Test + Surname 1 + Test Surname 1 + + + christian@outlook.com + + + + + + + + + + + Surname 1 + Q1ne1H54kk35i44UboHGPFRRPI8= + 2790877950c24ec1a3a9b41ce75aec8a + EXCH + + + + + + + + diff --git a/src/tests/data/ews/incremental/6.json b/src/tests/data/ews/incremental/6.json new file mode 100644 --- /dev/null +++ b/src/tests/data/ews/incremental/6.json @@ -0,0 +1,96 @@ +{ + "error": false, + "statusCode": 200, + "headers": { + "Cache-Control": [ + "private" + ], + "Transfer-Encoding": [ + "chunked" + ], + "Content-Type": [ + "text\/xml; charset=utf-8" + ], + "Server": [ + "Microsoft-HTTPAPI\/2.0" + ], + "X-NanoProxy": [ + "1,1" + ], + "X-AspNet-Version": [ + "4.0.30319" + ], + "Request-Id": [ + "75aec142-54d8-bfc0-c0e7-adc4e3f2ba14" + ], + "X-CalculatedFETarget": [ + "GV0P278CU005.internal.outlook.com" + ], + "Alt-Svc": [ + "h3=\":443\";ma=2592000,h3-29=\":443\";ma=2592000" + ], + "MS-CV": [ + "QsGuddhUwL\/A563E4\/K6FA.1.1" + ], + "Restrict-Access-Confirm": [ + "1" + ], + "X-BackEndHttpStatus": [ + "200,200" + ], + "X-BEServer": [ + "GV0P278MB0353" + ], + "X-BeSku": [ + "WCS6" + ], + "X-CalculatedBETarget": [ + "GV0P278MB0353.CHEP278.PROD.OUTLOOK.COM" + ], + "X-DiagInfo": [ + "GV0P278MB0353" + ], + "x-EwsHandler": [ + "GetItem" + ], + "X-FEEFZInfo": [ + "GVA" + ], + "X-FEProxyInfo": [ + "GV0P278CA0084" + ], + "X-FEServer": [ + "WA0P291CA0004" + ], + "x-ms-appId": [ + "6ce1e52b-cd1d-4663-abc3-368fba0bfae7" + ], + "X-Proxy-BackendServerStatus": [ + "200" + ], + "X-Proxy-RoutingCorrectness": [ + "1" + ], + "X-RUM-NotUpdateQueriedPath": [ + "1" + ], + "X-RUM-NotUpdateQueriedDbCopy": [ + "1" + ], + "X-RUM-Validated": [ + "1" + ], + "X-FirstHopCafeEFZ": [ + "WAW" + ], + "Strict-Transport-Security": [ + "max-age=31536000; includeSubDomains" + ], + "Set-Cookie": [ + "exchangecookie=08d3bd1184da4e9f8016984e26367d56; expires=Fri, 11-Jul-2025 12:51:50 GMT; path=\/; secure; HttpOnly" + ], + "Date": [ + "Thu, 11 Jul 2024 12:51:50 GMT" + ] + } +} \ No newline at end of file diff --git a/src/tests/data/ews/incremental/6.xml b/src/tests/data/ews/incremental/6.xml new file mode 100644 --- /dev/null +++ b/src/tests/data/ews/incremental/6.xml @@ -0,0 +1,49 @@ + + + + + + + + + + NoError + + + QkVHSU46VkNBUkQNClBST0ZJTEU6VkNBUkQNClZFUlNJT046My4wDQpNQUlMRVI6TWljcm9zb2Z0IEV4Y2hhbmdlDQpQUk9ESUQ6TWljcm9zb2Z0IEV4Y2hhbmdlDQpGTjpUZXN0IE5ldw0KTjpOZXc7VGVzdDs7Ow0KTk9URToNCk9SRzo7DQpDTEFTUzpQVUJMSUMNCkFEUjtUWVBFPVdPUks6Ozs7Ozs7DQpBRFI7VFlQRT1IT01FOjs7Ozs7Ow0KQURSO1RZUEU9UE9TVEFMOjs7Ozs7Ow0KVEVMO1RZUEU9Q0VMTDoNClRFTDtUWVBFPVBBR0VSOg0KVEVMO1RZUEU9Q0FSOg0KVEVMO1RZUEU9Vk9JQ0U6DQpYLU1TLVNQT1VTRTtUWVBFPU46DQpYLU1TLU1BTkFHRVI7VFlQRT1OOg0KWC1NUy1BU1NJU1RBTlQ7VFlQRT1OOg0KVElUTEU6DQpVUkw7VFlQRT1IT01FOg0KVVJMO1RZUEU9V09SSzoNClJFVjtWQUxVRT1EQVRFLVRJTUU6MjAyNC0wNi0yNVQxMDo1NDo1NCwyMTRaDQpFTkQ6VkNBUkQNCg== + + false + en-US + 2024-06-25T09:54:54Z + + Test New + Test + + Test + New + Test New + + + new@outlook.com + + + + + + + + + + + New + Q1ne1H54kk35i44UboHGPFRRPI8= + 2790877950c24ec1a3a9b41ce75aec8a + EXCH + + + + + + + + diff --git a/src/tests/data/ews/initial/0.json b/src/tests/data/ews/initial/0.json new file mode 100644 --- /dev/null +++ b/src/tests/data/ews/initial/0.json @@ -0,0 +1,96 @@ +{ + "error": false, + "statusCode": 200, + "headers": { + "Cache-Control": [ + "private" + ], + "Transfer-Encoding": [ + "chunked" + ], + "Content-Type": [ + "text\/xml; charset=utf-8" + ], + "Server": [ + "Microsoft-HTTPAPI\/2.0" + ], + "X-NanoProxy": [ + "1,1" + ], + "X-AspNet-Version": [ + "4.0.30319" + ], + "Request-Id": [ + "a4ce6838-81ac-65a7-4759-3d9294738779" + ], + "X-CalculatedFETarget": [ + "GV0P278CU004.internal.outlook.com" + ], + "Alt-Svc": [ + "h3=\":443\";ma=2592000,h3-29=\":443\";ma=2592000" + ], + "MS-CV": [ + "OGjOpKyBp2VHWT2SlHOHeQ.1.1" + ], + "Restrict-Access-Confirm": [ + "1" + ], + "X-BackEndHttpStatus": [ + "200,200" + ], + "X-BEServer": [ + "GVAP278MB0615" + ], + "X-BeSku": [ + "WCS6" + ], + "X-CalculatedBETarget": [ + "GVAP278MB0615.CHEP278.PROD.OUTLOOK.COM" + ], + "X-DiagInfo": [ + "GVAP278MB0615" + ], + "x-EwsHandler": [ + "FindFolder" + ], + "X-FEEFZInfo": [ + "GVA" + ], + "X-FEProxyInfo": [ + "GV0P278CA0060" + ], + "X-FEServer": [ + "WA0P291CA0004" + ], + "x-ms-appId": [ + "6ce1e52b-cd1d-4663-abc3-368fba0bfae7" + ], + "X-Proxy-BackendServerStatus": [ + "200" + ], + "X-Proxy-RoutingCorrectness": [ + "1" + ], + "X-RUM-NotUpdateQueriedPath": [ + "1" + ], + "X-RUM-NotUpdateQueriedDbCopy": [ + "1" + ], + "X-RUM-Validated": [ + "1" + ], + "X-FirstHopCafeEFZ": [ + "WAW" + ], + "Strict-Transport-Security": [ + "max-age=31536000; includeSubDomains" + ], + "Set-Cookie": [ + "exchangecookie=faf9d40d8bc14d53a013ecd1336e35b5; expires=Fri, 11-Jul-2025 12:51:36 GMT; path=\/; secure; HttpOnly" + ], + "Date": [ + "Thu, 11 Jul 2024 12:51:36 GMT" + ] + } +} \ No newline at end of file diff --git a/src/tests/data/ews/initial/0.xml b/src/tests/data/ews/initial/0.xml new file mode 100644 --- /dev/null +++ b/src/tests/data/ews/initial/0.xml @@ -0,0 +1,7139 @@ + + + + + + + + + + NoError + + + + + + IPF.Note + AllCategorizedItems + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + AllContacts + 3 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + AllContactsExtended + 3 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF + AllItems + 230 + 0 + + true + true + true + true + true + true + true + + 110 + + + + + IPF.Note + AllPersonMetadata + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Task + AllTodoTasks + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + ApplicationDataRoot + 0 + 56 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 00000002-0000-0ff1-ce00-000000000000 + 0 + 3 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + HxNotificationSettings + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 00000006-0000-0ff1-ce00-000000000000 + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + GlobalSearchHistory + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 13937bba-652e-4c46-b222-3003f4d1ff97 + 0 + 3 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + ContextDataFast + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + ContextMetadata + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + UserInteractionsFast + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 1caee58f-eb14-4a6b-9339-1fe2ddf6692b + 0 + 2 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + Recent + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + Settings + 2 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 1e70cd27-4707-4589-8ec5-9bd20c472a46 + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 224fffa9-a547-4c78-ab95-3aacd66c3e99 + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + FeaturesManagementCollection_1 + 3 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 32d4b5e5-7d33-4e7f-b073-f8cffbbb47a1 + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + outlookfavorites + 3 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 33b68b23-a6c2-4684-99a0-fa3832792226 + 0 + 2 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + AggregationV2BackfillStateCollection + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + RelevanceDailyAggregation + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 34421fbe-f100-4e5b-9c46-2fea25aa7b88 + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + Contacts + 6 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 35d54a08-36c9-4847-9018-93934c62740c + 0 + 3 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + PeoplePredictions.FeedbackEntries + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + PeoplePredictions.RequestEntries + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + PeoplePredictions.UserProfile + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 3873c4f1-2162-4ddb-96e6-232e4eddeedc + 0 + 4 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SEED_PeopleIntegrityCheckerStateCollection_v2 + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SEED_ScdIntegrityCheckerStateCollection_v2 + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 394866fc-eedb-4f01-8536-3ff84b16be2a + 0 + 3 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + AssociationBackfillStatus + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + Favorites + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + InsightInstancesActions + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 3b2e5a14-128d-48aa-b581-482aac616d32 + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 3c896ded-22c5-450f-91f6-3d1ef0848f6e + 0 + 42 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + ActionExecutions + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + ActivitiesDaily + 58 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + ActivitiesWeekly + 8 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + AfterHoursEmailImpact + 50 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + AutomaticRepliesHistory + 105 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + ChatsInterruptionStatistics + 49 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + ComputeLogs + 38 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + CumulativeNetworkSnapshot + 3 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + CumulativeOutOfOfficeClustering + 106 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + DailyActivityTimeBins + 56 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + DailyAppointments + 85 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + DailyInteractions + 50 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + DailyNetworkSnapshot + 51 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + DelayedEmail + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + DeliverCardEvents + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + DetailedMeetings + 51 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + EmailActionStatistics + 50 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + EmailGrazerData + 50 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + EmfResponses + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + FoodForThoughtRanking + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + HeterogeneousItems + 10 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + ImportantContact + 3 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + InsightsEngagement + 10 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + MailActivityCompactSignalBatch + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + ManagementOperationExecutionRecords + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + MeetingActionStatistics + 9 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + MeetingResponseActivity + 6 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + OutcomeStates + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + OutOfOffice + 44 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + ProgramMetrics + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SegmentsStateRecord + 18 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SentMailLogs + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SigsChatsAndCallsCompactSignalBatch + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + UnifiedCardEngagements + 30 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + UserConfiguration + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + UserProgramInstances + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + WeeklyEmbeddingBasedUserTimePrediction + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + WeeklyInteractions + 27 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + WeeklyOutOfOfficeAndWorkingDay + 28 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + WeeklyOutOfRoutineMeetingScorePDF + 30 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + WeeklyOutOfRoutineMeetingTimes + 61 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + WeeklyWorkplaceActivityEmbedding + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 3e3c8645-20a6-4c6e-8355-c34cbbe04585 + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + PintSigsMsGraphState + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 42c2c67f-2760-4f42-b0c4-ef5c3854a0c2 + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + CollabObjects + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 43375d74-c6a5-4d4e-a0a3-de139860ea75 + 0 + 2 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + ElcArchiveProcessorStatsSdsCollection + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + OverallArchivingStatsSdsCollection + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 441509e5-a165-4363-8ee7-bcf0b7d26739 + 0 + 3 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + GenericWorkflowProcessor.SessionManager.Data + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + Idf + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + IdfMeeting + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 4787c7ff-7cea-43db-8d0d-919f15c6354b + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + VivaSales + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 48af08dc-f6d2-435f-b2a7-069abd99c086 + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + InsightsProvidersSettings + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 49499048-0129-47f5-b95e-f9d315b861a6 + 0 + 2 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + OutlookAccountCloudSettings + 3 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + OutlookCloudSettings + 5 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 497effe9-df71-4043-a8bb-14cf78c4b63b + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + EACUserPreferences + 5 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 4e445925-163e-42ca-b801-9073bfa46d17 + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + NewsSubscriptionSourcesv2 + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 59cc317d-5453-4fcd-ab98-60552b158926 + 0 + 6 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + AlgorithmRunStatus + 9 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + CDDS_SuggestionCheckpoint + 2 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + ContactFeedback + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + ContactMergeSuggestions + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + HiddenDuplicates + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + HideSettings + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 644c1b11-f63f-45fa-826b-a9d2801db711 + 0 + 3 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + _PolicyContainer + 3 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + YWxlY0BhcGhlbGVpYWl0Lm9ubWljcm9zb2Z0LmNvbQ==_LabelFile + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + YWxlY0BhcGhlbGVpYWl0Lm9ubWljcm9zb2Z0LmNvbQ==_PolicyContainer + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 66a88757-258c-4c72-893c-3e8bed4d6899 + 0 + 31 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + ScopeEntities + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.Apps + 3 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.CalendarEvents + 10 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.CollaborationNetworkEntities + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.ContentDomain + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.EmailEntities + 3 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.EmailTokens + 2 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.EntityServe + 2 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.EntityServe.Bookmarks + 2 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.EntityServe.Links + 4 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.EntityServe.Locations + 2 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.EntityServe.Qnas + 2 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.FreshHistory + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.FreshSharePointFiles + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.FreshSharePointSites + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.GroupsRoomsMiscIndex + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.Notes + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.People + 11 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.PeopleCache + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.PeopleIndex + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.RecentEmailItems + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.RecommendationsService + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.RecommendationsServiceProcessor + 2 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.Scope + 2 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.SearchHistory.Main + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.SearchHistoryState + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.SharePointDocuments + 5 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.SkillEntities + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.TeamsAndChannels + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.TeamsEntities + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SubstrateSearch.Topics + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 6cd5135b-7a07-43ec-acc2-b5e27dc628cb + 0 + 3 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + currentuser + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + neighbors + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + OfficeFeedSdsCacheCollection + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 766ef332-38e5-4cb4-920c-baa478e39fd9 + 0 + 3 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + CrawlerExecutionInfoCollection + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 7a5fbd1c-3e6d-461a-9075-83049393b3a7 + 0 + 7 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + AcronymAggregationState + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + AcronymService.SessionManager.Data + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + ConceptAggregationSessionManager.Data + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + NicknamesAllInbox + 2 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SimpleAcronymsIndex + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SimpleAcronymsIndexElysium + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SimpleUserContextIndex + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 7aadb841-2368-4d24-a373-94d0ba1f077a + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + outlookspaces + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 7ae974c5-1af7-4923-af3a-fb1fd14dcb7e + 0 + 9 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + AppBarTiles + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + FloodgateSurvey + 3 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + GetStartedStore + 20 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + lightning + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + LightningSharedStore + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + LightningStore + 67 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + OutlookEndpointDataCollection + 2 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + OutlookOptionsV3 + 7 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + WhatsNewStore + 97 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 7e02887d-df1d-45a4-af52-dcee2e585eee + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + UserEnablementStatus + 8 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 80723a00-368e-4d64-8281-210e49e593a8 + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + ActivityFeed_201905 + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 82d8ab62-be52-a567-14ea-1616c4ee06c4 + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + ActorAnalyticsProcessorState + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 8a18aa92-0a1e-4e06-abd0-e118fa4787b1 + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + GraphMetaColl + 26 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 8c22b648-ee54-4ece-a4ca-3015b6d24f8e + 0 + 20 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + DIF + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + Images + 2 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + source_contactsync + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + source_meetinginsightssetting + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + source_officegraphvisibilitysetting + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + source_sourceaad + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + source_sourceconnector + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + source_sourceemailaddressdisplaynames + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + source_sourcemanagerchain + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + source_sourcemsgraph + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + source_sourcenamepronunciation + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + source_sourcenone + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + source_sourceorganizationheadcount + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + source_sourcephotoetag + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + source_sourceupa + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + source_sourceuserdefined + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + source_userdefinedsettings + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SQI_FI + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + view_profilev2 + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + view_settingsv2 + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 94c63fef-13a3-47bc-8074-75af8c65887a + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + DelveCollection + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + 97cb1f73-50df-47d1-8fb0-0271f2728514 + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + CleanupProcessorState + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + a3883eba-fbe9-48bd-9ed3-dca3e0e84250 + 0 + 4 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + AggregatedLinks + 9 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + EmailsIndexV1 + 65 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + LinkFiltersMetadataIndex + 3 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + LinksIndex + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + a6061a71-f529-4ca2-bc9d-c8085ecbf3ca + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + EdgeSettings + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + adcd8967-0799-4ec0-bfc8-dcf85fd84767 + 0 + 2 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + CssProcessingState + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + ae8e128e-080f-4086-b0e3-4c19301ada69 + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + Scheduling + 2 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + b669c6ea-1adf-453f-b8bc-6d526592b419 + 0 + 3 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + FocusedInboxMailboxData + 2 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + NudgeCandidates + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + ScenarioTracking + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + b6e65498-8dce-4d57-8de9-1269fcfcf6ce + 0 + 6 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + KeyphraseRelationshipsSessionManager.Data + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + UserDocKpeStats + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + UserDocWithKpes + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + UserKpes + 2 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + UserKpeState + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + UserStatistics + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + c9224372-5534-42cb-a48b-8db4f4a3892e + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + TeamsCalendar.SSMeetingPropsSync + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + c94eb245-f5ab-4fea-a534-841091469193 + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + ic3usersettings + 13 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + d297b9ff-5d5b-4bce-8ed4-eedb1431bf61 + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + NucleusProperties + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + d396de1f-10d4-4023-aae2-5bb3d724ba9a + 0 + 3 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + FolderGroups-DefaultCollection + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + settings + 6 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + TasksDataMarker_v9 + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + d71dfe16-1070-48f3-bd3a-c3ec919d34e7 + 0 + 2 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + TxpAutoblocking + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + TxpUserSettings + 10 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + d8cbf452-c2df-4756-95a5-8aa23fedc3ce + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + UserMigrationDetails + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + e69932cd-f814-4087-8ab1-5ab3f1ad18eb + 0 + 2 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + e7762c80-392b-4278-80fa-a8fda80b129c + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + CMUState + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + e7f049f2-9dc5-4301-88a2-121b268ad42f + 0 + 2 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + Common + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SharingSuggestion + 2 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + f08262d6-bf02-4e1e-bdef-e95e2f0a940f + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + GlowCollection + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + f164ee43-46e5-4f7c-b5ff-2d1abcd4ce7e + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + PersonalProfileVector_AnalyzerStates + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + f3f64fec-ecee-4e9a-9eed-a36a5e421300 + 0 + 10 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + IdfEmailPoi + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + IdfInboxPoi + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + IdfMeetingPoi + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + InferredLanguage + 2 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SlpJobs + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SpeechNGrams + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SpeechTrimmedLms + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SpeechUserDocumentNGrams + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SpeechUserDocumentSentences + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPM.ApplicationData + SpeechUserDocumentsHistory + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + BrokerSubscriptions + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + BulkActions + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + CalendarSharingCacheCollection + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + Common Views + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + ComplianceMetadata + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + Connectors + 0 + 2 + + true + true + true + true + true + true + true + + 0 + + + + + ConnectorConfigurations + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.StoreItem.CrawlerData + CrawlerData + 35 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + Deferred Action + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.StoreItem.DlpPolicyEvaluation + DlpPolicyEvaluation + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + Document Centric Conversations + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + ExchangeODataSyncData + 199 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + ExchangeSyncData + 0 + 3 + + true + true + true + true + true + true + true + + 0 + + + + + AirSync-iPhone-J97G80P7O916504POMJIHAJE70 + 10 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + AirSync-TestActiveSyncConnectivity-430847304 + 5 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + Hx-Outlook-B57C063B9A6C46ECAD4C159C1E161B14 + 0 + 2 + + true + true + true + true + true + true + true + + 0 + + + + + OutlookServiceActionQueue + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + Policy + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + Finder + 0 + 2 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + OwaFV15.1AllFocusedAQMkAGEzOGRlODRiLTBkN2ItNDgwZS04ZDJmLTM5NDEyY2Q0NABkNDgALgAAA722UNhKUbZNrFYGsDU7Na0BACzZqOGSdeVFg3+lsLwmpuUAAAIBDAAAAA== + 101 + 0 + + true + true + true + true + true + true + true + + 95 + + + + + IPF.Note + OwaFV15.1AllOtherAQMkAGEzOGRlODRiLTBkN2ItNDgwZS04ZDJmLTM5NDEyY2Q0NABkNDgALgAAA722UNhKUbZNrFYGsDU7Na0BACzZqOGSdeVFg3+lsLwmpuUAAAIBDAAAAA== + 15 + 0 + + true + true + true + true + true + true + true + + 15 + + + + + IPF.Task + Folder Memberships + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Task + Flagged Emails + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + Folder nadrzędny magazynu informacji + 0 + 19 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + Archiwum + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Configuration + Conversation Action Settings + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Journal + Dziennik + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + Elementy usunięte + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + Elementy wysłane + 5 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.StoreItem.EventCheckPoints + EventCheckPoints + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Contact + ExternalContacts + 0 + 0 + + true + true + true + true + true + true + true + + + + + + IPF + Folder główny usługi Yammer + 0 + 3 + + true + true + true + true + true + true + true + + 0 + + + + + IPF + Feeds + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF + Inbound + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF + Outbound + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + Historia konwersacji + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.SkypeTeams.Message + Czat zespołu + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Appointment + Calendar + 2 + 2 + + true + true + true + true + true + true + true + + + + + + IPF.Appointment + United States holidays + 97 + 0 + + true + true + true + true + true + true + true + + + + + + IPF.Appointment.Birthday + Urodziny + 0 + 0 + + true + true + true + true + true + true + true + + + + + + IPF.Contact + Kontakty + 3 + 7 + + true + true + true + true + true + true + true + + + + + + IPF.Contact.MOC.QuickContacts + {06967759-274D-40B2-A3EB-D7F9E73727D7} + 0 + 0 + + true + true + true + true + true + true + true + + + + + + IPF.Contact.MOC.ImContactList + {A9E2BC46-B3A0-4243-B315-60D991004455} + 0 + 0 + + true + true + true + true + true + true + true + + + + + + IPF.Contact.Company + Firmy + 0 + 0 + + true + true + true + true + true + true + true + + + + + + IPF.Contact.GalContacts + GAL Contacts + 0 + 0 + + true + true + true + true + true + true + true + + + + + + IPF.Contact.OrganizationalContacts + Organizational Contacts + 0 + 0 + + true + true + true + true + true + true + true + + + + + + IPF.Contact.PeopleCentricConversationBuddies + PeopleCentricConversation Buddies + 0 + 0 + + true + true + true + true + true + true + true + + + + + + IPF.Contact.RecipientCache + Recipient Cache + 0 + 0 + + true + true + true + true + true + true + true + + + + + + IPF.Contact.MeContact + MeContact + 0 + 0 + + true + true + true + true + true + true + true + + + + + + IPF.StickyNote + Notatki + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Files + Pliki + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + Skrzynka nadawcza + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + Skrzynka odbiorcza + 116 + 0 + + true + true + true + true + true + true + true + + 110 + + + + + IPF.Note + Wersje robocze + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + Wiadomości-śmieci + 0 + 0 + + true + true + true + true + true + true + true + + 3dbb5f39-dc76-4916-9db3-fa9191760a55 + 0 + + + + + IPF.Task + Tasks + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + Freebusy Data + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.StoreItem.FreeBusyCache + FreeBusyLocalCache + 2 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + FreeBusyLocalCacheSubscriptions + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + GraphFilesAndWorkingSetSearchFolder + 64 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + GraphStore + 0 + 2 + + true + true + true + true + true + true + true + + 0 + + + + + GraphRelations + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + Inference + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + MailboxAssociations + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + MailboxMoveHistory + 4 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + MailboxReplicationService Index + 4 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + MergedViewFolderCollection + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + MessageIngestion + 0 + 1 + + true + true + true + true + true + true + true + + 0 + + + + + Yammer + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + Moje kontakty + 3 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + O365 Suite Notifications + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF + OneDriveRoot + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + OneNotePagePreviews + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Task + Orion Notes + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + OutlookExtensions + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + PACE + 31 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + People I Know + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + PeopleConnect + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + PeoplePublicData + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + Outlook.Reminder + Przypomnienia + 21 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + QuarantinedEmail + 0 + 1 + + true + true + true + true + true + true + true + + cce0d6e6-b69b-410a-907d-06dc2071ab58 + 0 + + + + + QuarantinedEmailDefaultCategory + 0 + 4 + + true + true + true + true + true + true + true + + cce0d6e6-b69b-410a-907d-06dc2071ab58 + 0 + + + + + QedcDefaultRetention + 0 + 0 + + true + true + true + true + true + true + true + + cce0d6e6-b69b-410a-907d-06dc2071ab58 + 0 + + + + + QedcLongRetention + 0 + 0 + + true + true + true + true + true + true + true + + cce0d6e6-b69b-410a-907d-06dc2071ab58 + 0 + + + + + QedcMediumRetention + 0 + 0 + + true + true + true + true + true + true + true + + cce0d6e6-b69b-410a-907d-06dc2071ab58 + 0 + + + + + QedcShortRetention + 0 + 0 + + true + true + true + true + true + true + true + + cce0d6e6-b69b-410a-907d-06dc2071ab58 + 0 + + + + + Recoverable Items + 0 + 6 + + true + true + false + false + false + + + true + true + true + true + true + true + true + + 0 + + + + + Audits + 12 + 0 + + true + true + false + false + false + + + true + true + true + true + true + true + true + + 0 + + + + + Calendar Logging + 0 + 0 + + true + true + false + false + false + + + true + true + true + true + true + true + true + + 0 + + + + + Deletions + 0 + 0 + + true + true + false + false + false + + + true + true + true + true + true + true + true + + 0 + + + + + Purges + 2 + 0 + + true + true + false + false + false + + + true + true + true + true + true + true + true + + 0 + + + + + SubstrateHolds + 0 + 0 + + true + true + false + false + false + + + true + true + true + true + true + true + true + + 0 + + + + + Versions + 0 + 0 + + true + true + false + false + false + + + true + true + true + true + true + true + true + + 0 + + + + + IPF.StoreItem.RecoveryPoints + RecoveryPoints + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + RelevantContacts + 3 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + Schedule + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + SearchFoldersView + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.StoreItem.ShadowItems + ShadowItems + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + SharedFilesSearchFolder + 63 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + SharePointNotifications + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + Sharing + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + Shortcuts + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + ShortNotes + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + SkypeSpacesData + 0 + 3 + + true + true + true + true + true + true + true + + 0 + + + + + SkypeMessages + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + TeamsMeetings + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + TeamsMessages + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + Spooler Queue + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + SpoolsPresentSharedItemsSearchFolder + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + SpoolsSearchFolder + 8 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF + SubstrateFiles + 0 + 3 + + true + true + true + true + true + true + true + + 0 + + + + + ClassicAttachments + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.StoreItem.Signal + GraphWorkingSet + 64 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + SPOOLS + 8 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + SuggestedUserGroupAssociations + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.StoreItem.SwssItems + SwssItems + 0 + 10 + + true + true + true + true + true + true + true + + 0 + + + + + IPF + TeamChatHistory + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF + TeamsMessagesData + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + TemporarySaves + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Task + To-Do Search + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + Ulubione + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + UserCuratedContacts + 3 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + UserSocialActivityNotifications + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + Views + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + XrmActivityStream + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + XrmActivityStreamSearch + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + XrmCompanySearch + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + XrmDealSearch + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + XrmInsights + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + XrmProjects + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + IPF.Note + XrmSearch + 1 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + YammerData + 0 + 0 + + true + true + true + true + true + true + true + + 0 + + + + + + + + diff --git a/src/tests/data/ews/initial/1.json b/src/tests/data/ews/initial/1.json new file mode 100644 --- /dev/null +++ b/src/tests/data/ews/initial/1.json @@ -0,0 +1,96 @@ +{ + "error": false, + "statusCode": 200, + "headers": { + "Cache-Control": [ + "private" + ], + "Transfer-Encoding": [ + "chunked" + ], + "Content-Type": [ + "text\/xml; charset=utf-8" + ], + "Server": [ + "Microsoft-HTTPAPI\/2.0" + ], + "X-NanoProxy": [ + "1,1" + ], + "X-AspNet-Version": [ + "4.0.30319" + ], + "Request-Id": [ + "0de708d9-ea99-409a-9a67-9c8506607510" + ], + "X-CalculatedFETarget": [ + "GV0P278CU003.internal.outlook.com" + ], + "Alt-Svc": [ + "h3=\":443\";ma=2592000,h3-29=\":443\";ma=2592000" + ], + "MS-CV": [ + "2QjnDZnqmkCaZ5yFBmB1EA.1.1" + ], + "Restrict-Access-Confirm": [ + "1" + ], + "X-BackEndHttpStatus": [ + "200,200" + ], + "X-BEServer": [ + "GV0P278MB1046" + ], + "X-BeSku": [ + "WCS7" + ], + "X-CalculatedBETarget": [ + "GV0P278MB1046.CHEP278.PROD.OUTLOOK.COM" + ], + "X-DiagInfo": [ + "GV0P278MB1046" + ], + "x-EwsHandler": [ + "FindItem" + ], + "X-FEEFZInfo": [ + "GVA" + ], + "X-FEProxyInfo": [ + "GV0P278CA0041" + ], + "X-FEServer": [ + "WA0P291CA0004" + ], + "x-ms-appId": [ + "6ce1e52b-cd1d-4663-abc3-368fba0bfae7" + ], + "X-Proxy-BackendServerStatus": [ + "200" + ], + "X-Proxy-RoutingCorrectness": [ + "1" + ], + "X-RUM-NotUpdateQueriedPath": [ + "1" + ], + "X-RUM-NotUpdateQueriedDbCopy": [ + "1" + ], + "X-RUM-Validated": [ + "1" + ], + "X-FirstHopCafeEFZ": [ + "WAW" + ], + "Strict-Transport-Security": [ + "max-age=31536000; includeSubDomains" + ], + "Set-Cookie": [ + "exchangecookie=69bae057f3b74f0fb7163f66ddd11493; expires=Fri, 11-Jul-2025 12:51:40 GMT; path=\/; secure; HttpOnly" + ], + "Date": [ + "Thu, 11 Jul 2024 12:51:39 GMT" + ] + } +} \ No newline at end of file diff --git a/src/tests/data/ews/initial/1.xml b/src/tests/data/ews/initial/1.xml new file mode 100644 --- /dev/null +++ b/src/tests/data/ews/initial/1.xml @@ -0,0 +1,27 @@ + + + + + + + + + + NoError + + + + + IPM.Appointment + + + + IPM.Appointment + + + + + + + + diff --git a/src/tests/data/ews/initial/2.json b/src/tests/data/ews/initial/2.json new file mode 100644 --- /dev/null +++ b/src/tests/data/ews/initial/2.json @@ -0,0 +1,96 @@ +{ + "error": false, + "statusCode": 200, + "headers": { + "Cache-Control": [ + "private" + ], + "Transfer-Encoding": [ + "chunked" + ], + "Content-Type": [ + "text\/xml; charset=utf-8" + ], + "Server": [ + "Microsoft-HTTPAPI\/2.0" + ], + "X-NanoProxy": [ + "1,1" + ], + "X-AspNet-Version": [ + "4.0.30319" + ], + "Request-Id": [ + "a48823f0-3a1b-590e-4128-026b3aa867e7" + ], + "X-CalculatedFETarget": [ + "GV0P278CU002.internal.outlook.com" + ], + "Alt-Svc": [ + "h3=\":443\";ma=2592000,h3-29=\":443\";ma=2592000" + ], + "MS-CV": [ + "8COIpBs6DllBKAJrOqhn5w.1.1" + ], + "Restrict-Access-Confirm": [ + "1" + ], + "X-BackEndHttpStatus": [ + "200,200" + ], + "X-BEServer": [ + "GV0P278MB1143" + ], + "X-BeSku": [ + "WCS7" + ], + "X-CalculatedBETarget": [ + "GV0P278MB1143.CHEP278.PROD.OUTLOOK.COM" + ], + "X-DiagInfo": [ + "GV0P278MB1143" + ], + "x-EwsHandler": [ + "GetItem" + ], + "X-FEEFZInfo": [ + "GVA" + ], + "X-FEProxyInfo": [ + "GV0P278CA0020" + ], + "X-FEServer": [ + "WA0P291CA0004" + ], + "x-ms-appId": [ + "6ce1e52b-cd1d-4663-abc3-368fba0bfae7" + ], + "X-Proxy-BackendServerStatus": [ + "200" + ], + "X-Proxy-RoutingCorrectness": [ + "1" + ], + "X-RUM-NotUpdateQueriedPath": [ + "1" + ], + "X-RUM-NotUpdateQueriedDbCopy": [ + "1" + ], + "X-RUM-Validated": [ + "1" + ], + "X-FirstHopCafeEFZ": [ + "WAW" + ], + "Strict-Transport-Security": [ + "max-age=31536000; includeSubDomains" + ], + "Set-Cookie": [ + "exchangecookie=80fb424f92194e4d8d138e60ef6f4d89; expires=Fri, 11-Jul-2025 12:51:40 GMT; path=\/; secure; HttpOnly" + ], + "Date": [ + "Thu, 11 Jul 2024 12:51:39 GMT" + ] + } +} \ No newline at end of file diff --git a/src/tests/data/ews/initial/2.xml b/src/tests/data/ews/initial/2.xml new file mode 100644 --- /dev/null +++ b/src/tests/data/ews/initial/2.xml @@ -0,0 +1,65 @@ + + + + + + + + + + NoError + + + QkVHSU46VkNBTEVOREFSDQpNRVRIT0Q6UFVCTElTSA0KUFJPRElEOk1pY3Jvc29mdCBFeGNoYW5nZSBTZXJ2ZXIgMjAxMA0KVkVSU0lPTjoyLjANCkJFR0lOOlZUSU1FWk9ORQ0KVFpJRDpDZW50cmFsIEV1cm9wZWFuIFN0YW5kYXJkIFRpbWUNCkJFR0lOOlNUQU5EQVJEDQpEVFNUQVJUOjE2MDEwMTAxVDAzMDAwMA0KVFpPRkZTRVRGUk9NOiswMjAwDQpUWk9GRlNFVFRPOiswMTAwDQpSUlVMRTpGUkVRPVlFQVJMWTtJTlRFUlZBTD0xO0JZREFZPS0xU1U7QllNT05USD0xMA0KRU5EOlNUQU5EQVJEDQpCRUdJTjpEQVlMSUdIVA0KRFRTVEFSVDoxNjAxMDEwMVQwMjAwMDANClRaT0ZGU0VURlJPTTorMDEwMA0KVFpPRkZTRVRUTzorMDIwMA0KUlJVTEU6RlJFUT1ZRUFSTFk7SU5URVJWQUw9MTtCWURBWT0tMVNVO0JZTU9OVEg9Mw0KRU5EOkRBWUxJR0hUDQpFTkQ6VlRJTUVaT05FDQpCRUdJTjpWRVZFTlQNCk9SR0FOSVpFUjtDTj1BbGVrc2FuZGVyIE1hY2huaWFrOm1haWx0bzp0ZXN0QGtvbGFiLm9yZw0KQVRURU5ERUU7Uk9MRT1SRVEtUEFSVElDSVBBTlQ7UEFSVFNUQVQ9TkVFRFMtQUNUSU9OO1JTVlA9VFJVRTtDTj1BbGVrc2FuZGVyDQogIE1hY2huaWFrOm1haWx0bzp0ZXN0QGtvbGFiLm9yZw0KQVRURU5ERUU7Uk9MRT1SRVEtUEFSVElDSVBBTlQ7UEFSVFNUQVQ9TkVFRFMtQUNUSU9OO1JTVlA9VFJVRTtDTj1BbGVjIE1hY2huDQogaWFrOm1haWx0bzphbGVjQG91dGxvb2suY29tDQpERVNDUklQVElPTjoqdGVzdCB0byBtcyoNClVJRDoxRjNDMTNEN0U5OTY0MkE3NUFCRTIzRDUwNDg3QjQ1NC04RkU2OEIyRTY4RTFCMzQ4DQpTVU1NQVJZOnRlc3QgdG8gbXMNCkRUU1RBUlQ7VFpJRD1DZW50cmFsIEV1cm9wZWFuIFN0YW5kYXJkIFRpbWU6MjAyMzExMjFUMTIwMDAwDQpEVEVORDtUWklEPUNlbnRyYWwgRXVyb3BlYW4gU3RhbmRhcmQgVGltZToyMDIzMTEyMVQxMjMwMDANCkNMQVNTOlBVQkxJQw0KUFJJT1JJVFk6NQ0KRFRTVEFNUDoyMDIzMTEyMFQxNDUwMDVaDQpUUkFOU1A6T1BBUVVFDQpTVEFUVVM6Q09ORklSTUVEDQpTRVFVRU5DRTowDQpYLU1JQ1JPU09GVC1DRE8tQVBQVC1TRVFVRU5DRTowDQpYLU1JQ1JPU09GVC1DRE8tT1dORVJBUFBUSUQ6MA0KWC1NSUNST1NPRlQtQ0RPLUJVU1lTVEFUVVM6VEVOVEFUSVZFDQpYLU1JQ1JPU09GVC1DRE8tSU5URU5ERURTVEFUVVM6QlVTWQ0KWC1NSUNST1NPRlQtQ0RPLUFMTERBWUVWRU5UOkZBTFNFDQpYLU1JQ1JPU09GVC1DRE8tSU1QT1JUQU5DRToxDQpYLU1JQ1JPU09GVC1DRE8tSU5TVFRZUEU6MA0KWC1NSUNST1NPRlQtRE9OT1RGT1JXQVJETUVFVElORzpGQUxTRQ0KWC1NSUNST1NPRlQtRElTQUxMT1ctQ09VTlRFUjpGQUxTRQ0KWC1NSUNST1NPRlQtUkVRVUVTVEVEQVRURU5EQU5DRU1PREU6REVGQVVMVA0KWC1NSUNST1NPRlQtSVNSRVNQT05TRVJFUVVFU1RFRDpUUlVFDQpFTkQ6VkVWRU5UDQpFTkQ6VkNBTEVOREFSDQo= + + test to ms + + + + + + + + + false + false + 1F3C13D7E99642A75ABE23D50487B454-8FE68B2E68E1B348 + 2023-11-21T11:00:00Z + 2023-11-21T11:30:00Z + Tentative + Single + + + Aleksander Machniak + test@kolab.org + SMTP + Contact + + + + + + Aleksander Machniak + test@kolab.org + SMTP + Contact + + Unknown + + + + Alec Machniak + test@outlook.com + SMTP + Mailbox + + Unknown + + + + + + + + + diff --git a/src/tests/data/ews/initial/3.json b/src/tests/data/ews/initial/3.json new file mode 100644 --- /dev/null +++ b/src/tests/data/ews/initial/3.json @@ -0,0 +1,96 @@ +{ + "error": false, + "statusCode": 200, + "headers": { + "Cache-Control": [ + "private" + ], + "Transfer-Encoding": [ + "chunked" + ], + "Content-Type": [ + "text\/xml; charset=utf-8" + ], + "Server": [ + "Microsoft-HTTPAPI\/2.0" + ], + "X-NanoProxy": [ + "1,1" + ], + "X-AspNet-Version": [ + "4.0.30319" + ], + "Request-Id": [ + "eb8edd0a-70f5-a87e-535b-5bedf507e372" + ], + "X-CalculatedFETarget": [ + "ZR0P278CU012.internal.outlook.com" + ], + "Alt-Svc": [ + "h3=\":443\";ma=2592000,h3-29=\":443\";ma=2592000" + ], + "MS-CV": [ + "Ct2O6\/VwfqhTW1vt9Qfjcg.1.1" + ], + "Restrict-Access-Confirm": [ + "1" + ], + "X-BackEndHttpStatus": [ + "200,200" + ], + "X-BEServer": [ + "ZRAP278MB0826" + ], + "X-BeSku": [ + "WCS7" + ], + "X-CalculatedBETarget": [ + "ZRAP278MB0826.CHEP278.PROD.OUTLOOK.COM" + ], + "X-DiagInfo": [ + "ZRAP278MB0826" + ], + "x-EwsHandler": [ + "GetItem" + ], + "X-FEEFZInfo": [ + "ZRH" + ], + "X-FEProxyInfo": [ + "ZR0P278CA0210" + ], + "X-FEServer": [ + "WA0P291CA0004" + ], + "x-ms-appId": [ + "6ce1e52b-cd1d-4663-abc3-368fba0bfae7" + ], + "X-Proxy-BackendServerStatus": [ + "200" + ], + "X-Proxy-RoutingCorrectness": [ + "1" + ], + "X-RUM-NotUpdateQueriedPath": [ + "1" + ], + "X-RUM-NotUpdateQueriedDbCopy": [ + "1" + ], + "X-RUM-Validated": [ + "1" + ], + "X-FirstHopCafeEFZ": [ + "WAW" + ], + "Strict-Transport-Security": [ + "max-age=31536000; includeSubDomains" + ], + "Set-Cookie": [ + "exchangecookie=fff7d362128747ce83b755cc7b5a43c6; expires=Fri, 11-Jul-2025 12:51:41 GMT; path=\/; secure; HttpOnly" + ], + "Date": [ + "Thu, 11 Jul 2024 12:51:40 GMT" + ] + } +} \ No newline at end of file diff --git a/src/tests/data/ews/initial/3.xml b/src/tests/data/ews/initial/3.xml new file mode 100644 --- /dev/null +++ b/src/tests/data/ews/initial/3.xml @@ -0,0 +1,56 @@ + + + + + + + + + + NoError + + + QkVHSU46VkNBTEVOREFSDQpNRVRIT0Q6UFVCTElTSA0KUFJPRElEOk1pY3Jvc29mdCBFeGNoYW5nZSBTZXJ2ZXIgMjAxMA0KVkVSU0lPTjoyLjANCkJFR0lOOlZUSU1FWk9ORQ0KVFpJRDpDZW50cmFsIEV1cm9wZWFuIFN0YW5kYXJkIFRpbWUNCkJFR0lOOlNUQU5EQVJEDQpEVFNUQVJUOjE2MDEwMTAxVDAzMDAwMA0KVFpPRkZTRVRGUk9NOiswMjAwDQpUWk9GRlNFVFRPOiswMTAwDQpSUlVMRTpGUkVRPVlFQVJMWTtJTlRFUlZBTD0xO0JZREFZPS0xU1U7QllNT05USD0xMA0KRU5EOlNUQU5EQVJEDQpCRUdJTjpEQVlMSUdIVA0KRFRTVEFSVDoxNjAxMDEwMVQwMjAwMDANClRaT0ZGU0VURlJPTTorMDEwMA0KVFpPRkZTRVRUTzorMDIwMA0KUlJVTEU6RlJFUT1ZRUFSTFk7SU5URVJWQUw9MTtCWURBWT0tMVNVO0JZTU9OVEg9Mw0KRU5EOkRBWUxJR0hUDQpFTkQ6VlRJTUVaT05FDQpCRUdJTjpWRVZFTlQNCk9SR0FOSVpFUjtDTj1BbGVjIE1hY2huaWFrOm1haWx0bzphbGVjQG91dGxvb2suY29tDQpBVFRFTkRFRTtST0xFPVJFUS1QQVJUSUNJUEFOVDtQQVJUU1RBVD1ORUVEUy1BQ1RJT047UlNWUD1UUlVFO0NOPXRlc3RAYWxlYy4NCiBwbDptYWlsdG86dGVzdEBrb2xhYi5vcmcNCkRFU0NSSVBUSU9OO0xBTkdVQUdFPXBsLVBMOmdoamdoalxuDQpVSUQ6MDQwMDAwMDA4MjAwRTAwMDc0QzVCNzEwMUE4MkUwMDgwMDAwMDAwMEI2MTQwQzc3QjgxQkRBMDEwMDAwMDAwMDAwMDAwMDANCiAwMTAwMDAwMDBGQTBGOTg5QTFCM0MyMDQ5OUUxREU1QjY4REIxRTMzOQ0KU1VNTUFSWTtMQU5HVUFHRT1wbC1QTDp0ZXN0IG1zMw0KRFRTVEFSVDtUWklEPUNlbnRyYWwgRXVyb3BlYW4gU3RhbmRhcmQgVGltZToyMDIzMTEyMlQwODAwMDANCkRURU5EO1RaSUQ9Q2VudHJhbCBFdXJvcGVhbiBTdGFuZGFyZCBUaW1lOjIwMjMxMTIyVDA4MzAwMA0KQ0xBU1M6UFVCTElDDQpQUklPUklUWTo1DQpEVFNUQU1QOjIwMjMxMTIwVDEzNTAwNFoNClRSQU5TUDpPUEFRVUUNClNUQVRVUzpDT05GSVJNRUQNClNFUVVFTkNFOjANCkxPQ0FUSU9OO0xBTkdVQUdFPXBsLVBMOg0KWC1NSUNST1NPRlQtQ0RPLUFQUFQtU0VRVUVOQ0U6MA0KWC1NSUNST1NPRlQtQ0RPLU9XTkVSQVBQVElEOjIxMjIwMzE1NDINClgtTUlDUk9TT0ZULUNETy1CVVNZU1RBVFVTOkJVU1kNClgtTUlDUk9TT0ZULUNETy1JTlRFTkRFRFNUQVRVUzpCVVNZDQpYLU1JQ1JPU09GVC1DRE8tQUxMREFZRVZFTlQ6RkFMU0UNClgtTUlDUk9TT0ZULUNETy1JTVBPUlRBTkNFOjENClgtTUlDUk9TT0ZULUNETy1JTlNUVFlQRTowDQpYLU1JQ1JPU09GVC1ET05PVEZPUldBUkRNRUVUSU5HOkZBTFNFDQpYLU1JQ1JPU09GVC1ESVNBTExPVy1DT1VOVEVSOkZBTFNFDQpYLU1JQ1JPU09GVC1SRVFVRVNURURBVFRFTkRBTkNFTU9ERTpERUZBVUxUDQpYLU1JQ1JPU09GVC1JU1JFU1BPTlNFUkVRVUVTVEVEOlRSVUUNClgtTUlDUk9TT0ZULUxPQ0FUSU9OUzpbXQ0KQkVHSU46VkFMQVJNDQpERVNDUklQVElPTjpSRU1JTkRFUg0KVFJJR0dFUjtSRUxBVEVEPVNUQVJUOi1QVDE1TQ0KQUNUSU9OOkRJU1BMQVkNCkVORDpWQUxBUk0NCkVORDpWRVZFTlQNCkVORDpWQ0FMRU5EQVINCg== + + test ms3 + + + + + + + false + false + 040000008200E00074C5B7101A82E00800000000B6140C77B81BDA01000000000000000010000000FA0F989A1B3C20499E1DE5B68DB1E339 + 2023-11-22T07:00:00Z + 2023-11-22T07:30:00Z + Busy + + Single + + + Alec Machniak + test@outlook.com + SMTP + Mailbox + + + + + + test@kolab.org + test@kolab.org + SMTP + Contact + + Accept + 2023-11-20T14:08:26Z + + + + + + + + + diff --git a/src/tests/data/ews/initial/4.json b/src/tests/data/ews/initial/4.json new file mode 100644 --- /dev/null +++ b/src/tests/data/ews/initial/4.json @@ -0,0 +1,96 @@ +{ + "error": false, + "statusCode": 200, + "headers": { + "Cache-Control": [ + "private" + ], + "Transfer-Encoding": [ + "chunked" + ], + "Content-Type": [ + "text\/xml; charset=utf-8" + ], + "Server": [ + "Microsoft-HTTPAPI\/2.0" + ], + "X-NanoProxy": [ + "1,1" + ], + "X-AspNet-Version": [ + "4.0.30319" + ], + "Request-Id": [ + "65d9caeb-2f07-ca8d-bd20-851f8dc232ed" + ], + "X-CalculatedFETarget": [ + "GV0P278CU002.internal.outlook.com" + ], + "Alt-Svc": [ + "h3=\":443\";ma=2592000,h3-29=\":443\";ma=2592000" + ], + "MS-CV": [ + "68rZZQcvjcq9IIUfjcIy7Q.1.1" + ], + "Restrict-Access-Confirm": [ + "1" + ], + "X-BackEndHttpStatus": [ + "200,200" + ], + "X-BEServer": [ + "GVAP278MB0389" + ], + "X-BeSku": [ + "WCS6" + ], + "X-CalculatedBETarget": [ + "GVAP278MB0389.CHEP278.PROD.OUTLOOK.COM" + ], + "X-DiagInfo": [ + "GVAP278MB0389" + ], + "x-EwsHandler": [ + "FindItem" + ], + "X-FEEFZInfo": [ + "GVA" + ], + "X-FEProxyInfo": [ + "GV0P278CA0020" + ], + "X-FEServer": [ + "WA0P291CA0004" + ], + "x-ms-appId": [ + "6ce1e52b-cd1d-4663-abc3-368fba0bfae7" + ], + "X-Proxy-BackendServerStatus": [ + "200" + ], + "X-Proxy-RoutingCorrectness": [ + "1" + ], + "X-RUM-NotUpdateQueriedPath": [ + "1" + ], + "X-RUM-NotUpdateQueriedDbCopy": [ + "1" + ], + "X-RUM-Validated": [ + "1" + ], + "X-FirstHopCafeEFZ": [ + "WAW" + ], + "Strict-Transport-Security": [ + "max-age=31536000; includeSubDomains" + ], + "Set-Cookie": [ + "exchangecookie=5ad29dedadde423c99430af280c2ae09; expires=Fri, 11-Jul-2025 12:51:49 GMT; path=\/; secure; HttpOnly" + ], + "Date": [ + "Thu, 11 Jul 2024 12:51:49 GMT" + ] + } +} \ No newline at end of file diff --git a/src/tests/data/ews/initial/4.xml b/src/tests/data/ews/initial/4.xml new file mode 100644 --- /dev/null +++ b/src/tests/data/ews/initial/4.xml @@ -0,0 +1,31 @@ + + + + + + + + + + NoError + + + + + IPM.Contact + + + + IPM.DistList + + + + IPM.Contact + + + + + + + + diff --git a/src/tests/data/ews/initial/5.json b/src/tests/data/ews/initial/5.json new file mode 100644 --- /dev/null +++ b/src/tests/data/ews/initial/5.json @@ -0,0 +1,96 @@ +{ + "error": false, + "statusCode": 200, + "headers": { + "Cache-Control": [ + "private" + ], + "Transfer-Encoding": [ + "chunked" + ], + "Content-Type": [ + "text\/xml; charset=utf-8" + ], + "Server": [ + "Microsoft-HTTPAPI\/2.0" + ], + "X-NanoProxy": [ + "1,1" + ], + "X-AspNet-Version": [ + "4.0.30319" + ], + "Request-Id": [ + "d5779317-a712-c0a1-6244-9b07bb130f96" + ], + "X-CalculatedFETarget": [ + "ZR0P278CU002.internal.outlook.com" + ], + "Alt-Svc": [ + "h3=\":443\";ma=2592000,h3-29=\":443\";ma=2592000" + ], + "MS-CV": [ + "F5N31RKnocBiRJsHuxMPlg.1.1" + ], + "Restrict-Access-Confirm": [ + "1" + ], + "X-BackEndHttpStatus": [ + "200,200" + ], + "X-BEServer": [ + "ZRAP278MB0015" + ], + "X-BeSku": [ + "WCS6" + ], + "X-CalculatedBETarget": [ + "ZRAP278MB0015.CHEP278.PROD.OUTLOOK.COM" + ], + "X-DiagInfo": [ + "ZRAP278MB0015" + ], + "x-EwsHandler": [ + "GetItem" + ], + "X-FEEFZInfo": [ + "ZRH" + ], + "X-FEProxyInfo": [ + "ZR0P278CA0035" + ], + "X-FEServer": [ + "WA0P291CA0004" + ], + "x-ms-appId": [ + "6ce1e52b-cd1d-4663-abc3-368fba0bfae7" + ], + "X-Proxy-BackendServerStatus": [ + "200" + ], + "X-Proxy-RoutingCorrectness": [ + "1" + ], + "X-RUM-NotUpdateQueriedPath": [ + "1" + ], + "X-RUM-NotUpdateQueriedDbCopy": [ + "1" + ], + "X-RUM-Validated": [ + "1" + ], + "X-FirstHopCafeEFZ": [ + "WAW" + ], + "Strict-Transport-Security": [ + "max-age=31536000; includeSubDomains" + ], + "Set-Cookie": [ + "exchangecookie=5eac629e2747489c9301bb9476ffc4ac; expires=Fri, 11-Jul-2025 12:51:49 GMT; path=\/; secure; HttpOnly" + ], + "Date": [ + "Thu, 11 Jul 2024 12:51:49 GMT" + ] + } +} \ No newline at end of file diff --git a/src/tests/data/ews/initial/5.xml b/src/tests/data/ews/initial/5.xml new file mode 100644 --- /dev/null +++ b/src/tests/data/ews/initial/5.xml @@ -0,0 +1,47 @@ + + + + + + + + + + NoError + + + QkVHSU46VkNBUkQNClBST0ZJTEU6VkNBUkQNClZFUlNJT046My4wDQpNQUlMRVI6TWljcm9zb2Z0IEV4Y2hhbmdlDQpQUk9ESUQ6TWljcm9zb2Z0IEV4Y2hhbmdlDQpGTjpOb3d5IEtvbnRha3QNCk46O05vd3kgS29udGFrdDs7Ow0KTk9URToNCk9SRzo7DQpDTEFTUzpQVUJMSUMNCkFEUjtUWVBFPVdPUks6Ozs7Ozs7DQpBRFI7VFlQRT1IT01FOjs7Ozs7Ow0KQURSO1RZUEU9UE9TVEFMOjs7Ozs7Ow0KVEVMO1RZUEU9Q0VMTDoxMjM0NTU2Njc5MjAwDQpURUw7VFlQRT1QQUdFUjoNClRFTDtUWVBFPUNBUjoNClRFTDtUWVBFPVZPSUNFOg0KWC1NUy1TUE9VU0U7VFlQRT1OOg0KWC1NUy1NQU5BR0VSO1RZUEU9TjoNClgtTVMtQVNTSVNUQU5UO1RZUEU9TjoNClRJVExFOg0KVVJMO1RZUEU9SE9NRToNClVSTDtUWVBFPVdPUks6DQpSRVY7VkFMVUU9REFURS1USU1FOjIwMjQtMDctMDRUMDg6MzU6NDgsNDkwWg0KRU5EOlZDQVJEDQo= + + false + en-US + 2024-07-04T08:35:48Z + + Nowy Kontakt + Nowy Kontakt + + Nowy Kontakt + Nowy Kontakt + + + test@kolab.org + + + + 1234556679200 + + + + + + + Q1ne1H54kk35i44UboHGPFRRPI8= + 8097ef714bb84706bbe35dcdbad33d16 + EXCH + + + + + + + + diff --git a/src/tests/data/ews/initial/6.json b/src/tests/data/ews/initial/6.json new file mode 100644 --- /dev/null +++ b/src/tests/data/ews/initial/6.json @@ -0,0 +1,96 @@ +{ + "error": false, + "statusCode": 200, + "headers": { + "Cache-Control": [ + "private" + ], + "Transfer-Encoding": [ + "chunked" + ], + "Content-Type": [ + "text\/xml; charset=utf-8" + ], + "Server": [ + "Microsoft-HTTPAPI\/2.0" + ], + "X-NanoProxy": [ + "1,1" + ], + "X-AspNet-Version": [ + "4.0.30319" + ], + "Request-Id": [ + "75aec142-54d8-bfc0-c0e7-adc4e3f2ba14" + ], + "X-CalculatedFETarget": [ + "GV0P278CU005.internal.outlook.com" + ], + "Alt-Svc": [ + "h3=\":443\";ma=2592000,h3-29=\":443\";ma=2592000" + ], + "MS-CV": [ + "QsGuddhUwL\/A563E4\/K6FA.1.1" + ], + "Restrict-Access-Confirm": [ + "1" + ], + "X-BackEndHttpStatus": [ + "200,200" + ], + "X-BEServer": [ + "GV0P278MB0353" + ], + "X-BeSku": [ + "WCS6" + ], + "X-CalculatedBETarget": [ + "GV0P278MB0353.CHEP278.PROD.OUTLOOK.COM" + ], + "X-DiagInfo": [ + "GV0P278MB0353" + ], + "x-EwsHandler": [ + "GetItem" + ], + "X-FEEFZInfo": [ + "GVA" + ], + "X-FEProxyInfo": [ + "GV0P278CA0084" + ], + "X-FEServer": [ + "WA0P291CA0004" + ], + "x-ms-appId": [ + "6ce1e52b-cd1d-4663-abc3-368fba0bfae7" + ], + "X-Proxy-BackendServerStatus": [ + "200" + ], + "X-Proxy-RoutingCorrectness": [ + "1" + ], + "X-RUM-NotUpdateQueriedPath": [ + "1" + ], + "X-RUM-NotUpdateQueriedDbCopy": [ + "1" + ], + "X-RUM-Validated": [ + "1" + ], + "X-FirstHopCafeEFZ": [ + "WAW" + ], + "Strict-Transport-Security": [ + "max-age=31536000; includeSubDomains" + ], + "Set-Cookie": [ + "exchangecookie=08d3bd1184da4e9f8016984e26367d56; expires=Fri, 11-Jul-2025 12:51:50 GMT; path=\/; secure; HttpOnly" + ], + "Date": [ + "Thu, 11 Jul 2024 12:51:50 GMT" + ] + } +} \ No newline at end of file diff --git a/src/tests/data/ews/initial/6.xml b/src/tests/data/ews/initial/6.xml new file mode 100644 --- /dev/null +++ b/src/tests/data/ews/initial/6.xml @@ -0,0 +1,49 @@ + + + + + + + + + + NoError + + + QkVHSU46VkNBUkQNClBST0ZJTEU6VkNBUkQNClZFUlNJT046My4wDQpNQUlMRVI6TWljcm9zb2Z0IEV4Y2hhbmdlDQpQUk9ESUQ6TWljcm9zb2Z0IEV4Y2hhbmdlDQpGTjpUZXN0IFN1cm5hbWUNCk46U3VybmFtZTtUZXN0Ozs7DQpOT1RFOg0KT1JHOjsNCkNMQVNTOlBVQkxJQw0KQURSO1RZUEU9V09SSzo7Ozs7OzsNCkFEUjtUWVBFPUhPTUU6Ozs7Ozs7DQpBRFI7VFlQRT1QT1NUQUw6Ozs7Ozs7DQpURUw7VFlQRT1DRUxMOg0KVEVMO1RZUEU9UEFHRVI6DQpURUw7VFlQRT1DQVI6DQpURUw7VFlQRT1WT0lDRToNClgtTVMtU1BPVVNFO1RZUEU9TjoNClgtTVMtTUFOQUdFUjtUWVBFPU46DQpYLU1TLUFTU0lTVEFOVDtUWVBFPU46DQpUSVRMRToNClVSTDtUWVBFPUhPTUU6DQpVUkw7VFlQRT1XT1JLOg0KUkVWO1ZBTFVFPURBVEUtVElNRToyMDI0LTA2LTI1VDA5OjU0OjU0LDIxNFoNCkVORDpWQ0FSRA0K + + false + en-US + 2024-06-25T09:54:54Z + + Test Surname + Test + + Test + Surname + Test Surname + + + christian@outlook.com + + + + + + + + + + + Surname + Q1ne1H54kk35i44UboHGPFRRPI8= + 2790877950c24ec1a3a9b41ce75aec8a + EXCH + + + + + + + + diff --git a/src/tests/data/ews/initial/7.json b/src/tests/data/ews/initial/7.json new file mode 100644 --- /dev/null +++ b/src/tests/data/ews/initial/7.json @@ -0,0 +1,96 @@ +{ + "error": false, + "statusCode": 200, + "headers": { + "Cache-Control": [ + "private" + ], + "Transfer-Encoding": [ + "chunked" + ], + "Content-Type": [ + "text\/xml; charset=utf-8" + ], + "Server": [ + "Microsoft-HTTPAPI\/2.0" + ], + "X-NanoProxy": [ + "1,1" + ], + "X-AspNet-Version": [ + "4.0.30319" + ], + "Request-Id": [ + "447884f2-e7b4-e0b7-35eb-415042ed57b1" + ], + "X-CalculatedFETarget": [ + "ZR0P278CU001.internal.outlook.com" + ], + "Alt-Svc": [ + "h3=\":443\";ma=2592000,h3-29=\":443\";ma=2592000" + ], + "MS-CV": [ + "8oR4RLTnt+A160FQQu1XsQ.1.1" + ], + "Restrict-Access-Confirm": [ + "1" + ], + "X-BackEndHttpStatus": [ + "200,200" + ], + "X-BEServer": [ + "ZR1P278MB1172" + ], + "X-BeSku": [ + "WCS7" + ], + "X-CalculatedBETarget": [ + "ZR1P278MB1172.CHEP278.PROD.OUTLOOK.COM" + ], + "X-DiagInfo": [ + "ZR1P278MB1172" + ], + "x-EwsHandler": [ + "GetItem" + ], + "X-FEEFZInfo": [ + "ZRH" + ], + "X-FEProxyInfo": [ + "ZR0P278CA0015" + ], + "X-FEServer": [ + "WA0P291CA0004" + ], + "x-ms-appId": [ + "6ce1e52b-cd1d-4663-abc3-368fba0bfae7" + ], + "X-Proxy-BackendServerStatus": [ + "200" + ], + "X-Proxy-RoutingCorrectness": [ + "1" + ], + "X-RUM-NotUpdateQueriedPath": [ + "1" + ], + "X-RUM-NotUpdateQueriedDbCopy": [ + "1" + ], + "X-RUM-Validated": [ + "1" + ], + "X-FirstHopCafeEFZ": [ + "WAW" + ], + "Strict-Transport-Security": [ + "max-age=31536000; includeSubDomains" + ], + "Set-Cookie": [ + "exchangecookie=38c00eae8e8243da82af82c2859ab5ec; expires=Fri, 11-Jul-2025 12:51:51 GMT; path=\/; secure; HttpOnly" + ], + "Date": [ + "Thu, 11 Jul 2024 12:51:51 GMT" + ] + } +} \ No newline at end of file diff --git a/src/tests/data/ews/initial/7.xml b/src/tests/data/ews/initial/7.xml new file mode 100644 --- /dev/null +++ b/src/tests/data/ews/initial/7.xml @@ -0,0 +1,44 @@ + + + + + + + + + + NoError + + + + nowa lista + 2024-06-27T13:44:32Z + nowa lista + nowa lista + + + + alec@kolab.org + alec@kolab.org + SMTP + OneOff + + Normal + + + + Christian Mollekopf + christian@outlook.com + SMTP + Mailbox + + Normal + + + + + + + + + diff --git a/src/tests/data/ews/initial/8.json b/src/tests/data/ews/initial/8.json new file mode 100644 --- /dev/null +++ b/src/tests/data/ews/initial/8.json @@ -0,0 +1,96 @@ +{ + "error": false, + "statusCode": 200, + "headers": { + "Cache-Control": [ + "private" + ], + "Transfer-Encoding": [ + "chunked" + ], + "Content-Type": [ + "text\/xml; charset=utf-8" + ], + "Server": [ + "Microsoft-HTTPAPI\/2.0" + ], + "X-NanoProxy": [ + "1,1" + ], + "X-AspNet-Version": [ + "4.0.30319" + ], + "Request-Id": [ + "3b9674f7-6105-035a-c28a-8235a47686e8" + ], + "X-CalculatedFETarget": [ + "ZR0P278CU002.internal.outlook.com" + ], + "Alt-Svc": [ + "h3=\":443\";ma=2592000,h3-29=\":443\";ma=2592000" + ], + "MS-CV": [ + "93SWOwVhWgPCioI1pHaG6A.1.1" + ], + "Restrict-Access-Confirm": [ + "1" + ], + "X-BackEndHttpStatus": [ + "200,200" + ], + "X-BEServer": [ + "ZR1P278MB1139" + ], + "X-BeSku": [ + "WCS7" + ], + "X-CalculatedBETarget": [ + "ZR1P278MB1139.CHEP278.PROD.OUTLOOK.COM" + ], + "X-DiagInfo": [ + "ZR1P278MB1139" + ], + "x-EwsHandler": [ + "FindItem" + ], + "X-FEEFZInfo": [ + "ZRH" + ], + "X-FEProxyInfo": [ + "ZR0P278CA0035" + ], + "X-FEServer": [ + "WA0P291CA0004" + ], + "x-ms-appId": [ + "6ce1e52b-cd1d-4663-abc3-368fba0bfae7" + ], + "X-Proxy-BackendServerStatus": [ + "200" + ], + "X-Proxy-RoutingCorrectness": [ + "1" + ], + "X-RUM-NotUpdateQueriedPath": [ + "1" + ], + "X-RUM-NotUpdateQueriedDbCopy": [ + "1" + ], + "X-RUM-Validated": [ + "1" + ], + "X-FirstHopCafeEFZ": [ + "WAW" + ], + "Strict-Transport-Security": [ + "max-age=31536000; includeSubDomains" + ], + "Set-Cookie": [ + "exchangecookie=6cf935f5c1e24a81a25af0ee9b7efc8f; expires=Fri, 11-Jul-2025 12:51:54 GMT; path=\/; secure; HttpOnly" + ], + "Date": [ + "Thu, 11 Jul 2024 12:51:54 GMT" + ] + } +} \ No newline at end of file diff --git a/src/tests/data/ews/initial/8.xml b/src/tests/data/ews/initial/8.xml new file mode 100644 --- /dev/null +++ b/src/tests/data/ews/initial/8.xml @@ -0,0 +1,23 @@ + + + + + + + + + + NoError + + + + + IPM.Task + + + + + + + + diff --git a/src/tests/data/ews/initial/9.json b/src/tests/data/ews/initial/9.json new file mode 100644 --- /dev/null +++ b/src/tests/data/ews/initial/9.json @@ -0,0 +1,96 @@ +{ + "error": false, + "statusCode": 200, + "headers": { + "Cache-Control": [ + "private" + ], + "Transfer-Encoding": [ + "chunked" + ], + "Content-Type": [ + "text\/xml; charset=utf-8" + ], + "Server": [ + "Microsoft-HTTPAPI\/2.0" + ], + "X-NanoProxy": [ + "1,1" + ], + "X-AspNet-Version": [ + "4.0.30319" + ], + "Request-Id": [ + "9b80e10a-33b0-752a-c294-85f398895b7c" + ], + "X-CalculatedFETarget": [ + "ZR0P278CU001.internal.outlook.com" + ], + "Alt-Svc": [ + "h3=\":443\";ma=2592000,h3-29=\":443\";ma=2592000" + ], + "MS-CV": [ + "CuGAm7AzKnXClIXzmIlbfA.1.1" + ], + "Restrict-Access-Confirm": [ + "1" + ], + "X-BackEndHttpStatus": [ + "200,200" + ], + "X-BEServer": [ + "ZR0P278MB1652" + ], + "X-BeSku": [ + "WCS7" + ], + "X-CalculatedBETarget": [ + "ZR0P278MB1652.CHEP278.PROD.OUTLOOK.COM" + ], + "X-DiagInfo": [ + "ZR0P278MB1652" + ], + "x-EwsHandler": [ + "GetItem" + ], + "X-FEEFZInfo": [ + "ZRH" + ], + "X-FEProxyInfo": [ + "ZR0P278CA0015" + ], + "X-FEServer": [ + "WA0P291CA0004" + ], + "x-ms-appId": [ + "6ce1e52b-cd1d-4663-abc3-368fba0bfae7" + ], + "X-Proxy-BackendServerStatus": [ + "200" + ], + "X-Proxy-RoutingCorrectness": [ + "1" + ], + "X-RUM-NotUpdateQueriedPath": [ + "1" + ], + "X-RUM-NotUpdateQueriedDbCopy": [ + "1" + ], + "X-RUM-Validated": [ + "1" + ], + "X-FirstHopCafeEFZ": [ + "WAW" + ], + "Strict-Transport-Security": [ + "max-age=31536000; includeSubDomains" + ], + "Set-Cookie": [ + "exchangecookie=5ead4020ab764b83b6611fccc770bb4e; expires=Fri, 11-Jul-2025 12:51:54 GMT; path=\/; secure; HttpOnly" + ], + "Date": [ + "Thu, 11 Jul 2024 12:51:54 GMT" + ] + } +} \ No newline at end of file diff --git a/src/tests/data/ews/initial/9.xml b/src/tests/data/ews/initial/9.xml new file mode 100644 --- /dev/null +++ b/src/tests/data/ews/initial/9.xml @@ -0,0 +1,80 @@ + + + + + + + + + + NoError + + + + + IPM.Task + Nowe zadanie + Normal + + 2024-06-27T08:58:05Z + 2025 + High + false + false + false + false + false + 2024-06-27T08:58:05Z + 2024-06-27T08:58:05Z + 2024-06-28T07:00:00Z + true + 2024-06-28T07:00:00Z + 0 + + + false + en-US + + false + false + false + true + true + true + true + + Alec Machniak + 2024-06-27T08:58:11Z + false + https://outlook.office365.com/owa/?ItemID=AAMkAGEzOGRlODRiLTBkN2ItNDgwZS04ZDJmLTM5NDEyY2Q0NGQ0OABGAAAAAAC9tlDYSlG2TaxWBrA1OzWtBwAs2ajhknXlRYN%2FpbC8JqblAAAAAAESAAAs2ajhknXlRYN%2FpbC8JqblAAJo4gtPAAA%3D&exvsurl=1&viewmodel=TaskReadingPaneViewModelPopOutFactory + + + NotFlagged + + AQEAAAAAAAESAQAAAmjiC08AAAAA + + 1 + 2024-06-26T22:00:00Z + false + true + Alec Machniak + 0 + + + 1 + Thursday + Sunday + + + 2024-06-27Z + + + NotStarted + Not Started + + + + + + + diff --git a/src/tests/data/mail/1.eml b/src/tests/data/mail/1.eml new file mode 100644 --- /dev/null +++ b/src/tests/data/mail/1.eml @@ -0,0 +1,10 @@ +Date: Thu, 09 Aug 2012 13:18:31 +0000 +Subject: test sync +Message-ID: +From: "Sync 1" +To: "To 1" , "To 2" +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: base64 + +ZWVlYQ== diff --git a/src/tests/data/mail/2.eml b/src/tests/data/mail/2.eml new file mode 100644 --- /dev/null +++ b/src/tests/data/mail/2.eml @@ -0,0 +1,20 @@ +Date: Thu, 10 Aug 2012 13:18:31 +0000 +Subject: sync test with attachment +Message-ID: +From: jack@kolab.org +To: john@kolab.org +MIME-Version: 1.0 +Content-Type: multipart/mixed; boundary="BOUNDARY" + +--BOUNDARY +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: base64 + +ZWVl +--BOUNDARY +Content-Transfer-Encoding: base64 +Content-Type: image/jpeg; name=logo.gif +Content-Disposition: inline; filename=logo.gif; size=2574 + +/9j/4AAQSkZJRgABAgEASABIAAD/4QqARXhpZgAATU0AKgAAAAgABwESAAMAAAABAAEAAAEaAAUA +--BOUNDARY-- diff --git a/src/tests/data/mail/3.eml b/src/tests/data/mail/3.eml new file mode 100644 --- /dev/null +++ b/src/tests/data/mail/3.eml @@ -0,0 +1,10 @@ +Date: Thu, 09 Aug 2012 13:18:31 +0000 +Subject: test migrator +Message-ID: +From: "Sync 3" +To: "To 1" , "To 2" +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: base64 + +ZWVlYQ== diff --git a/src/tests/data/mail/4.eml b/src/tests/data/mail/4.eml new file mode 100644 --- /dev/null +++ b/src/tests/data/mail/4.eml @@ -0,0 +1,10 @@ +Date: Thu, 09 Aug 2012 13:18:31 +0000 +Subject: test sync 4th +Message-ID: +From: test@kolab.org +To: "To 1" , "To 2" +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: base64 + +ZWVlYQ==