Added draft code to use Kolab as AddressBook

This commit is contained in:
the-djmaze 2022-05-11 15:14:28 +02:00
parent 733a96a987
commit be35be8908
6 changed files with 246 additions and 42 deletions

View file

@ -293,7 +293,7 @@ abstract class SearchCriterias
return $sCriteriasResult ?: 'ALL';
}
private static function escapeSearchString(\MailSo\Imap\ImapClient $oImapClient, string $sSearch) : string
public static function escapeSearchString(\MailSo\Imap\ImapClient $oImapClient, string $sSearch) : string
{
return !\MailSo\Base\Utils::IsAscii($sSearch)
? '{'.\strlen($sSearch).'}'."\r\n".$sSearch : $oImapClient->EscapeString($sSearch);

View file

@ -267,6 +267,7 @@ class Actions
$sDsn = $sDsnType . ':' . \preg_replace('/^[a-z]+:/', '', $sDsn);
}
$mResult = new Providers\AddressBook\PdoAddressBook($sDsn, $sUser, $sPassword, $sDsnType);
// $mResult = new Providers\AddressBook\KolabAddressBook($this->MailClient()->ImapClient());
break;
case 'identities':
case 'suggestions':

View file

@ -14,9 +14,9 @@ interface AddressBookInterface
public function ContactSave(string $sEmail, Classes\Contact $oContact) : bool;
public function DeleteContacts(string $sEmail, array $aContactIds, bool $bSyncDb = true) : bool;
public function DeleteContacts(string $sEmail, array $aContactIds) : bool;
public function DeleteAllContacts(string $sEmail, bool $bSyncDb = true) : bool;
public function DeleteAllContacts(string $sEmail) : bool;
public function GetContacts(string $sEmail, int $iOffset = 0, int $iLimit = 20, string $sSearch = '', int &$iResultCount = 0) : array;

View file

@ -180,44 +180,20 @@ class Contact implements \JsonSerializable
return $this->IdContactStr.'.vcf';
}
public function ToVCard(string $sPreVCard = '', $oLogger = null) : string
public function GetUID() : string
{
$this->UpdateDependentValues();
if ("\xef\xbb\xbf" === \substr($sPreVCard, 0, 3))
{
$sPreVCard = \substr($sPreVCard, 3);
}
$oVCard = null;
if (\strlen($sPreVCard))
{
try
{
$oVCard = \Sabre\VObject\Reader::read($sPreVCard);
}
catch (\Throwable $oExc)
{
if ($oLogger)
{
$oLogger->WriteException($oExc);
$oLogger->WriteDump($sPreVCard);
}
foreach ($this->Properties as $oProperty) {
if ($oProperty && PropertyType::UID == $oProperty->Type) {
return $oProperty->Value;
}
}
return $this->IdContactStr;
}
// if ($oLogger)
// {
// $oLogger->WriteDump($sPreVCard);
// }
if (!$oVCard)
{
$oVCard = new \Sabre\VObject\Component\VCard();
}
private function fillVCard(\Sabre\VObject\Component\VCard $oVCard) : void
{
$oVCard->VERSION = '3.0';
$oVCard->PRODID = '-//RainLoop//'.APP_VERSION.'//EN';
$oVCard->PRODID = '-//SnappyMail//'.APP_VERSION.'//EN';
unset($oVCard->FN, $oVCard->EMAIL, $oVCard->TEL, $oVCard->URL, $oVCard->NICKNAME);
@ -282,10 +258,70 @@ class Contact implements \JsonSerializable
$oVCard->UID = empty($sUid) ? $this->IdContactStr : $sUid;
$oVCard->N = array($sLastName, $sFirstName, $sMiddleName, $sPrefix, $sSuffix);
$oVCard->REV = \gmdate('Ymd', $this->Changed).'T'.\gmdate('His', $this->Changed).'Z';
}
public function ToVCard(string $sPreVCard = '', $oLogger = null) : string
{
$this->UpdateDependentValues();
if ("\xef\xbb\xbf" === \substr($sPreVCard, 0, 3)) {
$sPreVCard = \substr($sPreVCard, 3);
}
$oVCard = null;
if (\strlen($sPreVCard)) {
try
{
$oVCard = \Sabre\VObject\Reader::read($sPreVCard);
}
catch (\Throwable $oExc)
{
if ($oLogger) {
$oLogger->WriteException($oExc);
$oLogger->WriteDump($sPreVCard);
}
}
}
// if ($oLogger) {
// $oLogger->WriteDump($sPreVCard);
// }
$oVCard = $oVCard ?: new \Sabre\VObject\Component\VCard();
$this->fillVCard($oVCard);
return (string) $oVCard->serialize();
}
public function ToXCard(string $sPreVCard = '', $oLogger = null) : string
{
$this->UpdateDependentValues();
$oVCard = null;
if (\strlen($sPreVCard)) {
try
{
$oVCard = \Sabre\VObject\Reader::readXML($sPreVCard);
}
catch (\Throwable $oExc)
{
if ($oLogger) {
$oLogger->WriteException($oExc);
$oLogger->WriteDump($sPreVCard);
}
}
}
$oVCard = $oVCard ?: new \Sabre\VObject\Component\VCard();
$this->fillVCard($oVCard);
return (string) \Sabre\VObject\Writer::writeXml($oVCard);
}
public function ToCsv(bool $bWithHeader = false) : string
{
$aData = array();

View file

@ -0,0 +1,170 @@
<?php
namespace RainLoop\Providers\AddressBook;
use RainLoop\Providers\AddressBook\Enumerations\PropertyType;
class KolabAddressBook implements \RainLoop\Providers\AddressBook\AddressBookInterface
{
use CardDAV;
protected $sFolderName;
function __construct(\MailSo\Imap\ImapClient $oImapClient)
{
$this->oImapClient = $oImapClient;
}
public function SetFolder(string $sFolderName) : bool
{
$metadata = $this->oImapClient->FolderGetMetadata($sFolderName, [\MailSo\Imap\Enumerations\MetadataKeys::KOLAB_CTYPE]);
if ($metadata && 'contact' !== \array_shift($metadata)) {
// Throw error
// $this->oImapClient->FolderList() : array
}
$this->oImapClient->FolderSelect($sFolderName);
$this->sFolderName = $sFolderName;
}
public function IsSupported() : bool
{
// Check $this->oImapClient->IsSupported('METADATA')
return true;
}
public function IsSharingAllowed() : bool
{
return $this->IsSupported() && false; // TODO
}
public function Sync(array $oConfig) : bool
{
// TODO
return false;
}
public function Export(string $sEmail, string $sType = 'vcf') : bool
{
// TODO
return false;
}
public function ContactSave(string $sEmail, Classes\Contact $oContact) : bool
{
// TODO
// $emails = $oContact->GetEmails();
$oContact->PopulateDisplayAndFullNameValue();
$sUID = $oContact->GetUID();
$oMessage = new \MailSo\Mime\Message();
$oMessage->SetFrom(new \MailSo\Mime\Email($sEmail, $oContact->Display));
$oMessage->SetSubject($sUID);
// $oMessage->SetDate(\time());
$oMessage->Headers->AddByName('X-Kolab-Type', 'application/x-vnd.kolab.contact');
$oMessage->Headers->AddByName('X-Kolab-Mime-Version', '3.0');
// $oMessage->Headers->AddByName('User-Agent', 'SnappyMail');
$oPart = new \MailSo\Mime\Part;
$oPart->Headers->AddByName(\MailSo\Mime\Enumerations\Header::CONTENT_TYPE, 'text/plain');
$oPart->Headers->AddByName(\MailSo\Mime\Enumerations\Header::CONTENT_TRANSFER_ENCODING, '7Bit');
$oPart->Body = "This is a Kolab Groupware object.\r\n"
. "To view this object you will need an email client that can understand the Kolab Groupware format.\r\n"
. "For a list of such email clients please visit\r\n"
. "http://www.kolab.org/get-kolab";
$oMessage->SubParts->append($oPart);
// Now the vCard
$oPart = new \MailSo\Mime\Part;
$oPart->Headers->AddByName(\MailSo\Mime\Enumerations\Header::CONTENT_TYPE, 'application/vcard+xml; name="kolab.xml"');
// $oPart->Headers->AddByName(\MailSo\Mime\Enumerations\Header::CONTENT_TRANSFER_ENCODING, 'quoted-printable');
$oPart->Headers->AddByName(\MailSo\Mime\Enumerations\Header::CONTENT_DISPOSITION, 'attachment; filename="kolab.xml"');
$oPart->Body = $oContact->ToXCard($sPreVCard = '', $oLogger);
$oMessage->SubParts->append($oPart);
// Search in IMAP folder:
$email = \MailSo\Imap\SearchCriterias::escapeSearchString($sEmail);
$aUids = $this->oImapClient->MessageSimpleSearch("SUBJECT {$sUID}");
// $aUids = $this->oImapClient->MessageSimpleSearch("OR SUBJECT {$sUID} FROM {$email}");
// $aUids = $this->oImapClient->MessageSimpleSearch("OR SUBJECT {$sUID} FROM {$email} BODY {$email}");
if ($aUids) {
// Replace Message
if (false && $this->oImapClient->IsSupported('REPLACE')) {
// UID REPLACE
} else {
$oRange = new \MailSo\Imap\SequenceSet($aUids[0]);
$this->oImapClient->MessageStoreFlag($oRange,
array(\MailSo\Imap\Enumerations\MessageFlag::DELETED),
\MailSo\Imap\Enumerations\StoreAction::ADD_FLAGS_SILENT
);
$this->oImapClient->FolderExpunge($oRange);
}
}
// Store Message
$rMessageStream = \MailSo\Base\ResourceRegistry::CreateMemoryResource();
$iMessageStreamSize = \MailSo\Base\Utils::MultipleStreamWriter(
$oMessage->ToStream(false), array($rMessageStream), 8192, true, true);
if (false !== $iMessageStreamSize) {
\rewind($rMessageStream);
$this->oImapClient->MessageAppendStream($this->sFolderName, $rMessageStream, $iMessageStreamSize);
}
return true;
}
public function DeleteContacts(string $sEmail, array $aContactIds) : bool
{
// TODO
return false;
}
public function DeleteAllContacts(string $sEmail) : bool
{
// TODO
return false;
}
public function GetContacts(string $sEmail, int $iOffset = 0, int $iLimit = 20, string $sSearch = '', int &$iResultCount = 0) : array
{
// TODO
return [];
}
public function GetContactByID(string $sEmail, $mID, bool $bIsStrID = false) : ?Classes\Contact
{
// TODO
return null;
}
public function GetSuggestions(string $sEmail, string $sSearch, int $iLimit = 20) : array
{
// TODO
return [];
}
public function IncFrec(string $sEmail, array $aEmails, bool $bCreateAuto = true) : bool
{
return false;
}
public function Test() : string
{
$sResult = '';
try
{
// $sResult = 'Unknown error';
}
catch (\Throwable $oException)
{
$sResult = $oException->getMessage();
if (!\is_string($sResult) || empty($sResult)) {
$sResult = 'Unknown error';
}
}
return $sResult;
}
}

View file

@ -308,7 +308,7 @@ class PdoAddressBook
$bCsvHeader = true;
$aDatabaseSyncData = $this->prepareDatabaseSyncData($iUserID);
if (\is_array($aDatabaseSyncData) && \count($aDatabaseSyncData))
if (\count($aDatabaseSyncData))
{
foreach ($aDatabaseSyncData as $mData)
{
@ -476,12 +476,9 @@ class PdoAddressBook
return true;
}
public function DeleteAllContacts(string $sEmail, bool $bSyncDb = true) : bool
public function DeleteAllContacts(string $sEmail) : bool
{
if ($bSyncDb)
{
$this->SyncDatabase();
}
$this->SyncDatabase();
$iUserID = $this->getUserId($sEmail);