diff --git a/plugins/avatars/avatars.js b/plugins/avatars/avatars.js index 6d45dc376..f18dbdf7f 100644 --- a/plugins/avatars/avatars.js +++ b/plugins/avatars/avatars.js @@ -22,10 +22,12 @@ view.viewUserPicVisible = ko.observable(false); view.message.subscribe(msg => { + view.viewUserPicVisible(false); if (msg) { let from = msg.from[0], bimi = 'pass' == from.dkimStatus ? 1 : 0; // view.viewUserPic(`?Avatar/${bimi}/${encodeURIComponent(from.email)}`); +// view.viewUserPicVisible(true); rl.pluginRemoteRequest((iError, data) => { if (!iError && data?.Result.type) { view.viewUserPic(`data:${data.Result.type};base64,${data.Result.data}`); @@ -38,6 +40,23 @@ } }); } +/* + if ('MailMessageList' === e.detail.viewModelTemplateID) { + const + template = document.getElementById('MailMessageList' ), + messageCheckbox = template.content.querySelector('.messageCheckbox'); + messageCheckbox.dataset.bind = 'attr:{style:$root.viewUserPic($data)}'; + e.detail.viewUserPic = msg => { + let from = msg.from[0], + bimi = 'pass' == from.dkimStatus ? 1 : 0; + return `background:no-repeat url("?Avatar/${bimi}/${encodeURIComponent(from.email)}") center / contain`; + return `background:no-repeat url("?Avatar/${bimi}/${encodeURIComponent(from.email)}") right / 32px;width:68px`; + }; + .checkboxMessage { + background: #000; + } + } +*/ }); })(window.rl); diff --git a/plugins/avatars/images/services/amazon.com.png b/plugins/avatars/images/services/amazon.com.png index 07ad04dff..adfc6f526 100644 Binary files a/plugins/avatars/images/services/amazon.com.png and b/plugins/avatars/images/services/amazon.com.png differ diff --git a/plugins/avatars/images/services/apple.com.png b/plugins/avatars/images/services/apple.com.png index 72b10f4df..31ca5e8fd 100644 Binary files a/plugins/avatars/images/services/apple.com.png and b/plugins/avatars/images/services/apple.com.png differ diff --git a/plugins/avatars/images/services/cnet.online.com.png b/plugins/avatars/images/services/cnet.online.com.png deleted file mode 100644 index b3f2b5325..000000000 Binary files a/plugins/avatars/images/services/cnet.online.com.png and /dev/null differ diff --git a/plugins/avatars/images/services/connect.asana.com.png b/plugins/avatars/images/services/connect.asana.com.png deleted file mode 100644 index 35d3e1db5..000000000 Binary files a/plugins/avatars/images/services/connect.asana.com.png and /dev/null differ diff --git a/plugins/avatars/images/services/e.paypal.com.png b/plugins/avatars/images/services/e.paypal.com.png deleted file mode 100644 index 7ddea03c9..000000000 Binary files a/plugins/avatars/images/services/e.paypal.com.png and /dev/null differ diff --git a/plugins/avatars/images/services/em.ea.com.png b/plugins/avatars/images/services/em.ea.com.png deleted file mode 100644 index e88b641c6..000000000 Binary files a/plugins/avatars/images/services/em.ea.com.png and /dev/null differ diff --git a/plugins/avatars/images/services/email.blizzard.com.png b/plugins/avatars/images/services/email.blizzard.com.png deleted file mode 100644 index f5baf8db8..000000000 Binary files a/plugins/avatars/images/services/email.blizzard.com.png and /dev/null differ diff --git a/plugins/avatars/images/services/email.microsoft.com.png b/plugins/avatars/images/services/email.microsoft.com.png deleted file mode 100644 index e058c2300..000000000 Binary files a/plugins/avatars/images/services/email.microsoft.com.png and /dev/null differ diff --git a/plugins/avatars/images/services/email.skype.com.png b/plugins/avatars/images/services/email.skype.com.png deleted file mode 100644 index 881b13cf8..000000000 Binary files a/plugins/avatars/images/services/email.skype.com.png and /dev/null differ diff --git a/plugins/avatars/images/services/facebookmail.com.png b/plugins/avatars/images/services/facebookmail.com.png deleted file mode 100644 index 2d416f898..000000000 Binary files a/plugins/avatars/images/services/facebookmail.com.png and /dev/null differ diff --git a/plugins/avatars/images/services/google.com.png b/plugins/avatars/images/services/google.com.png index 143c40f4a..7f6262573 100644 Binary files a/plugins/avatars/images/services/google.com.png and b/plugins/avatars/images/services/google.com.png differ diff --git a/plugins/avatars/images/services/id.apple.com.png b/plugins/avatars/images/services/id.apple.com.png deleted file mode 100644 index 72b10f4df..000000000 Binary files a/plugins/avatars/images/services/id.apple.com.png and /dev/null differ diff --git a/plugins/avatars/images/services/intl.paypal.com.png b/plugins/avatars/images/services/intl.paypal.com.png deleted file mode 100644 index 7ddea03c9..000000000 Binary files a/plugins/avatars/images/services/intl.paypal.com.png and /dev/null differ diff --git a/plugins/avatars/images/services/microsoft.com.png b/plugins/avatars/images/services/microsoft.com.png index e058c2300..bfe230d86 100644 Binary files a/plugins/avatars/images/services/microsoft.com.png and b/plugins/avatars/images/services/microsoft.com.png differ diff --git a/plugins/avatars/images/services/microsoftonline.com.png b/plugins/avatars/images/services/microsoftonline.com.png deleted file mode 100644 index e058c2300..000000000 Binary files a/plugins/avatars/images/services/microsoftonline.com.png and /dev/null differ diff --git a/plugins/avatars/images/services/myspace.com.png b/plugins/avatars/images/services/myspace.com.png deleted file mode 100644 index c29c00239..000000000 Binary files a/plugins/avatars/images/services/myspace.com.png and /dev/null differ diff --git a/plugins/avatars/images/services/news.myspace.com.png b/plugins/avatars/images/services/news.myspace.com.png deleted file mode 100644 index c29c00239..000000000 Binary files a/plugins/avatars/images/services/news.myspace.com.png and /dev/null differ diff --git a/plugins/avatars/images/services/news.onlive.com.png b/plugins/avatars/images/services/news.onlive.com.png deleted file mode 100644 index 8207cd108..000000000 Binary files a/plugins/avatars/images/services/news.onlive.com.png and /dev/null differ diff --git a/plugins/avatars/images/services/plus.google.com.png b/plugins/avatars/images/services/plus.google.com.png deleted file mode 100644 index 12ccdc99e..000000000 Binary files a/plugins/avatars/images/services/plus.google.com.png and /dev/null differ diff --git a/plugins/avatars/images/services/postmaster.twitter.com.png b/plugins/avatars/images/services/postmaster.twitter.com.png deleted file mode 100644 index 18112e856..000000000 Binary files a/plugins/avatars/images/services/postmaster.twitter.com.png and /dev/null differ diff --git a/plugins/avatars/images/services/reply.ebay.com.png b/plugins/avatars/images/services/reply.ebay.com.png deleted file mode 100644 index b38920ca3..000000000 Binary files a/plugins/avatars/images/services/reply.ebay.com.png and /dev/null differ diff --git a/plugins/avatars/images/services/reply1.ebay.com.png b/plugins/avatars/images/services/reply1.ebay.com.png deleted file mode 100644 index b38920ca3..000000000 Binary files a/plugins/avatars/images/services/reply1.ebay.com.png and /dev/null differ diff --git a/plugins/avatars/images/services/reply2.ebay.com.png b/plugins/avatars/images/services/reply2.ebay.com.png deleted file mode 100644 index b38920ca3..000000000 Binary files a/plugins/avatars/images/services/reply2.ebay.com.png and /dev/null differ diff --git a/plugins/avatars/images/services/reply3.ebay.com.png b/plugins/avatars/images/services/reply3.ebay.com.png deleted file mode 100644 index b38920ca3..000000000 Binary files a/plugins/avatars/images/services/reply3.ebay.com.png and /dev/null differ diff --git a/plugins/avatars/index.php b/plugins/avatars/index.php index 038e21137..61a8547c4 100644 --- a/plugins/avatars/index.php +++ b/plugins/avatars/index.php @@ -8,7 +8,7 @@ class AvatarsPlugin extends \RainLoop\Plugins\AbstractPlugin URL = 'https://snappymail.eu/', VERSION = '1.0', RELEASE = '2022-11-11', - REQUIRED = '2.21.0', + REQUIRED = '2.22.0', CATEGORY = 'Contacts', LICENSE = 'MIT', DESCRIPTION = ''; @@ -53,48 +53,82 @@ class AvatarsPlugin extends \RainLoop\Plugins\AbstractPlugin return null; } -// $this->verifyCacheByKey($sEmail); + $oActions = \RainLoop\Api::Actions(); + $oActions->verifyCacheByKey($sEmail); - // DATA_IMAGE_USER_DOT_PIC - $sDomain = \explode('@', $sEmail); - $sDomain = \array_pop($sDomain); - - $BIMI = $bBimi ? \SnappyMail\DNS::BIMI($sDomain) : null; - // TODO: process $BIMI value + $aResult = null; // TODO: lookup contacts vCard - - // TODO: make this optional - $aResult = static::Gravatar($sEmail); - - if (!$aResult && \file_exists(__DIR__ . '/images/services/'.$sDomain.'.png')) { - $aResult = [ - 'image/png', - \file_get_contents(__DIR__ . '/images/services/'.$sDomain.'.png') - ]; + $oAccount = $oActions->getAccountFromToken(); + if ($oAccount) { + $oAddressBookProvider = $oActions->AddressBookProvider($oAccount); + if ($oAddressBookProvider) { + $oContact = $oAddressBookProvider->GetContactByEmail($sEmail); + if ($oContact && $oContact->vCard && $oContact->vCard['PHOTO']) { + $aResult = [ + 'text/vcard', + $oContact->vCard + ]; + } + } } + if (!$aResult) { - $aResult = [ - 'image/png', - \file_get_contents(__DIR__.'/images/empty-contact.png') - ]; + $sDomain = \explode('@', $sEmail); + $sDomain = \array_pop($sDomain); + + $aUrls = []; + + $BIMI = $bBimi ? \SnappyMail\DNS::BIMI($sDomain) : null; + if ($BIMI) { + $aUrls[] = $BIMI; +// $aResult = ['text/uri-list', $BIMI]; + \SnappyMail\Log::debug('Avatar', "BIMI {$sDomain} for {$sUrl}"); + } else { + \SnappyMail\Log::notice('Avatar', "BIMI 404 for {$sDomain}"); + } + + // TODO: make Gravatar optional + $sAsciiEmail = \MailSo\Base\Utils::IdnToAscii($sEmail, true); + $aUrls[] = 'http://gravatar.com/avatar/'.\md5(\strtolower($sAsciiEmail)).'?s=80&d=404'; + + foreach ($aUrls as $sUrl) { + if ($aResult = static::getUrl($sUrl)) { + break; + } + } } -// $this->cacheByKey($sEmail); + if (!$aResult) { + $aServices = [ + "services/{$sDomain}", + 'services/' . \preg_replace('/^.+\\.([^.]+\\.[^.]+)$/D', '$1', $sDomain), + 'empty-contact' // DATA_IMAGE_USER_DOT_PIC + ]; + foreach ($aServices as $service) { + if (\file_exists(__DIR__ . "/images/{$service}.png")) { + $aResult = [ + 'image/png', + \file_get_contents(__DIR__ . "/images/{$service}.png") + ]; + break; + } + } + } + + $oActions->cacheByKey($sEmail); return $aResult; } - private static function Gravatar(string $sEmail) : ?array + private static function getUrl(string $sUrl) : ?array { - $sEmail = \MailSo\Base\Utils::IdnToAscii($sEmail, true); - $sGravatarUrl = 'http://gravatar.com/avatar/'.\md5(\strtolower($sEmail)).'?s=80&d=404'; $oHTTP = \SnappyMail\HTTP\Request::factory(/*'socket' or 'curl'*/); $oHTTP->proxy = \RainLoop\Api::Config()->Get('labs', 'curl_proxy', ''); $oHTTP->proxy_auth = \RainLoop\Api::Config()->Get('labs', 'curl_proxy_auth', ''); $oHTTP->max_response_kb = 0; $oHTTP->timeout = 15; // timeout in seconds. - $oResponse = $oHTTP->doRequest('GET', $sGravatarUrl); + $oResponse = $oHTTP->doRequest('GET', $sUrl); if ($oResponse) { if (200 === $oResponse->status && \str_starts_with($oResponse->getHeader('content-type'), 'image/')) { return [ @@ -102,11 +136,10 @@ class AvatarsPlugin extends \RainLoop\Plugins\AbstractPlugin $oResponse->body ]; } - \SnappyMail\Log::notice('Gravatar', "error {$oResponse->status} for {$sGravatarUrl}"); + \SnappyMail\Log::notice('Avatar', "error {$oResponse->status} for {$sUrl}"); } else { - \SnappyMail\Log::warning('Gravatar', "failed for {$sGravatarUrl}"); + \SnappyMail\Log::warning('Avatar', "failed for {$sUrl}"); } return null; } - } diff --git a/plugins/kolab/KolabAddressBook.php b/plugins/kolab/KolabAddressBook.php index 64c058e09..89b704227 100644 --- a/plugins/kolab/KolabAddressBook.php +++ b/plugins/kolab/KolabAddressBook.php @@ -313,6 +313,12 @@ class KolabAddressBook implements \RainLoop\Providers\AddressBook\AddressBookInt return $aResult; } + public function GetContactByEmail(string $sEmail) : ?Contact; + { + // TODO + return null; + } + public function GetContactByID($mID, bool $bIsStrID = false) : ?Contact { if ($bIsStrID) { diff --git a/plugins/kolab/index.php b/plugins/kolab/index.php index 84902031a..49cb56167 100644 --- a/plugins/kolab/index.php +++ b/plugins/kolab/index.php @@ -8,7 +8,7 @@ class KolabPlugin extends \RainLoop\Plugins\AbstractPlugin RELEASE = '2022-09-06', CATEGORY = 'Contacts', DESCRIPTION = 'Use an Address Book of Kolab.', - REQUIRED = '2.18.0'; + REQUIRED = '2.22.0'; public function Init() : void { diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook.php index d9f0fd987..6136e07c5 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Providers/AddressBook.php @@ -60,6 +60,11 @@ class AddressBook extends AbstractProvider ) : array(); } + public function GetContactByEmail(string $sEmail) : ?AddressBook\Classes\Contact + { + return $this->IsActive() ? $this->oDriver->GetContactByEmail($sEmail) : null; + } + public function GetContactByID($mID, bool $bIsStrID = false) : ?AddressBook\Classes\Contact { return $this->IsActive() ? $this->oDriver->GetContactByID($mID, $bIsStrID) : null; 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 d0ce8ef54..564a0d48b 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 @@ -20,6 +20,8 @@ interface AddressBookInterface public function GetContacts(int $iOffset = 0, int $iLimit = 20, string $sSearch = '', int &$iResultCount = 0) : array; + public function GetContactByEmail(string $sEmail) : ?Classes\Contact; + public function GetContactByID($mID, bool $bIsStrID = false) : ?Classes\Contact; public function GetSuggestions(string $sSearch, int $iLimit = 20) : array; 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 ae698febb..f7bbf15d4 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 @@ -694,6 +694,40 @@ class PdoAddressBook return []; } + /** + * @param mixed $mID + */ + public function GetContactByEmail(string $sEmail) : ?Contact + { + $sLowerSearch = $this->specialConvertSearchValueLower($sEmail); + + $sSql = 'SELECT + DISTINCT id_contact + FROM rainloop_ab_properties + WHERE id_user = :id_user + AND prop_type = '.PropertyType::JCARD.' + AND ('. + 'prop_value LIKE :search ESCAPE \'=\'' + . (\strlen($sLowerSearch) ? ' OR (prop_value_lower <> \'\' AND prop_value_lower LIKE :search_lower ESCAPE \'=\')' : ''). + ')'; + $aParams = array( + ':id_user' => array($this->iUserID, \PDO::PARAM_INT), + ':search' => array($this->specialConvertSearchValue($sEmail, '='), \PDO::PARAM_STR) + ); + if (\strlen($sLowerSearch)) { + $aParams[':search_lower'] = array($sLowerSearch, \PDO::PARAM_STR); + } + + $oContact = null; + $iIdContact = 0; + + $aContacts = $this->getContactsFromPDO( + $this->prepareAndExecute($sSql, $aParams) + ); + + return $aContacts ? $aContacts[0] : null; + } + /** * @param mixed $mID */ diff --git a/snappymail/v/0.0.0/app/libraries/snappymail/dns.php b/snappymail/v/0.0.0/app/libraries/snappymail/dns.php index 302f2e841..cb3ebda20 100644 --- a/snappymail/v/0.0.0/app/libraries/snappymail/dns.php +++ b/snappymail/v/0.0.0/app/libraries/snappymail/dns.php @@ -4,6 +4,10 @@ namespace SnappyMail; abstract class DNS { + /** + * $domain = 'bimigroup.org' + * Then a TXT lookup is done on 'default._bimi.bimigroup.org' + */ public static function BIMI(string $domain) : string { $oCache = \RainLoop\Api::Actions()->Cacher(); @@ -18,7 +22,7 @@ abstract class DNS } if (null === $BIMI) { $BIMI = ''; - $values = \dns_get_record($domain, \DNS_TXT); + $values = \dns_get_record("default._bimi.{$domain}", \DNS_TXT); if ($values) { foreach ($values as $value) { if (\str_starts_with($value['txt'], 'v=BIMI1')) {