mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-07-13 03:27:39 +03:00
Added: Plugin: Contacts suggestion from ldap
Added: Custom favicon setting + Small fixes
This commit is contained in:
parent
d6d19c99bf
commit
7312b2854b
25 changed files with 526 additions and 25 deletions
20
plugins/ldap-contacts-suggestions/LICENSE
Normal file
20
plugins/ldap-contacts-suggestions/LICENSE
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 RainLoop Team
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
317
plugins/ldap-contacts-suggestions/LdapContactsSuggestions.php
Normal file
317
plugins/ldap-contacts-suggestions/LdapContactsSuggestions.php
Normal file
|
|
@ -0,0 +1,317 @@
|
|||
<?php
|
||||
|
||||
class LdapContactsSuggestions implements \RainLoop\Providers\Suggestions\ISuggestions
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sHostName = '127.0.0.1';
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $iHostPort = 389;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sAccessDn = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sAccessPassword = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sUsersDn = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sObjectClass = 'inetOrgPerson';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sNameField = 'givenname';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sEmailField = 'mail';
|
||||
|
||||
/**
|
||||
* @var \MailSo\Log\Logger
|
||||
*/
|
||||
private $oLogger = null;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sAllowedEmails = '';
|
||||
|
||||
/**
|
||||
* @param string $sHostName
|
||||
* @param int $iHostPort
|
||||
* @param string $sAccessDn
|
||||
* @param string $sAccessPassword
|
||||
* @param string $sUsersDn
|
||||
* @param string $sObjectClass
|
||||
* @param string $sNameField
|
||||
* @param string $sEmailField
|
||||
*
|
||||
* @return \LdapContactsSuggestions
|
||||
*/
|
||||
public function SetConfig($sHostName, $iHostPort, $sAccessDn, $sAccessPassword, $sUsersDn, $sObjectClass, $sNameField, $sEmailField)
|
||||
{
|
||||
$this->sHostName = $sHostName;
|
||||
$this->iHostPort = $iHostPort;
|
||||
$this->sAccessDn = $sAccessDn;
|
||||
$this->sAccessPassword = $sAccessPassword;
|
||||
$this->sUsersDn = $sUsersDn;
|
||||
$this->sObjectClass = $sObjectClass;
|
||||
$this->sNameField = $sNameField;
|
||||
$this->sEmailField = $sEmailField;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sAllowedEmails
|
||||
*
|
||||
* @return \LdapContactsSuggestions
|
||||
*/
|
||||
public function SetAllowedEmails($sAllowedEmails)
|
||||
{
|
||||
$this->sAllowedEmails = $sAllowedEmails;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Model\Account $oAccount
|
||||
* @param string $sQuery
|
||||
* @param int $iLimit = 20
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function Process($oAccount, $sQuery, $iLimit = 20)
|
||||
{
|
||||
$sQuery = \trim($sQuery);
|
||||
|
||||
if (2 > \strlen($sQuery))
|
||||
{
|
||||
return array();
|
||||
}
|
||||
else if (!$oAccount || !\RainLoop\Plugins\Helper::ValidateWildcardValues($oAccount->Email(), $this->sAllowedEmails))
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
$aResult = $this->ldapSearch($oAccount, $sQuery);
|
||||
|
||||
$aResult = \RainLoop\Utils::RemoveSuggestionDuplicates($aResult);
|
||||
if ($iLimit < \count($aResult))
|
||||
{
|
||||
$aResult = \array_slice($aResult, 0, $iLimit);
|
||||
}
|
||||
|
||||
return $aResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $aLdapItem
|
||||
* @param array $aEmailFields
|
||||
* @param array $aNameFields
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function findNameAndEmail($aLdapItem, $aEmailFields, $aNameFields)
|
||||
{
|
||||
$sEmail = $sName = '';
|
||||
if ($aLdapItem)
|
||||
{
|
||||
foreach ($aEmailFields as $sField)
|
||||
{
|
||||
if (!empty($aLdapItem[$sField][0]))
|
||||
{
|
||||
$sEmail = \trim($aLdapItem[$sField][0]);
|
||||
if (!empty($sEmail))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($aNameFields as $sField)
|
||||
{
|
||||
if (!empty($aLdapItem[$sField][0]))
|
||||
{
|
||||
$sName = \trim($aLdapItem[$sField][0]);
|
||||
if (!empty($sName))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array($sEmail, $sName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Model\Account $oAccount
|
||||
* @param string $sQuery
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function ldapSearch($oAccount, $sQuery)
|
||||
{
|
||||
$sSearchEscaped = $this->escape($sQuery);
|
||||
|
||||
$aResult = array();
|
||||
$oCon = @\ldap_connect($this->sHostName, $this->iHostPort);
|
||||
if ($oCon)
|
||||
{
|
||||
$this->oLogger->Write('ldap_connect: connected', \MailSo\Log\Enumerations\Type::INFO, 'LDAP');
|
||||
|
||||
@\ldap_set_option($oCon, LDAP_OPT_PROTOCOL_VERSION, 3);
|
||||
|
||||
if (!@\ldap_bind($oCon, $this->sAccessDn, $this->sAccessPassword))
|
||||
{
|
||||
$this->logLdapError($oCon, 'ldap_bind');
|
||||
return $aResult;
|
||||
}
|
||||
|
||||
$sDomain = \MailSo\Base\Utils::GetDomainFromEmail($oAccount->Email());
|
||||
$sSearchDn = \strtr($this->sUsersDn, array(
|
||||
'{domain}' => $sDomain,
|
||||
'{domain:dc}' => 'dc='.\strtr($sDomain, array('.' => ',dc=')),
|
||||
'{email}' => $oAccount->Email(),
|
||||
'{email:user}' => \MailSo\Base\Utils::GetAccountNameFromEmail($oAccount->Email()),
|
||||
'{email:domain}' => $sDomain,
|
||||
'{login}' => $oAccount->Login(),
|
||||
'{imap:login}' => $oAccount->Login(),
|
||||
'{imap:host}' => $oAccount->DomainIncHost(),
|
||||
'{imap:port}' => $oAccount->DomainIncPort()
|
||||
));
|
||||
|
||||
$aEmails = empty($this->sEmailField) ? array() : \explode(',', $this->sEmailField);
|
||||
$aNames = empty($this->sNameField) ? array() : \explode(',', $this->sNameField);
|
||||
|
||||
$aEmails = \array_map('trim', $aEmails);
|
||||
$aNames = \array_map('trim', $aNames);
|
||||
|
||||
$aFields = \array_merge($aEmails, $aNames);
|
||||
|
||||
$aItems = array();
|
||||
$sSubFilter = '';
|
||||
foreach ($aFields as $sItem)
|
||||
{
|
||||
if (!empty($sItem))
|
||||
{
|
||||
$aItems[] = $sItem;
|
||||
$sSubFilter .= '('.$sItem.'=*'.$sSearchEscaped.'*)';
|
||||
}
|
||||
}
|
||||
|
||||
$sFilter = '(&(objectclass='.$this->sObjectClass.')';
|
||||
$sFilter .= (1 < count($aItems) ? '(|' : '').$sSubFilter.(1 < count($aItems) ? ')' : '');
|
||||
$sFilter .= ')';
|
||||
|
||||
$this->oLogger->Write('ldap_search: start: '.$sSearchDn.' / '.$sFilter, \MailSo\Log\Enumerations\Type::INFO, 'LDAP');
|
||||
$oS = @\ldap_search($oCon, $sSearchDn, $sFilter, $aItems, 0, 30, 30);
|
||||
if ($oS)
|
||||
{
|
||||
$aEntries = @\ldap_get_entries($oCon, $oS);
|
||||
if (is_array($aEntries))
|
||||
{
|
||||
if (isset($aEntries['count']))
|
||||
{
|
||||
unset($aEntries['count']);
|
||||
}
|
||||
|
||||
foreach ($aEntries as $aItem)
|
||||
{
|
||||
if ($aItem)
|
||||
{
|
||||
$sName = $sEmail = '';
|
||||
list ($sEmail, $sName) = $this->findNameAndEmail($aItem, $aEmails, $aNames);
|
||||
if (!empty($sEmail))
|
||||
{
|
||||
$aResult[] = array($sEmail, $sName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->logLdapError($oCon, 'ldap_get_entries');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->logLdapError($oCon, 'ldap_search');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return $aResult;
|
||||
}
|
||||
|
||||
return $aResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sStr
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function escape($sStr)
|
||||
{
|
||||
$aNewChars = array();
|
||||
$aChars = array('\\', '*', '(', ')', \chr(0));
|
||||
|
||||
foreach ($aChars as $iIndex => $sValue)
|
||||
{
|
||||
$aNewChars[$iIndex] = '\\'.\str_pad(\dechex(\ord($sValue)), 2, '0');
|
||||
}
|
||||
|
||||
return \str_replace($aChars, $aNewChars, $sStr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $oCon
|
||||
* @param string $sCmd
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function logLdapError($oCon, $sCmd)
|
||||
{
|
||||
if ($this->oLogger)
|
||||
{
|
||||
$sError = $oCon ? @\ldap_error($oCon) : '';
|
||||
$iErrno = $oCon ? @\ldap_errno($oCon) : 0;
|
||||
|
||||
$this->oLogger->Write($sCmd.' error: '.$sError.' ('.$iErrno.')',
|
||||
\MailSo\Log\Enumerations\Type::WARNING, 'LDAP');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \MailSo\Log\Logger $oLogger
|
||||
*
|
||||
* @return \LdapContactsSuggestions
|
||||
*/
|
||||
public function SetLogger($oLogger)
|
||||
{
|
||||
if ($oLogger instanceof \MailSo\Log\Logger)
|
||||
{
|
||||
$this->oLogger = $oLogger;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
1
plugins/ldap-contacts-suggestions/VERSION
Normal file
1
plugins/ldap-contacts-suggestions/VERSION
Normal file
|
|
@ -0,0 +1 @@
|
|||
1.0
|
||||
92
plugins/ldap-contacts-suggestions/index.php
Normal file
92
plugins/ldap-contacts-suggestions/index.php
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
<?php
|
||||
|
||||
class LdapContactsSuggestionsPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||
{
|
||||
public function Init()
|
||||
{
|
||||
$this->addHook('main.fabrica', 'MainFabrica');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function Supported()
|
||||
{
|
||||
if (!\function_exists('ldap_connect'))
|
||||
{
|
||||
return 'The LDAP PHP exention must be installed to use this plugin';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sName
|
||||
* @param mixed $mResult
|
||||
*/
|
||||
public function MainFabrica($sName, &$mResult)
|
||||
{
|
||||
switch ($sName)
|
||||
{
|
||||
case 'suggestions':
|
||||
|
||||
if (!\is_array($mResult))
|
||||
{
|
||||
$mResult = array();
|
||||
}
|
||||
|
||||
$sHostName = \trim($this->Config()->Get('plugin', 'hostname', ''));
|
||||
$iHostPort = (int) $this->Config()->Get('plugin', 'port', 389);
|
||||
$sAccessDn = \trim($this->Config()->Get('plugin', 'access_dn', ''));
|
||||
$sAccessPassword = \trim($this->Config()->Get('plugin', 'access_password', ''));
|
||||
$sUsersDn = \trim($this->Config()->Get('plugin', 'users_dn_format', ''));
|
||||
$sObjectClass = \trim($this->Config()->Get('plugin', 'object_class', ''));
|
||||
$sNameField = \trim($this->Config()->Get('plugin', 'name_field', ''));
|
||||
$sEmailField = \trim($this->Config()->Get('plugin', 'mail_field', ''));
|
||||
|
||||
if (0 < \strlen($sAccessDn) && 0 < \strlen($sAccessPassword) && 0 < \strlen($sUsersDn) &&
|
||||
0 < \strlen($sObjectClass) && 0 < \strlen($sEmailField))
|
||||
{
|
||||
include_once __DIR__.'/LdapContactsSuggestions.php';
|
||||
|
||||
$oProvider = new LdapContactsSuggestions();
|
||||
$oProvider->SetConfig($sHostName, $iHostPort, $sAccessDn, $sAccessPassword, $sUsersDn, $sObjectClass, $sNameField, $sEmailField);
|
||||
|
||||
$mResult[] = $oProvider;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function configMapping()
|
||||
{
|
||||
return array(
|
||||
\RainLoop\Plugins\Property::NewInstance('hostname')->SetLabel('LDAP hostname')
|
||||
->SetDefaultValue('127.0.0.1'),
|
||||
\RainLoop\Plugins\Property::NewInstance('port')->SetLabel('LDAP port')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::INT)
|
||||
->SetDefaultValue(389),
|
||||
\RainLoop\Plugins\Property::NewInstance('access_dn')->SetLabel('Access dn (login)')
|
||||
->SetDefaultValue(''),
|
||||
\RainLoop\Plugins\Property::NewInstance('access_password')->SetLabel('Access password')
|
||||
->SetType(\RainLoop\Enumerations\PluginPropertyType::PASSWORD)
|
||||
->SetDefaultValue(''),
|
||||
\RainLoop\Plugins\Property::NewInstance('users_dn_format')->SetLabel('Users DN format')
|
||||
->SetDescription('LDAP users dn format. Supported tokens: {email}, {login}, {domain}, {domain:dc}, {imap:login}, {imap:host}, {imap:port}')
|
||||
->SetDefaultValue('ou=People,dc=domain,dc=com'),
|
||||
\RainLoop\Plugins\Property::NewInstance('object_class')->SetLabel('objectClass value')
|
||||
->SetDefaultValue('inetOrgPerson'),
|
||||
\RainLoop\Plugins\Property::NewInstance('name_field')->SetLabel('Name field')
|
||||
->SetDefaultValue('givenname'),
|
||||
\RainLoop\Plugins\Property::NewInstance('mail_field')->SetLabel('Mail field')
|
||||
->SetDefaultValue('mail'),
|
||||
\RainLoop\Plugins\Property::NewInstance('allowed_emails')->SetLabel('Allowed emails')
|
||||
->SetDescription('Allowed emails, space as delimiter, wildcard supported. Example: user1@domain1.net user2@domain1.net *@domain2.net')
|
||||
->SetDefaultValue('*')
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue