Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F117750513
D5838.1775183185.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
25 KB
Referenced Files
None
Subscribers
None
D5838.1775183185.diff
View Options
diff --git a/composer.json-dist b/composer.json-dist
--- a/composer.json-dist
+++ b/composer.json-dist
@@ -15,6 +15,7 @@
"pear/net_sieve": "~1.4.0",
"roundcube/rtf-html-php": "~2.1",
"sabre/vobject": "~4.5.1",
+ "symfony/polyfill-php85": "^1.33.0",
"zf1s/zend-controller": "~1.12.20",
"zf1s/zend-json": "~1.12.20",
"zf1s/zend-log": "~1.12.20"
diff --git a/lib/kolab_sync_data_notes.php b/lib/kolab_sync_data_notes.php
--- a/lib/kolab_sync_data_notes.php
+++ b/lib/kolab_sync_data_notes.php
@@ -96,7 +96,7 @@
break;
}
- if (empty($value) || is_array($value)) {
+ if (empty($value) || (is_array($value) && $key != 'categories')) {
continue;
}
@@ -137,6 +137,14 @@
if ($value === null) {
continue 2;
}
+
+ // Make sure to use HTML format for Kolab v4
+ if (kolab_sync::get_instance()->config->get('activesync_storage') == 'kolab4') {
+ if (!preg_match('/<(html|body)(\s+[a-z]|>)/i', $value, $m)) {
+ $value = "<!DOCTYPE html><html><body><pre>{$value}</pre></body></html>";
+ }
+ }
+
break;
}
diff --git a/lib/kolab_sync_plugin_api.php b/lib/kolab_sync_plugin_api.php
--- a/lib/kolab_sync_plugin_api.php
+++ b/lib/kolab_sync_plugin_api.php
@@ -86,7 +86,7 @@
*
* @param string $fn Path to script
*/
- public function include_script($fn)
+ public function include_script($fn, $unused = [])
{
//empty
}
diff --git a/lib/kolab_sync_storage_kolab4.php b/lib/kolab_sync_storage_kolab4.php
--- a/lib/kolab_sync_storage_kolab4.php
+++ b/lib/kolab_sync_storage_kolab4.php
@@ -124,7 +124,7 @@
if ($flat_mode) {
$list = $this->folders_list_flat_mail($list);
}
- } elseif (in_array($type, [self::MODEL_CONTACTS, self::MODEL_CALENDAR, self::MODEL_TASKS])) {
+ } elseif (in_array($type, [self::MODEL_CONTACTS, self::MODEL_CALENDAR, self::MODEL_TASKS, self::MODEL_NOTES])) {
if (!empty($this->folders)) {
foreach ($this->folders as $unique_key => $folder) {
if (strpos($unique_key, "DAV:$type:") === 0) {
@@ -142,7 +142,7 @@
$list[$folder_data['serverId']] = $folder_data;
// Store all folder objects in internal cache, otherwise
- // Any access to the folder (or list) will invoke excessive DAV requests
+ // any access to the folder (or list) will invoke excessive DAV requests
$unique_key = $folder_data['serverId'] . ":$deviceid:$type";
$this->folders[$unique_key] = $folder;
}
@@ -247,7 +247,7 @@
}
return false;
- } elseif ($type == 8 || $type == 13 || $type == 7 || $type == 15 || $type == 9 || $type == 14) {
+ } elseif (in_array($type, [8, 13, 7, 15, 9, 14, 10, 17])) {
// DAV folder
$type = preg_replace('|\..*|', '', self::type_activesync2kolab($type));
@@ -585,6 +585,7 @@
'contact' => [],
'event' => [],
'task' => [],
+ 'note' => [],
];
foreach ($all_folders as $folder) {
diff --git a/tests/Sync/FoldersTest.php b/tests/Sync/FoldersTest.php
--- a/tests/Sync/FoldersTest.php
+++ b/tests/Sync/FoldersTest.php
@@ -16,11 +16,11 @@
$this->deleteTestFolder('Test Contacts Folder', 'contact');
$this->deleteTestFolder('Test Contacts New', 'contact');
// Make sure the default folders exist
+ $this->createTestFolder('Notes', 'note.default');
if (!$this->isStorageDriver('kolab4')) {
$this->createTestFolder('Calendar', 'event.default');
$this->createTestFolder('Contacts', 'contact.default');
$this->createTestFolder('Tasks', 'task.default');
- $this->createTestFolder('Notes', 'note.default');
}
//TODO: handle kolab4 case?
}
@@ -305,10 +305,10 @@
['Drafts', Syncroton_Command_FolderSync::FOLDERTYPE_DRAFTS],
['Sent', Syncroton_Command_FolderSync::FOLDERTYPE_SENTMAIL],
['Trash', Syncroton_Command_FolderSync::FOLDERTYPE_DELETEDITEMS],
- ['Spam', Syncroton_Command_FolderSync::FOLDERTYPE_MAIL_USER_CREATED],
+ // ['Spam', Syncroton_Command_FolderSync::FOLDERTYPE_MAIL_USER_CREATED],
+ ['Notes', Syncroton_Command_FolderSync::FOLDERTYPE_NOTE],
['Tasks', Syncroton_Command_FolderSync::FOLDERTYPE_TASK],
];
-
} else {
$folders = [
['Calendar', Syncroton_Command_FolderSync::FOLDERTYPE_CALENDAR],
@@ -351,6 +351,7 @@
['Drafts', Syncroton_Command_FolderSync::FOLDERTYPE_DRAFTS],
['Sent', Syncroton_Command_FolderSync::FOLDERTYPE_SENTMAIL],
['Trash', Syncroton_Command_FolderSync::FOLDERTYPE_DELETEDITEMS],
+ ['Notes', Syncroton_Command_FolderSync::FOLDERTYPE_NOTE],
// Note: For now Kolab 4 uses the same Calendar folder for calendar and tasks
['/^(Tasks|Calendar)$/', Syncroton_Command_FolderSync::FOLDERTYPE_TASK],
];
@@ -390,7 +391,7 @@
$xpath = $this->xpath($dom);
// This depends on multifolder blacklists to be configured (otherwise we get no "collective" folders)
- $deleted = $this->isStorageDriver('kolab4') ? 4 : 5; // No Notes folder in Kolab4
+ $deleted = 4;
$syncKey = 2;
$this->assertSame('1', $xpath->query("//ns:FolderSync/ns:Status")->item(0)->nodeValue);
@@ -787,6 +788,7 @@
['Sent', Syncroton_Command_FolderSync::FOLDERTYPE_SENTMAIL],
['Spam', Syncroton_Command_FolderSync::FOLDERTYPE_MAIL_USER_CREATED],
['Trash', Syncroton_Command_FolderSync::FOLDERTYPE_DELETEDITEMS],
+ ['Notes', Syncroton_Command_FolderSync::FOLDERTYPE_NOTE],
['Tasks', Syncroton_Command_FolderSync::FOLDERTYPE_TASK],
];
diff --git a/tests/Sync/Sync/NotesTest.php b/tests/Sync/Sync/NotesTest.php
new file mode 100644
--- /dev/null
+++ b/tests/Sync/Sync/NotesTest.php
@@ -0,0 +1,347 @@
+<?php
+
+namespace Tests\Sync\Sync;
+
+class NotesTest extends \Tests\SyncTestCase
+{
+ /**
+ * Test Sync command
+ */
+ public function testSync()
+ {
+ // Test with multi-folder support enabled
+ self::$deviceType = 'iphone';
+
+ $davFolder = 'Notes';
+ $this->createTestFolder($davFolder, 'note', false);
+ $this->emptyTestFolder($davFolder, 'note');
+ $this->deleteTestFolder('Test Notes Folder', 'note'); // from other test files
+ $this->registerDevice();
+
+ // Test empty contacts folder
+ $folderId = array_search('Notes', $this->folders);
+ $syncKey = 0;
+ $request = <<<EOF
+ <?xml version="1.0" encoding="utf-8"?>
+ <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/">
+ <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase">
+ <Collections>
+ <Collection>
+ <Class>Notes</Class>
+ <SyncKey>{$syncKey}</SyncKey>
+ <CollectionId>{$folderId}</CollectionId>
+ <DeletesAsMoves/>
+ <GetChanges/>
+ <Options>
+ <AirSyncBase:BodyPreference>
+ <AirSyncBase:Type>1</AirSyncBase:Type>
+ <AirSyncBase:TruncationSize>5120</AirSyncBase:TruncationSize>
+ </AirSyncBase:BodyPreference>
+ <Conflict>1</Conflict>
+ </Options>
+ </Collection>
+ </Collections>
+ </Sync>
+ EOF;
+
+ $response = $this->request($request, 'Sync');
+
+ $this->assertEquals(200, $response->getStatusCode());
+
+ $dom = $this->fromWbxml($response->getBody());
+ $xpath = $this->xpath($dom);
+
+ $root = "//ns:Sync/ns:Collections/ns:Collection";
+ $this->assertSame('1', $xpath->query("{$root}/ns:Status")->item(0)->nodeValue);
+ $this->assertSame(strval(++$syncKey), $xpath->query("{$root}/ns:SyncKey")->item(0)->nodeValue);
+ $this->assertSame($folderId, $xpath->query("{$root}/ns:CollectionId")->item(0)->nodeValue);
+ $this->assertSame(0, $xpath->query("{$root}/ns:Commands/ns:Add")->count());
+
+ if ($this->isStorageDriver('kolab')) {
+ $this->markTestSkipped("Appending test objects does not work with 'kolab' storage yet.");
+ }
+
+ // Append two notes objects and sync them
+ $this->appendObject($davFolder, 'note1.html', 'note');
+ $this->appendObject($davFolder, 'note2.html', 'note');
+
+ $request = str_replace("<SyncKey>0</SyncKey>", "<SyncKey>{$syncKey}</SyncKey>", $request);
+
+ $response = $this->request($request, 'Sync');
+
+ $this->assertEquals(200, $response->getStatusCode());
+
+ $dom = $this->fromWbxml($response->getBody());
+ $xpath = $this->xpath($dom);
+
+ $root = "//ns:Sync/ns:Collections/ns:Collection";
+ $this->assertSame('1', $xpath->query("{$root}/ns:Status")->item(0)->nodeValue);
+ $this->assertSame(strval(++$syncKey), $xpath->query("{$root}/ns:SyncKey")->item(0)->nodeValue);
+ $this->assertSame($folderId, $xpath->query("{$root}/ns:CollectionId")->item(0)->nodeValue);
+ $this->assertSame(2, $xpath->query("{$root}/ns:Commands/ns:Add")->count());
+
+ $root .= "/ns:Commands/ns:Add";
+ $this->assertStringMatchesFormat("CRC%s", $xpath->query("{$root}/ns:ServerId")->item(0)->nodeValue);
+ $r = "{$root}[1]/ns:ApplicationData";
+ $this->assertSame('test note', $xpath->query("{$r}/Notes:Subject")->item(0)->nodeValue);
+ $this->assertSame('IPM.StickyNote', $xpath->query("{$r}/Notes:MessageClass")->item(0)->nodeValue);
+ $this->assertSame('1', $xpath->query("{$r}/AirSyncBase:Body/AirSyncBase:Type")->item(0)->nodeValue);
+ $this->assertStringContainsString('test note 1', $xpath->query("{$r}/AirSyncBase:Body/AirSyncBase:Data")->item(0)->nodeValue);
+ $this->assertCount(2, $xpath->query("{$r}/Notes:Categories/Notes:Category"));
+ $this->assertSame('test1', $xpath->query("{$r}/Notes:Categories/Notes:Category")->item(0)->nodeValue);
+ $this->assertSame('test2', $xpath->query("{$r}/Notes:Categories/Notes:Category")->item(1)->nodeValue);
+ $r = "{$root}[2]/ns:ApplicationData";
+ $this->assertSame('test note 2', $xpath->query("{$r}/Notes:Subject")->item(0)->nodeValue);
+ $this->assertSame('IPM.StickyNote', $xpath->query("{$r}/Notes:MessageClass")->item(0)->nodeValue);
+ $this->assertSame('1', $xpath->query("{$r}/AirSyncBase:Body/AirSyncBase:Type")->item(0)->nodeValue);
+ $this->assertStringContainsString('test note 2', $xpath->query("{$r}/AirSyncBase:Body/AirSyncBase:Data")->item(0)->nodeValue);
+ $this->assertCount(0, $xpath->query("{$r}/Notes:Categories/Notes:Category"));
+
+ return [$syncKey, $folderId];
+ }
+
+ /**
+ * Test adding objects from client
+ *
+ * @depends testSync
+ */
+ public function testAddFromClient($params)
+ {
+ // Test with multi-folder support enabled
+ self::$deviceType = 'iphone';
+
+ [$syncKey, $folderId] = $params;
+
+ $request = <<<EOF
+ <?xml version="1.0" encoding="utf-8"?>
+ <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/">
+ <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase" xmlns:Notes="uri:Notes">
+ <Collections>
+ <Collection>
+ <Class>Notes</Class>
+ <SyncKey>{$syncKey}</SyncKey>
+ <CollectionId>{$folderId}</CollectionId>
+ <DeletesAsMoves/>
+ <GetChanges/>
+ <Options>
+ <AirSyncBase:BodyPreference>
+ <AirSyncBase:Type>1</AirSyncBase:Type>
+ <AirSyncBase:TruncationSize>5120</AirSyncBase:TruncationSize>
+ </AirSyncBase:BodyPreference>
+ <Conflict>1</Conflict>
+ </Options>
+ <Commands>
+ <Add>
+ <ClientId>42</ClientId>
+ <ApplicationData>
+ <Notes:Subject>test note 3</Notes:Subject>
+ <Notes:MessageClass>IPM.StickyNote</Notes:MessageClass>
+ <AirSyncBase:Body>
+ <AirSyncBase:Type>1</AirSyncBase:Type>
+ <AirSyncBase:Data>test note 3</AirSyncBase:Data>
+ </AirSyncBase:Body>
+ <Notes:Categories>
+ <Notes:Category>test1</Notes:Category>
+ <Notes:Category>test2</Notes:Category>
+ </Notes:Categories>
+ </ApplicationData>
+ </Add>
+ </Commands>
+ </Collection>
+ </Collections>
+ </Sync>
+ EOF;
+
+ $response = $this->request($request, 'Sync');
+
+ $this->assertEquals(200, $response->getStatusCode());
+
+ $dom = $this->fromWbxml($response->getBody());
+ $xpath = $this->xpath($dom);
+
+ $root = $xpath->query("//ns:Sync/ns:Collections/ns:Collection")->item(0);
+ $this->assertSame('1', $xpath->query("ns:Status", $root)->item(0)->nodeValue);
+ $this->assertSame(strval(++$syncKey), $xpath->query("ns:SyncKey", $root)->item(0)->nodeValue);
+ $root = $xpath->query("ns:Responses/ns:Add", $root)->item(0);
+ $this->assertSame('1', $xpath->query("ns:Status", $root)->item(0)->nodeValue);
+ $this->assertSame('42', $xpath->query("ns:ClientId", $root)->item(0)->nodeValue);
+ $serverId = $xpath->query("ns:ServerId", $root)->item(0)->nodeValue;
+ $this->assertStringMatchesFormat("CRC%s", $serverId);
+
+ // Assert the content on the server
+ $notes = $this->getDavObjects('Notes', 'note');
+ usort($notes, function ($c1, $c2) { return $c1['title'] <=> $c2['title']; });
+ $this->assertCount(3, $notes);
+ $this->assertSame('test note 3', $notes[2]['title']);
+ $this->assertStringContainsString('<pre>test note 3</pre>', $notes[2]['description']);
+ $this->assertSame(['test1', 'test2'], $notes[2]['categories']);
+
+ return [$syncKey, $folderId, $serverId];
+ }
+
+ /**
+ * Test updating objects from client
+ *
+ * @depends testAddFromClient
+ */
+ public function testChangeFromClient($params)
+ {
+ // Test with multi-folder support enabled
+ self::$deviceType = 'iphone';
+
+ [$syncKey, $folderId, $serverId] = $params;
+
+ $request = <<<EOF
+ <?xml version="1.0" encoding="utf-8"?>
+ <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/">
+ <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase" xmlns:Notes="uri:Notes">
+ <Collections>
+ <Collection>
+ <Class>Notes</Class>
+ <SyncKey>{$syncKey}</SyncKey>
+ <CollectionId>{$folderId}</CollectionId>
+ <DeletesAsMoves/>
+ <GetChanges/>
+ <Options>
+ <AirSyncBase:BodyPreference>
+ <AirSyncBase:Type>1</AirSyncBase:Type>
+ <AirSyncBase:TruncationSize>5120</AirSyncBase:TruncationSize>
+ </AirSyncBase:BodyPreference>
+ <Conflict>1</Conflict>
+ </Options>
+ <Commands>
+ <Change>
+ <ServerId>{$serverId}</ServerId>
+ <ApplicationData>
+ <Notes:Subject>test note 3 mod</Notes:Subject>
+ <Notes:Categories>
+ <Notes:Category>test1</Notes:Category>
+ <Notes:Category>test3</Notes:Category>
+ </Notes:Categories>
+ </ApplicationData>
+ </Change>
+ </Commands>
+ </Collection>
+ </Collections>
+ </Sync>
+ EOF;
+
+ $response = $this->request($request, 'Sync');
+
+ $this->assertEquals(200, $response->getStatusCode());
+
+ $dom = $this->fromWbxml($response->getBody());
+ $xpath = $this->xpath($dom);
+
+ $root = $xpath->query("//ns:Sync/ns:Collections/ns:Collection")->item(0);
+ $this->assertSame('1', $xpath->query("ns:Status", $root)->item(0)->nodeValue);
+ $this->assertSame(strval(++$syncKey), $xpath->query("ns:SyncKey", $root)->item(0)->nodeValue);
+ $this->assertSame(0, $xpath->query("ns:Responses", $root)->length);
+
+ // Assert updated content on the server
+ $notes = $this->getDavObjects('Notes', 'note');
+ usort($notes, function ($c1, $c2) { return $c1['title'] <=> $c2['title']; });
+ $this->assertCount(3, $notes);
+ $this->assertSame('test note 3 mod', $notes[2]['title']);
+ $this->assertStringContainsString('<pre>test note 3</pre>', $notes[2]['description']);
+ $this->assertSame(['test1', 'test3'], $notes[2]['categories']);
+
+ return [$syncKey, $folderId, $serverId];
+ }
+
+ /**
+ * Test deleting objects from client
+ *
+ * @depends testChangeFromClient
+ */
+ public function testDeleteFromClient($params)
+ {
+ // Test with multi-folder support enabled
+ self::$deviceType = 'iphone';
+
+ [$syncKey, $folderId, $serverId] = $params;
+
+ $request = <<<EOF
+ <?xml version="1.0" encoding="utf-8"?>
+ <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/">
+ <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase" xmlns:Notes="uri:Notes">
+ <Collections>
+ <Collection>
+ <Class>Notes</Class>
+ <SyncKey>{$syncKey}</SyncKey>
+ <CollectionId>{$folderId}</CollectionId>
+ <DeletesAsMoves/>
+ <GetChanges/>
+ <Options>
+ <AirSyncBase:BodyPreference>
+ <AirSyncBase:Type>1</AirSyncBase:Type>
+ <AirSyncBase:TruncationSize>5120</AirSyncBase:TruncationSize>
+ </AirSyncBase:BodyPreference>
+ <Conflict>1</Conflict>
+ </Options>
+ <Commands>
+ <Delete>
+ <ServerId>{$serverId}</ServerId>
+ </Delete>
+ </Commands>
+ </Collection>
+ </Collections>
+ </Sync>
+ EOF;
+
+ $response = $this->request($request, 'Sync');
+
+ $this->assertEquals(200, $response->getStatusCode());
+
+ $dom = $this->fromWbxml($response->getBody());
+ $xpath = $this->xpath($dom);
+
+ $root = $xpath->query("//ns:Sync/ns:Collections/ns:Collection")->item(0);
+ $this->assertSame('1', $xpath->query("ns:Status", $root)->item(0)->nodeValue);
+ $this->assertSame(strval(++$syncKey), $xpath->query("ns:SyncKey", $root)->item(0)->nodeValue);
+ $this->assertSame(0, $xpath->query("ns:Responses", $root)->length);
+
+ // Assert deleted note on the server
+ $notes = $this->getDavObjects('Notes', 'note');
+ usort($notes, function ($c1, $c2) { return $c1['title'] <=> $c2['title']; });
+ $this->assertSame(['test note', 'test note 2'], array_column($notes, 'title'));
+ }
+
+ /**
+ * Test creating a notes folder
+ *
+ * @depends testSync
+ */
+ public function testCreateFolder()
+ {
+ // Create a notes folder
+ $folderName = 'Test Notes Folder';
+ $folderType = \Syncroton_Command_FolderSync::FOLDERTYPE_NOTE_USER_CREATED;
+ $request = <<<EOF
+ <?xml version="1.0" encoding="utf-8"?>
+ <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/">
+ <FolderCreate xmlns="uri:FolderHierarchy">
+ <SyncKey>1</SyncKey>
+ <ParentId>0</ParentId>
+ <DisplayName>{$folderName}</DisplayName>
+ <Type>{$folderType}</Type>
+ </FolderCreate>
+ EOF;
+
+ $response = $this->request($request, 'FolderCreate');
+
+ $this->assertEquals(200, $response->getStatusCode());
+
+ $dom = $this->fromWbxml($response->getBody());
+ $xpath = $this->xpath($dom);
+
+ $this->assertSame('1', $xpath->query("//ns:FolderCreate/ns:Status")->item(0)->nodeValue);
+ $this->assertSame('2', $xpath->query("//ns:FolderCreate/ns:SyncKey")->item(0)->nodeValue);
+ $this->assertSame(1, $xpath->query("//ns:FolderCreate/ns:ServerId")->count());
+ $folderId = $xpath->query("//ns:FolderCreate/ns:ServerId")->item(0)->nodeValue;
+
+ $folders = $this->getDavFolders('note');
+ $folders = array_map(fn ($f) => $f->get_name(), $folders);
+ $this->assertSame(['Notes', $folderName], $folders);
+ }
+}
diff --git a/tests/SyncTestCase.php b/tests/SyncTestCase.php
--- a/tests/SyncTestCase.php
+++ b/tests/SyncTestCase.php
@@ -185,6 +185,18 @@
$location = $folder->object_location($uid);
if ($folder->dav->create($location, $content, $dav_type) !== false) {
+ if ($type == 'note') {
+ $props = [];
+ if (preg_match('/<\!-- Title:(.*) -->/i', $content, $m)) {
+ $props['title'] = $m[1];
+ }
+ if (preg_match('/<\!-- Categories:(.*) -->/i', $content, $m)) {
+ $props['categories'] = explode(' ', $m[1]);
+ }
+
+ $folder->dav->propPatch($location, $props);
+ }
+
return;
}
}
@@ -231,6 +243,29 @@
$imap->set_metadata($name, ['/private/vendor/kolab/folder-type' => $type]);
}
$this->setSubscriptionState($name, $type, $subscriptionState);
+ return;
+ }
+
+ // Create DAV folder
+ $dav = $this->getDavStorage();
+ $type = preg_replace('/\..*$/', '', $type);
+
+ foreach ($dav->get_folders($type) as $folder) {
+ if ($folder->get_name() === $name) {
+ if ($subscriptionState) {
+ $this->setSubscriptionState($name, $type, $subscriptionState);
+ }
+ return;
+ }
+ }
+
+ $folder = ['name' => $name, 'type' => $type];
+ if ($dav->folder_update($folder) === false) {
+ throw new \Exception("Failed to create DAV folder: {$name}");
+ }
+
+ if ($subscriptionState) {
+ $this->setSubscriptionState($name, $type, $subscriptionState);
}
}
@@ -377,6 +412,16 @@
throw new \Exception("Folder not found");
}
+ /**
+ * Get list of folders from a DAV folder
+ */
+ protected function getDavFolders($type)
+ {
+ $dav = $this->getDavStorage();
+
+ return $dav->get_folders($type);
+ }
+
/**
* Initialize DAV storage
*/
@@ -519,6 +564,7 @@
$xpath->registerNamespace("ComposeMail", "uri:ComposeMail");
$xpath->registerNamespace("Email", "uri:Email");
$xpath->registerNamespace("Email2", "uri:Email2");
+ $xpath->registerNamespace("Notes", "uri:Notes");
$xpath->registerNamespace("Settings", "uri:Settings");
$xpath->registerNamespace("Tasks", "uri:Tasks");
diff --git a/tests/src/note1.html b/tests/src/note1.html
new file mode 100644
--- /dev/null
+++ b/tests/src/note1.html
@@ -0,0 +1,8 @@
+<html>
+<body>
+<!-- UID:12345678-12345678 -->
+<!-- Title:test note -->
+<!-- Categories:test1 test2 -->
+<p>test note 1</p>
+</body>
+</html>
diff --git a/tests/src/note2.html b/tests/src/note2.html
new file mode 100644
--- /dev/null
+++ b/tests/src/note2.html
@@ -0,0 +1,7 @@
+<html>
+<body>
+<!-- UID:aaaa-aaaa -->
+<!-- Title:test note 2 -->
+<p>test note 2</p>
+</body>
+</html>
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Apr 3, 2:26 AM (21 h, 6 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18822139
Default Alt Text
D5838.1775183185.diff (25 KB)
Attached To
Mode
D5838: WebDAV Notes Support
Attached
Detach File
Event Timeline