diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/SearchCriterias.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/SearchCriterias.php index 91178e146..ce1ed9e79 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/SearchCriterias.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/SearchCriterias.php @@ -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); diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions.php index b5c0d1867..924f8ee36 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions.php @@ -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': diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/AddressBookInterface.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/AddressBookInterface.php index 7bce55794..7cf207b1d 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/AddressBookInterface.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/AddressBookInterface.php @@ -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; diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/Classes/Contact.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/Classes/Contact.php index 9a81c61b5..0ce9fbf97 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/Classes/Contact.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/Classes/Contact.php @@ -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(); diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/KolabAddressBook.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/KolabAddressBook.php new file mode 100644 index 000000000..d45a45f5e --- /dev/null +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/KolabAddressBook.php @@ -0,0 +1,170 @@ +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; + } +} diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/PdoAddressBook.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/PdoAddressBook.php index 1055a9aca..2bb52fbc5 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/PdoAddressBook.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook/PdoAddressBook.php @@ -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);