Uploading and preparing the repository to the dev version.

Original unminified source code (dev folder - js, css, less) (fixes #6)
Grunt build system
Multiple identities correction (fixes #9)
Compose html editor (fixes #12)
New general settings - Loading Description
New warning about default admin password
Split general and login screen settings
This commit is contained in:
RainLoop Team 2013-11-16 02:21:12 +04:00
parent afad45137e
commit 4cc2207513
846 changed files with 99453 additions and 2123 deletions

View file

@ -0,0 +1,181 @@
<?php
namespace RainLoop;
class Account
{
/**
* @var string
*/
private $sEmail;
/**
* @var string
*/
private $sLogin;
/**
* @var int
*/
private $sPassword;
/**
* @var string
*/
private $sSignMeToken;
/**
* @var \RainLoop\Domain
*/
private $oDomain;
/**
* @var string
*/
private $sParentEmail;
/**
* @param string $sEmail
* @param string $sLogin
* @param string $sPassword
* @param \RainLoop\Domain $oDomain
* @param string $sSignMeToken = ''
* @param string $sParentEmail = '';
*
* @return void
*/
protected function __construct($sEmail, $sLogin, $sPassword, \RainLoop\Domain $oDomain, $sSignMeToken = '', $sParentEmail = '')
{
$this->sEmail = \strtolower($sEmail);
$this->sLogin = $sLogin;
$this->sPassword = $sPassword;
$this->oDomain = $oDomain;
$this->sSignMeToken = $sSignMeToken;
$this->sParentEmail = \strtolower($sParentEmail);
}
/**
* @param string $sEmail
* @param string $sLogin
* @param string $sPassword
* @param \RainLoop\Domain $oDomain
* @param string $sSignMeToken = ''
* @param string $sParentEmail = ''
*
* @return \RainLoop\Account
*/
public static function NewInstance($sEmail, $sLogin, $sPassword, \RainLoop\Domain $oDomain, $sSignMeToken = '', $sParentEmail = '')
{
return new self($sEmail, $sLogin, $sPassword, $oDomain, $sSignMeToken, $sParentEmail);
}
/**
* @return string
*/
public function Email()
{
return $this->sEmail;
}
/**
* @return string
*/
public function ParentEmail()
{
return $this->sParentEmail;
}
/**
* @return string
*/
public function ParentEmailHelper()
{
return 0 < \strlen($this->sParentEmail) ? $this->sParentEmail : $this->sEmail;
}
/**
* @return string
*/
public function Login()
{
return $this->sLogin;
}
/**
* @return string
*/
public function Password()
{
return $this->sPassword;
}
/**
* @return bool
*/
public function SignMe()
{
return 0 < \strlen($this->sSignMeToken);
}
/**
* @return string
*/
public function SignMeToken()
{
return $this->sSignMeToken;
}
/**
* @return \RainLoop\Domain
*/
public function Domain()
{
return $this->oDomain;
}
/**
* @return \RainLoop\Domain
*/
public function Hash()
{
return md5(APP_SALT.$this->Email().APP_SALT.$this->oDomain->IncHost().APP_SALT.$this->oDomain->IncPort().
APP_SALT.$this->Password().APP_SALT.'0'.APP_SALT.$this->ParentEmail().APP_SALT);
}
/**
* @param string $sPassword
*
* @return void
*/
public function SetPassword($sPassword)
{
$this->sPassword = $sPassword;
}
/**
* @param string $sParentEmail
*
* @return void
*/
public function SetParentEmail($sParentEmail)
{
$this->sParentEmail = \strtolower($sParentEmail);
}
/**
* @return string
*/
public function GetAuthToken()
{
return \RainLoop\Utils::EncodeKeyValues(array(
'token',
$this->sEmail,
$this->sLogin,
$this->sPassword,
'0', // PasswordIsXOAuth2
$this->sSignMeToken,
$this->sParentEmail,
\RainLoop\Utils::GetShortToken()
));
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,198 @@
<?php
namespace RainLoop\Config;
abstract class AbstractConfig
{
/**
* @var string
*/
private $sFile;
/**
* @var array
*/
private $aData;
/**
* @var string
*/
protected $sFilePrefix;
/**
* @param string $sFileName
* @param string $sFilePrefix = ''
*
* @return void
*/
public function __construct($sFileName, $sFilePrefix = '')
{
$this->sFile = \APP_PRIVATE_DATA.'configs/'.$sFileName;
$this->sFilePrefix = $sFilePrefix;
$this->aData = $this->defaultValues();
}
/**
* @return array
*/
protected abstract function defaultValues();
/**
* @return bool
*/
public function IsInited()
{
return is_array($this->aData) && 0 < count($this->aData);
}
/**
* @param string $sSection
* @param string $sName
* @param mixed $mDefault = null
*
* @return mixed
*/
public function Get($sSection, $sName, $mDefault = null)
{
$mResult = $mDefault;
if (isset($this->aData[$sSection][$sName][0]))
{
$mResult = $this->aData[$sSection][$sName][0];
}
return $mResult;
}
/**
* @param string $sSectionKey
* @param string $sParamKey
* @param mixed $mParamValue
*
* @return void
*/
public function Set($sSectionKey, $sParamKey, $mParamValue)
{
if (isset($this->aData[$sSectionKey][$sParamKey][0]))
{
$sType = gettype($this->aData[$sSectionKey][$sParamKey][0]);
switch ($sType)
{
default:
case 'string':
$this->aData[$sSectionKey][$sParamKey][0] = (string) $mParamValue;
break;
case 'int':
case 'integer':
$this->aData[$sSectionKey][$sParamKey][0] = (int) $mParamValue;
break;
case 'bool':
case 'boolean':
$this->aData[$sSectionKey][$sParamKey][0] = (bool) $mParamValue;
break;
}
}
else if ('custom' === $sSectionKey)
{
$this->aData[$sSectionKey][$sParamKey] = array((string) $mParamValue);
}
}
/**
* @return bool
*/
public function Load()
{
if (\file_exists($this->sFile) && \is_readable($this->sFile))
{
$aData = @\parse_ini_file($this->sFile, true);
if (\is_array($aData) && 0 < count($aData))
{
foreach ($aData as $sSectionKey => $aSectionValue)
{
if (\is_array($aSectionValue))
{
foreach ($aSectionValue as $sParamKey => $mParamValue)
{
$this->Set($sSectionKey, $sParamKey, $mParamValue);
}
}
}
return true;
}
}
return false;
}
/**
* @return bool
*/
public function Save()
{
if (\file_exists($this->sFile) && !\is_writable($this->sFile))
{
return false;
}
$sNewLine = "\n";
$aResultLines = array();
foreach ($this->aData as $sSectionKey => $aSectionValue)
{
if (\is_array($aSectionValue))
{
$aResultLines[] = '';
$aResultLines[] = '['.$sSectionKey.']';
$bFirst = true;
foreach ($aSectionValue as $sParamKey => $mParamValue)
{
if (\is_array($mParamValue))
{
if (!empty($mParamValue[1]))
{
$sDesk = \str_replace("\r", '', $mParamValue[1]);
$aDesk = \explode("\n", $sDesk);
$aDesk = \array_map(function (&$sLine) {
return '; '.$sLine;
}, $aDesk);
if (!$bFirst)
{
$aResultLines[] = '';
}
$aResultLines[] = \implode($sNewLine, $aDesk);
}
$bFirst = false;
$sValue = '""';
switch (\gettype($mParamValue[0]))
{
default:
case 'string':
$sValue = '"'.$mParamValue[0].'"';
break;
case 'int':
case 'integer':
$sValue = $mParamValue[0];
break;
case 'bool':
case 'boolean':
$sValue = $mParamValue[0] ? 'On' : 'Off';
break;
}
$aResultLines[] = $sParamKey.' = '.$sValue;
}
}
}
}
return false !== \file_put_contents($this->sFile,
(0 < \strlen($this->sFilePrefix) ? $this->sFilePrefix : '').
$sNewLine.\implode($sNewLine, $aResultLines));
}
}

View file

@ -0,0 +1,225 @@
<?php
namespace RainLoop\Config;
class Application extends \RainLoop\Config\AbstractConfig
{
/**
* @return void
*/
public function __construct()
{
parent::__construct('application.ini',
'; RainLoop Webmail configuration file
; Please don\'t add custom parameters here, those will be overwritten');
}
/**
* @param string $sPassword
*
* @return void
*/
public function SetPassword($sPassword)
{
return $this->Set('security', 'admin_password', \md5(APP_SALT.$sPassword.APP_SALT));
}
/**
* @param string $sPassword
*
* @return bool
*/
public function ValidatePassword($sPassword)
{
$sPassword = (string) $sPassword;
$sConfigPassword = (string) $this->Get('security', 'admin_password', '');
return 0 < \strlen($sPassword) &&
($sPassword === $sConfigPassword || \md5(APP_SALT.$sPassword.APP_SALT) === $sConfigPassword);
}
/**
* @return bool
*/
public function Save()
{
$this->Set('version', 'current', APP_VERSION);
$this->Set('version', 'saved', \gmdate('r'));
return parent::Save();
}
/**
* @return array
*/
protected function defaultValues()
{
return array(
'webmail' => array(
'title' => array('RainLoop Webmail', 'Text displayed as page title'),
'loading_description' => array('RainLoop', 'Text displayed on startup'),
'theme' => array('Default', 'Theme used by default'),
'allow_themes' => array(true, 'Allow theme selection on settings screen'),
'allow_custom_theme' => array(true, ''),
'language' => array('en', 'Language used by default'),
'allow_languages_on_settings' => array(true, 'Allow language selection on settings screen'),
'allow_additional_accounts' => array(true, ''),
'allow_identities' => array(false, ''),
'use_preview_pane' => array(true, 'Whether message preview pane should be used'),
'messages_per_page' => array(20, ' Number of messages displayed on page by default'),
'editor_default_type' => array('Html', 'Editor mode used by default (Html or Plain)'),
'attachment_size_limit' => array(5,
'File size limit (MB) for file upload on compose screen
0 for unlimited.')
),
'security' => array(
'csrf_protection' => array(true,
'Enable CSRF protection (http://en.wikipedia.org/wiki/Cross-site_request_forgery)'),
'custom_server_signature' => array('RainLoop'),
'admin_login' => array('admin', 'Login and password for web admin panel'),
'admin_password' => array('12345')
),
'login' => array(
'allow_custom_login' => array(false,
'Enable additional Login field on webmail login screen'),
'default_domain' => array('', ''),
'allow_languages_on_login' => array(true,
'Allow language selection on webmail login screen'),
'sign_me_auto' => array(\RainLoop\Enumerations\SignMeType::DEFAILT_OFF,
'This option allows webmail to remember the logged in user
once they closed the browser window.
Values:
"DefaultOff" - can be used, disabled by default;
"DefaultOn" - can be used, enabled by default;
"Unused" - cannot be used')
),
'plugins' => array(
'enable' => array(false, 'Enable plugin support'),
'enabled_list' => array('', 'List of enabled plugins'),
),
'logs' => array(
'enable' => array(false, 'Enable logging'),
'write_on_error_only' => array(false, 'Logs entire request only if error occured'),
'filename' => array('log-{date:Y-m-d}.txt',
'Log filename.
For security reasons, some characters are removed from filename.
Allows for pattern-based folder creation (see examples below).
Patterns:
{date:Y-m-d} - Replaced by pattern-based date
Detailed info: http://www.php.net/manual/en/function.date.php
{user:email} - Replaced by user\'s email address
If user is not logged in, value is set to "unknown"
{user:login} - Replaced by user\'s login
If user is not logged in, value is set to "unknown"
{user:domain} - Replaced by user\'s domain name
If user is not logged in, value is set to "unknown"
{user:uid} - Replaced by user\'s UID regardless of account currently used
Examples:
filename = "log-{date:Y-m-d}.txt"
filename = "{date:Y-m-d}/{user:domain}/{user:email}_{user:uid}.log"
filename = "{user:email}-{date:Y-m-d}.txt"')
),
'debug' => array(
'enable' => array(false, 'Special option required for development purposes'),
),
'version' => array(
'current' => array(''),
'saved' => array('')
),
'social' => array(
'google_enable' => array(false, 'Google'),
'google_client_id' => array(''),
'google_client_secret' => array(''),
'fb_enable' => array(false, 'Facebook'),
'fb_app_id' => array(''),
'fb_app_secret' => array(''),
'twitter_enable' => array(false, 'Twitter'),
'twitter_consumer_key' => array(''),
'twitter_consumer_secret' => array(''),
'dropbox_enable' => array(false, 'Dropbox'),
'dropbox_api_key' => array(''),
),
'cache' => array(
'enable' => array(true,
'The section controls caching of the entire application.
Enables caching in the system'),
'index' => array('v1', 'Additional caching key. If changed, cache is purged'),
'fast_cache_driver' => array('files', 'Can be: files, APC, memcache'),
'fast_cache_index' => array('v1', 'Additional caching key. If changed, fast cache is purged'),
'http' => array(true, 'Browser-level cache. If enabled, caching is maintainted without using files'),
'server_uids' => array(false, 'Caching message UIDs when searching and sorting (threading)')
),
'labs' => array(
'ignore_folders_subscription' => array(false,
'Experimental settings. Handle with care.
'),
'allow_message_append' => array(false),
'date_from_headers' => array(false),
'cache_system_data' => array(true),
'use_app_debug_js' => array(false),
'use_app_debug_css' => array(false),
'login_fault_delay' => array(1),
'log_ajax_response_write_limit' => array(300),
'suggestions_limit' => array(50),
'determine_user_language' => array(true),
'use_imap_sort' => array(false),
'use_imap_list_status' => array(false),
'use_imap_list_subscribe' => array(true),
'use_imap_thread' => array(true),
'use_imap_move' => array(true),
'use_imap_auth_plain' => array(false),
'custom_repo' => array(''),
'additional_repo' => array(''),
'cdn_static_domain' => array(''),
'in_iframe' => array(false),
'custom_login_link' => array(''),
'custom_logout_link' => array(''),
'allow_contacts' => array(true),
'allow_external_login' => array(false),
'allow_admin_panel' => array(true),
'fast_cache_memcache_host' => array('127.0.0.1'),
'fast_cache_memcache_port' => array(11211),
'fast_cache_memcache_expire' => array(43200),
'usage_statistics' => array(true),
'dev_email' => array(''),
'dev_login' => array(''),
'dev_password' => array('')
)
);
}
}

View file

@ -0,0 +1,59 @@
<?php
namespace RainLoop\Config;
class Plugin extends \RainLoop\Config\AbstractConfig
{
/**
* @var array
*/
private $aMap;
/**
* @return void
*/
public function __construct($sPluginName, $aMap = array())
{
$this->aMap = is_array($aMap) ? $this->convertConfigMap($aMap) : array();
parent::__construct('plugin-'.$sPluginName.'.ini', '; RainLoop Webmail plugin ('.$sPluginName.')');
}
/**
* @param array $aMap
* @return array
*/
private function convertConfigMap($aMap)
{
if (0 < count($aMap))
{
$aResultMap = array();
foreach ($aMap as /* @var $oProperty \RainLoop\Plugins\Property */ $oProperty)
{
if ($oProperty)
{
$mValue = $oProperty->DefaultValue();
$sValue = is_array($mValue) && isset($mValue[0]) ? $mValue[0] : $mValue;
$aResultMap[$oProperty->Name()] = array($sValue, '');
}
}
if (0 < count($aResultMap))
{
return array(
'plugin' => $aResultMap
);
}
}
return array();
}
/**
* @return array
*/
protected function defaultValues()
{
return $this->aMap;
}
}

View file

@ -0,0 +1,434 @@
<?php
namespace RainLoop;
use MailSo\Net\Enumerations\ConnectionSecurityType;
class Domain
{
const DEFAULT_FORWARDED_FLAG = '$Forwarded';
/**
* @var string
*/
private $sName;
/**
* @var string
*/
private $sIncHost;
/**
* @var int
*/
private $iIncPort;
/**
* @var int
*/
private $iIncSecure;
/**
* @var bool
*/
private $bIncShortLogin;
/**
* @var string
*/
private $sOutHost;
/**
* @var int
*/
private $iOutPort;
/**
* @var int
*/
private $iOutSecure;
/**
* @var bool
*/
private $bOutShortLogin;
/**
* @var bool
*/
private $bOutAuth;
/**
* @var string
*/
private $sForwardFlag;
/**
* @var string
*/
private $sWhiteList;
/**
* @var bool
*/
private $bDisabled;
/**
* @param string $sName
* @param string $sIncHost
* @param int $iIncPort
* @param int $iIncSecure
* @param bool $bIncShortLogin
* @param string $sOutHost
* @param int $iOutPort
* @param int $iOutSecure
* @param bool $bOutShortLogin
* @param bool $bOutAuth
* @param string $sForwardFlag = \RainLoop\Domain::DEFAULT_FORWARDED_FLAG
* @param string $sWhiteList = ''
*/
private function __construct($sName, $sIncHost, $iIncPort, $iIncSecure, $bIncShortLogin,
$sOutHost, $iOutPort, $iOutSecure, $bOutShortLogin, $bOutAuth,
$sForwardFlag = \RainLoop\Domain::DEFAULT_FORWARDED_FLAG, $sWhiteList = '')
{
$this->sName = $sName;
$this->sIncHost = $sIncHost;
$this->iIncPort = $iIncPort;
$this->iIncSecure = $iIncSecure;
$this->bIncShortLogin = $bIncShortLogin;
$this->sOutHost = $sOutHost;
$this->iOutPort = $iOutPort;
$this->iOutSecure = $iOutSecure;
$this->bOutShortLogin = $bOutShortLogin;
$this->bOutAuth = $bOutAuth;
$this->sForwardFlag = $sForwardFlag;
$this->sWhiteList = \trim($sWhiteList);
$this->bDisabled = false;
}
/**
* @param string $sName
* @param string $sIncHost
* @param int $iIncPort
* @param int $iIncSecure
* @param bool $bIncShortLogin
* @param string $sOutHost
* @param int $iOutPort
* @param int $iOutSecure
* @param bool $bOutShortLogin
* @param bool $bOutAuth
* @param string $sForwardFlag = \RainLoop\Domain::DEFAULT_FORWARDED_FLAG
* @param string $sWhiteList = ''
*
* @return \RainLoop\Domain
*/
public static function NewInstance($sName,
$sIncHost, $iIncPort, $iIncSecure, $bIncShortLogin,
$sOutHost, $iOutPort, $iOutSecure, $bOutShortLogin, $bOutAuth,
$sForwardFlag = \RainLoop\Domain::DEFAULT_FORWARDED_FLAG, $sWhiteList = '')
{
return new self(
$sName,
$sIncHost, $iIncPort, $iIncSecure, $bIncShortLogin,
$sOutHost, $iOutPort, $iOutSecure, $bOutShortLogin, $bOutAuth,
$sForwardFlag, $sWhiteList);
}
/**
* @param array $aDomain
*
* @return \RainLoop\Domain | null
*/
public static function NewInstanceFromDomainConfigArray($sName, $aDomain)
{
$oDomain = null;
if (0 < strlen($sName) && is_array($aDomain) && !empty($aDomain['imap_host']) && !empty($aDomain['imap_port']) &&
!empty($aDomain['smpt_host']) && !empty($aDomain['smpt_port']))
{
$sIncHost = (string) $aDomain['imap_host'];
$iIncPort = (int) $aDomain['imap_port'];
$iIncSecure = self::StrConnectionSecurityTypeToCons(
!empty($aDomain['imap_secure']) ? $aDomain['imap_secure'] : '');
$sOutHost = (string) $aDomain['smpt_host'];
$iOutPort = (int) $aDomain['smpt_port'];
$iOutSecure = self::StrConnectionSecurityTypeToCons(
!empty($aDomain['smpt_secure']) ? $aDomain['smpt_secure'] : '');
$bOutAuth = isset($aDomain['smpt_auth']) ? (bool) $aDomain['smpt_auth'] : true;
$sForwardFlag = isset($aDomain['imap_custom_forward_flag']) ?
(string) $aDomain['imap_custom_forward_flag'] : '';
$sWhiteList = (string) (isset($aDomain['white_list']) ? $aDomain['white_list'] : '');
$bIncShortLogin = isset($aDomain['imap_short_login']) ? (bool) $aDomain['imap_short_login'] : false;
$bOutShortLogin = isset($aDomain['smtp_short_login']) ? (bool) $aDomain['smtp_short_login'] : false;
$oDomain = self::NewInstance($sName,
$sIncHost, $iIncPort, $iIncSecure, $bIncShortLogin,
$sOutHost, $iOutPort, $iOutSecure, $bOutShortLogin, $bOutAuth,
empty($sForwardFlag) ? \RainLoop\Domain::DEFAULT_FORWARDED_FLAG : $sForwardFlag, $sWhiteList);
}
return $oDomain;
}
/**
* @param string $sStr
*
* @return string
*/
private function encodeIniString($sStr)
{
return str_replace('"', '\\"', $sStr);
}
/**
* @param bool0 $bDisabled
*/
public function SetDisabled($bDisabled)
{
$this->bDisabled = (bool) $bDisabled;
}
/**
* @return string
*/
public function ToIniString()
{
return implode("\n", array(
'imap_host = "'.$this->encodeIniString($this->sIncHost).'"',
'imap_port = '.$this->iIncPort,
'imap_secure = "'.self::ConstConnectionSecurityTypeToStr($this->iIncSecure).'"',
'imap_short_login = '.($this->bIncShortLogin ? 'On' : 'Off'),
'smpt_host = "'.$this->encodeIniString($this->sOutHost).'"',
'smpt_port = '.$this->iOutPort,
'smpt_secure = "'.self::ConstConnectionSecurityTypeToStr($this->iOutSecure).'"',
'smtp_short_login = '.($this->bOutShortLogin ? 'On' : 'Off'),
'smpt_auth = '.($this->bOutAuth ? 'On' : 'Off'),
'white_list = "'.$this->encodeIniString($this->sWhiteList).'"'
));
}
/**
* @param string $sType
*
* @return int
*/
public static function StrConnectionSecurityTypeToCons($sType)
{
$iSecurityType = ConnectionSecurityType::NONE;
switch (strtoupper($sType))
{
case 'SSL':
$iSecurityType = ConnectionSecurityType::SSL;
break;
case 'TLS':
$iSecurityType = ConnectionSecurityType::STARTTLS;
break;
}
return $iSecurityType;
}
/**
* @param int $iSecurityType
*
* @return string
*/
public static function ConstConnectionSecurityTypeToStr($iSecurityType)
{
$sType = 'None';
switch ($iSecurityType)
{
case ConnectionSecurityType::SSL:
$sType = 'SSL';
break;
case ConnectionSecurityType::STARTTLS:
$sType = 'TLS';
break;
}
return $sType;
}
/**
* @param string $sIncHost
* @param int $iIncPort
* @param int $iIncSecure
* @param bool $bIncShortLogin
* @param string $sOutHost
* @param int $iOutPort
* @param int $iOutSecure
* @param bool $bOutShortLogin
* @param bool $bOutAuth
* @param string $sForwardFlag = \RainLoop\Domain::DEFAULT_FORWARDED_FLAG
* @param string $sWhiteList = ''
*
* @return \RainLoop\Domain
*/
public function UpdateInstance(
$sIncHost, $iIncPort, $iIncSecure, $bIncShortLogin,
$sOutHost, $iOutPort, $iOutSecure, $bOutShortLogin, $bOutAuth,
$sForwardFlag = \RainLoop\Domain::DEFAULT_FORWARDED_FLAG, $sWhiteList = '')
{
$this->sIncHost = $sIncHost;
$this->iIncPort = $iIncPort;
$this->iIncSecure = $iIncSecure;
$this->bIncShortLogin = $bIncShortLogin;
$this->sOutHost = $sOutHost;
$this->iOutPort = $iOutPort;
$this->iOutSecure = $iOutSecure;
$this->bOutShortLogin = $bOutShortLogin;
$this->bOutAuth = $bOutAuth;
$this->sForwardFlag = $sForwardFlag;
$this->sWhiteList = \trim($sWhiteList);
return $this;
}
/**
* @return string
*/
public function Name()
{
return $this->sName;
}
/**
* @return string
*/
public function IncHost()
{
return $this->sIncHost;
}
/**
* @return int
*/
public function IncPort()
{
return $this->iIncPort;
}
/**
* @return int
*/
public function IncSecure()
{
return $this->iIncSecure;
}
/**
* @return bool
*/
public function IncShortLogin()
{
return $this->bIncShortLogin;
}
/**
* @return string
*/
public function OutHost()
{
return $this->sOutHost;
}
/**
* @return int
*/
public function OutPort()
{
return $this->iOutPort;
}
/**
* @return int
*/
public function OutSecure()
{
return $this->iOutSecure;
}
/**
* @return bool
*/
public function OutShortLogin()
{
return $this->bOutShortLogin;
}
/**
* @return bool
*/
public function OutAuth()
{
return $this->bOutAuth;
}
/**
* @return string
*/
public function ForwardFlag()
{
return $this->sForwardFlag;
}
/**
* @return string
*/
public function WhiteList()
{
return $this->sWhiteList;
}
/**
* @return bool
*/
public function Disabled()
{
return $this->bDisabled;
}
/**
* @param string $sEmail
* @param string $sLogin = ''
*
* @return bool
*/
public function ValidateWhiteList($sEmail, $sLogin = '')
{
$sW = \trim($this->sWhiteList);
if (0 < strlen($sW))
{
$sW = \preg_replace('/([^\s]+)@[^\s]*/', '$1', $sW);
$sW = ' '.\strtolower(\trim(\preg_replace('/[\s;,\r\n\t]+/', ' ', $sW))).' ';
$sUserPart = \strtolower(\MailSo\Base\Utils::GetAccountNameFromEmail(0 < \strlen($sLogin) ? $sLogin : $sEmail));
return false !== \strpos($sW, ' '.$sUserPart.' ');
}
return true;
}
/**
* @return array
*/
public function ToSimpleJSON()
{
return array(
'Name' => $this->Name(),
'IncHost' => $this->IncHost(),
'IncPort' => $this->IncPort(),
'IncSecure' => $this->IncSecure(),
'IncShortLogin' => $this->IncShortLogin(),
'OutHost' => $this->OutHost(),
'OutPort' => $this->OutPort(),
'OutSecure' => $this->OutSecure(),
'OutShortLogin' => $this->OutShortLogin(),
'OutAuth' => $this->OutAuth(),
'WhiteList' => $this->WhiteList()
);
}
}

View file

@ -0,0 +1,9 @@
<?php
namespace RainLoop\Enumerations;
class CustomThemeType
{
const LIGHT = 'Light';
const DARK = 'Dark';
}

View file

@ -0,0 +1,10 @@
<?php
namespace RainLoop\Enumerations;
class InterfaceAnimation
{
const NONE = 'None';
const NORMAL = 'Normal';
const FULL = 'Full';
}

View file

@ -0,0 +1,13 @@
<?php
namespace RainLoop\Enumerations;
class PluginPropertyType
{
const STRING = 0;
const INT = 1;
const STRING_TEXT = 2;
const PASSWORD = 3;
const SELECTION = 4;
const BOOL = 5;
}

View file

@ -0,0 +1,10 @@
<?php
namespace RainLoop\Enumerations;
class SignMeType
{
const DEFAILT_OFF = 'DefaultOff';
const DEFAILT_ON = 'DefaultOn';
const UNUSED = 'Unused';
}

View file

@ -0,0 +1,9 @@
<?php
namespace RainLoop\Enumerations;
class TimeFormat
{
const F12 = '12';
const F24 = '24';
}

View file

@ -0,0 +1,16 @@
<?php
namespace RainLoop\Enumerations;
class UploadClientError
{
const NORMAL = 0;
const FILE_IS_TOO_BIG = 1;
const FILE_PARTIALLY_UPLOADED = 2;
const FILE_NO_UPLOADED = 3;
const MISSING_TEMP_FOLDER = 4;
const FILE_ON_SAVING_ERROR = 5;
const FILE_TYPE = 98;
const UNKNOWN = 99;
}

View file

@ -0,0 +1,13 @@
<?php
namespace RainLoop\Enumerations;
class UploadError
{
const UNKNOWN = 1000;
const CONFIG_SIZE = 1001;
const ON_SAVING = 1002;
const EMPTY_FILES_DATA = 1003;
const FILE_TYPE = 1004;
}

View file

@ -0,0 +1,9 @@
<?php
namespace RainLoop\Exceptions;
/**
* @category RainLoop
* @package Exceptions
*/
class AuthException extends Exception {}

View file

@ -0,0 +1,15 @@
<?php
namespace RainLoop\Exceptions;
/**
* @category RainLoop
* @package Exceptions
*/
class ClientException extends Exception
{
public function __construct($iCode, $oPrevious = null)
{
parent::__construct(\RainLoop\Notifications::GetNotificationsMessage($iCode), $iCode, $oPrevious);
}
}

View file

@ -0,0 +1,5 @@
<?php
namespace RainLoop\Exceptions;
class Exception extends \Exception {}

View file

@ -0,0 +1,9 @@
<?php
namespace RainLoop\Exceptions;
/**
* @category RainLoop
* @package Exceptions
*/
class InvalidArgumentException extends Exception {}

View file

@ -0,0 +1,9 @@
<?php
namespace RainLoop\Exceptions;
/**
* @category RainLoop
* @package Exceptions
*/
class RuntimeException extends Exception {}

View file

@ -0,0 +1,177 @@
<?php
namespace RainLoop;
class Identity
{
/**
* @var string
*/
private $sId;
/**
* @var string
*/
private $sEmail;
/**
* @var string
*/
private $sName;
/**
* @var string
*/
private $sReplyTo;
/**
* @var string
*/
private $sBcc;
/**
* @param string $sId
* @param string $sEmail
* @param string $sName
* @param string $sReplyTo
* @param string $sBcc
*
* @return void
*/
protected function __construct($sId, $sEmail, $sName, $sReplyTo, $sBcc)
{
$this->sId = $sId;
$this->sEmail = \strtolower($sEmail);
$this->sName = \trim($sName);
$this->sReplyTo = \trim($sReplyTo);
$this->sBcc = \trim($sBcc);
}
/**
* @param string $sId
* @param string $sEmail
* @param string $sName = ''
* @param string $sReplyTo = ''
* @param string $sBcc = ''
*
* @return \RainLoop\Identity
*/
public static function NewInstance($sId, $sEmail, $sName = '', $sReplyTo = '', $sBcc = '')
{
return new self($sId, $sEmail, $sName, $sReplyTo, $sBcc);
}
/**
* @return string
*/
public function Id()
{
return $this->sId;
}
/**
* @param string $sId
*
* @return \RainLoop\Identity
*/
public function SetId($sId)
{
$this->sId = $sId;
return $this;
}
/**
* @return string
*/
public function Email()
{
return $this->sEmail;
}
/**
* @param string $sEmail
*
* @return \RainLoop\Identity
*/
public function SetEmail($sEmail)
{
$this->sEmail = $sEmail;
return $this;
}
/**
* @return string
*/
public function Name()
{
return $this->sName;
}
/**
* @param string $sName
*
* @return \RainLoop\Identity
*/
public function SetName($sName)
{
$this->sName = $sName;
return $this;
}
/**
* @return string
*/
public function ReplyTo()
{
return $this->sReplyTo;
}
/**
* @param string $sReplyTo
*
* @return \RainLoop\Identity
*/
public function SetReplyTo($sReplyTo)
{
$this->sReplyTo = $sReplyTo;
return $this;
}
/**
* @return string
*/
public function Bcc()
{
return $this->sBcc;
}
/**
* @param string $sBcc
*
* @return \RainLoop\Identity
*/
public function SetBcc($sBcc)
{
$this->sBcc = $sBcc;
return $this;
}
/**
* @return array
*/
public function ToSimpleJSON()
{
return array(
'Id' => $this->Id(),
'Email' => $this->Email(),
'Name' => $this->Name(),
'ReplyTo' => $this->ReplyTo(),
'Bcc' => $this->Bcc()
);
}
}

View file

@ -0,0 +1,101 @@
<?php
namespace RainLoop;
class Notifications
{
const InvalidToken = 101;
const AuthError = 102;
const AccessError = 103;
const ConnectionError = 104;
const CaptchaError = 105;
const SocialFacebookLoginAccessDisable = 106;
const SocialTwitterLoginAccessDisable = 107;
const SocialGoogleLoginAccessDisable = 108;
const DomainNotAllowed = 109;
const AccountNotAllowed = 110;
const CantGetMessageList = 201;
const CantGetMessage = 202;
const CantDeleteMessage = 203;
const CantMoveMessage = 204;
const CantSaveMessage = 301;
const CantSendMessage = 302;
const InvalidRecipients = 303;
const CantCreateFolder = 400;
const CantRenameFolder = 401;
const CantDeleteFolder = 402;
const CantSubscribeFolder = 403;
const CantUnsubscribeFolder = 404;
const CantDeleteNonEmptyFolder = 405;
const CantSaveSettings = 501;
const CantSavePluginSettings = 502;
const DomainAlreadyExists = 601;
const CantInstallPackage = 701;
const CantDeletePackage = 702;
const InvalidPluginPackage = 703;
const UnsupportedPluginPackage = 704;
const LicensingServerIsUnavailable = 710;
const LicensingExpired = 711;
const LicensingBanned = 712;
const DemoSendMessageError = 750;
const AccountAlreadyExists = 801;
const MailServerError = 901;
const UnknownNotification = 998;
const UnknownError = 999;
static public function GetNotificationsMessage($iCode)
{
static $aMap = array(
self::InvalidToken => 'InvalidToken',
self::AuthError => 'AuthError',
self::AccessError => 'AccessError',
self::ConnectionError => 'ConnectionError',
self::CaptchaError => 'CaptchaError',
self::SocialFacebookLoginAccessDisable => 'SocialFacebookLoginAccessDisable',
self::SocialTwitterLoginAccessDisable => 'SocialTwitterLoginAccessDisable',
self::SocialGoogleLoginAccessDisable => 'SocialGoogleLoginAccessDisable',
self::DomainNotAllowed => 'DomainNotAllowed',
self::AccountNotAllowed => 'AccountNotAllowed',
self::CantGetMessageList => 'CantGetMessageList',
self::CantGetMessage => 'CantGetMessage',
self::CantDeleteMessage => 'CantDeleteMessage',
self::CantMoveMessage => 'CantMoveMessage',
self::CantSaveMessage => 'CantSaveMessage',
self::CantSendMessage => 'CantSendMessage',
self::InvalidRecipients => 'InvalidRecipients',
self::CantCreateFolder => 'CantCreateFolder',
self::CantRenameFolder => 'CantRenameFolder',
self::CantDeleteFolder => 'CantDeleteFolder',
self::CantSubscribeFolder => 'CantSubscribeFolder',
self::CantUnsubscribeFolder => 'CantUnsubscribeFolder',
self::CantDeleteNonEmptyFolder => 'CantDeleteNonEmptyFolder',
self::CantSaveSettings => 'CantSaveSettings',
self::CantSavePluginSettings => 'CantSavePluginSettings',
self::DomainAlreadyExists => 'DomainAlreadyExists',
self::CantInstallPackage => 'CantInstallPackage',
self::CantDeletePackage => 'CantDeletePackage',
self::InvalidPluginPackage => 'InvalidPluginPackage',
self::UnsupportedPluginPackage => 'UnsupportedPluginPackage',
self::LicensingServerIsUnavailable => 'LicensingServerIsUnavailable',
self::LicensingExpired => 'LicensingExpired',
self::LicensingBanned => 'LicensingBanned',
self::DemoSendMessageError => 'DemoSendMessageError',
self::AccountAlreadyExists => 'AccountAlreadyExists',
self::MailServerError => 'MailServerError',
self::UnknownNotification => 'UnknownNotification',
self::UnknownError => 'UnknownError'
);
return isset($aMap[$iCode]) ? $aMap[$iCode].'['.$iCode.']' : 'UnknownNotification['.$iCode.']';
}
}

View file

@ -0,0 +1,338 @@
<?php
namespace RainLoop\Plugins;
abstract class AbstractPlugin
{
/**
* @var \RainLoop\Plugins\Manager
*/
private $oPluginManager;
/**
* @var \RainLoop\Config\Plugin
*/
private $oPluginConfig;
/**
* @var bool
*/
private $bLangs;
/**
* @var string
*/
private $sName;
/**
* @var string
*/
private $sPath;
/**
* @var string
*/
private $sVersion;
/**
* @var array
*/
private $aConfigMap;
/**
* @var bool
*/
private $bPluginConfigLoaded;
public function __construct()
{
$this->sName = '';
$this->sPath = '';
$this->sVersion = '0.0';
$this->aConfigMap = null;
$this->oPluginManager = null;
$this->oPluginConfig = null;
$this->bPluginConfigLoaded = false;
$this->bLangs = false;
}
/**
* @return \RainLoop\Config\Plugin
*/
public function Config()
{
if (!$this->bPluginConfigLoaded && $this->oPluginConfig)
{
$this->bPluginConfigLoaded = true;
if ($this->oPluginConfig->IsInited())
{
if (!$this->oPluginConfig->Load())
{
$this->oPluginConfig->Save();
}
}
}
return $this->oPluginConfig;
}
/**
* @return \RainLoop\Plugins\Manager
*/
public function Manager()
{
return $this->oPluginManager;
}
/**
* @return string
*/
public function Path()
{
return $this->sPath;
}
/**
* @return string
*/
public function Name()
{
return $this->sName;
}
/**
* @return string
*/
public function Version()
{
return $this->sVersion;
}
/**
* @param bool | null $bLangs = null
* @return bool
*/
public function UseLangs($bLangs = null)
{
if (null !== $bLangs)
{
$this->bLangs = (bool) $bLangs;
}
return $this->bLangs;
}
/**
* @return array
*/
protected function configMapping()
{
return array();
}
/**
* @return string
*/
public function Hash()
{
return \md5($this->sVersion);
}
/**
* @return string
*/
public function Supported()
{
return '';
}
/**
* @final
* @return array
*/
final public function ConfigMap()
{
if (null === $this->aConfigMap)
{
$this->aConfigMap = $this->configMapping();
if (!is_array($this->aConfigMap))
{
$this->aConfigMap = array();
}
}
return $this->aConfigMap;
}
/**
* @param string $sPath
* @param string $sName
* @param string $sVersion = ''
*
* @return self
*/
public function SetValues($sPath, $sName, $sVersion = '')
{
$this->sName = $sName;
$this->sPath = $sPath;
if (0 < \strlen($sVersion))
{
$this->sVersion = $sVersion;
}
return $this;
}
/**
* @param \RainLoop\Plugins\Manager $oPluginManager
*
* @return self
*/
public function SetPluginManager(\RainLoop\Plugins\Manager $oPluginManager)
{
$this->oPluginManager = $oPluginManager;
return $this;
}
/**
* @param \RainLoop\Config\Plugin $oPluginConfig
*
* @return self
*/
public function SetPluginConfig(\RainLoop\Config\Plugin $oPluginConfig)
{
$this->oPluginConfig = $oPluginConfig;
return $this;
}
/**
* @return void
*/
public function PreInit()
{
}
/**
* @return void
*/
public function Init()
{
}
/**
* @param bool $bAdmin
* @param bool $bAuth
* @param array $aConfig
*
* @return void
*/
public function FilterAppDataPluginSection($bAdmin, $bAuth, &$aConfig)
{
}
/**
* @param string $sHookName
* @param string $sFunctionName
*
* @return self
*/
protected function addHook($sHookName, $sFunctionName)
{
if ($this->oPluginManager)
{
$this->oPluginManager->AddHook($sHookName, array(&$this, $sFunctionName));
}
return $this;
}
/**
* @param string $sFile
* @param bool $bAdminScope = false
*
* @return self
*/
protected function addJs($sFile, $bAdminScope = false)
{
if ($this->oPluginManager)
{
$this->oPluginManager->AddJs($this->sPath.'/'.$sFile, $bAdminScope);
}
return $this;
}
/**
* @param string $sFile
* @param bool $bAdminScope = false
*
* @return self
*/
protected function addTemplate($sFile, $bAdminScope = false)
{
if ($this->oPluginManager)
{
$this->oPluginManager->AddTemplate($this->sPath.'/'.$sFile, $bAdminScope);
}
return $this;
}
/**
* @param string $sActionName
* @param string $sFunctionName
*
* @return self
*/
protected function addPartHook($sActionName, $sFunctionName)
{
if ($this->oPluginManager)
{
$this->oPluginManager->AddAdditionalPartAction($sActionName, array(&$this, $sFunctionName));
}
return $this;
}
/**
* @param string $sActionName
* @param string $sFunctionName
*
* @return self
*/
protected function addAjaxHook($sActionName, $sFunctionName)
{
if ($this->oPluginManager)
{
$this->oPluginManager->AddAdditionalAjaxAction($sActionName, array(&$this, $sFunctionName));
}
return $this;
}
/**
* @param string $sName
* @param string $sPlace
* @param string $sHtml
* @param bool $bPrepend = false
*
* @return self
*/
protected function addTemplateHook($sName, $sPlace, $sLocalTemplateName, $bPrepend = false)
{
if ($this->oPluginManager)
{
$this->oPluginManager->AddProcessTemplateAction($sName, $sPlace,
'<!-- ko template: \''.$sLocalTemplateName.'\' --><!-- /ko -->', $bPrepend);
}
return $this;
}
}

View file

@ -0,0 +1,669 @@
<?php
namespace RainLoop\Plugins;
class Manager
{
/**
* @var \RainLoop\Actions
*/
private $oActions;
/**
* @var array
*/
private $aHooks;
/**
* @var array
*/
private $aJs;
/**
* @var array
*/
private $aAdminJs;
/**
* @var array
*/
private $aTemplates;
/**
* @var array
*/
private $aAdminTemplates;
/**
* @var array
*/
private $aProcessTemplate;
/**
* @var array
*/
private $aAdditionalParts;
/**
* @var array
*/
private $aAdditionalAjax;
/**
* @var array
*/
private $aPlugins;
/**
* @var bool
*/
private $bIsEnabled;
/**
* @var \MailSo\Log\Logger
*/
private $oLogger;
/**
* @param \RainLoop\Actions $oActions
*/
public function __construct(\RainLoop\Actions $oActions)
{
$this->oLogger = null;
$this->oActions = $oActions;
$this->aPlugins = array();
$this->aHooks = array();
$this->aJs = array();
$this->aAdminJs = array();
$this->aTemplates = array();
$this->aAdminTemplates = array();
$this->aAjaxFilters = array();
$this->aAdditionalAjax = array();
$this->aProcessTemplate = array();
$this->bIsEnabled = (bool) $this->oActions->Config()->Get('plugins', 'enable', false);
if ($this->bIsEnabled)
{
$sList = \strtolower($this->oActions->Config()->Get('plugins', 'enabled_list', ''));
if (0 < \strlen($sList))
{
$aList = \explode(',', $sList);
$aList = \array_map('trim', $aList);
foreach ($aList as $sName)
{
if (0 < \strlen($sName))
{
$oPlugin = $this->CreatePluginByName($sName);
if ($oPlugin)
{
$oPlugin->PreInit();
$oPlugin->Init();
$this->aPlugins[] = $oPlugin;
}
}
}
}
}
}
/**
* @param string $sName
*
* @return \RainLoop\Plugins\AbstractPlugin | null
*/
public function CreatePluginByName($sName)
{
$oPlugin = null;
if (\preg_match('/^[a-z0-9\-]+$/', $sName) &&
\file_exists(APP_PLUGINS_PATH.$sName.'/index.php'))
{
$sClassName = $this->convertPluginFolderNameToClassName($sName);
if (!\class_exists($sClassName))
{
include APP_PLUGINS_PATH.$sName.'/index.php';
}
if (\class_exists($sClassName))
{
$oPlugin = new $sClassName();
if ($oPlugin instanceof \RainLoop\Plugins\AbstractPlugin)
{
$oPlugin
->SetValues(APP_PLUGINS_PATH.$sName, $sName,
\file_exists(APP_PLUGINS_PATH.$sName.'/VERSION') ?
\file_get_contents(APP_PLUGINS_PATH.$sName.'/VERSION') : '')
->SetPluginManager($this)
->SetPluginConfig(new \RainLoop\Config\Plugin($sName, $oPlugin->ConfigMap()))
;
}
else
{
$oPlugin = null;
}
}
}
return $oPlugin;
}
/**
* @return array
*/
public function InstalledPlugins()
{
$aList = array();
$aGlob = @\glob(APP_PLUGINS_PATH.'*', GLOB_ONLYDIR|GLOB_NOSORT);
if (\is_array($aGlob))
{
foreach ($aGlob as $sPathName)
{
$sName = \basename($sPathName);
if (\preg_match('/^[a-z0-9\-]+$/', $sName) &&
\file_exists($sPathName.'/index.php'))
{
$sVersion = @\file_get_contents($sPathName.'/VERSION');
$aList[] = array(
$sName, $sVersion
);
}
}
}
else
{
$this->Actions()->Logger()->Write('Cannot get installed plugins from '.APP_PLUGINS_PATH,
\MailSo\Log\Enumerations\Type::ERROR);
}
return $aList;
}
/**
* @param string $sFolderName
*
* @return string
*/
private function convertPluginFolderNameToClassName($sFolderName)
{
$aParts = array_map('ucfirst', array_map('strtolower',
explode(' ', preg_replace('/[^a-z0-9]+/', ' ', $sFolderName))));
return implode($aParts).'Plugin';
}
/**
* @return \RainLoop\Actions
*/
public function Actions()
{
return $this->oActions;
}
/**
* @return \RainLoop\Actions
*/
public function Hash()
{
$sResult = \md5(APP_VERSION);
foreach ($this->aPlugins as $oPlugin)
{
$sResult = \md5($sResult.$oPlugin->Path().$oPlugin->Hash());
}
return $sResult;
}
/**
* @param bool $bAdminScope = false
*
* @return string
*/
public function CompileJs($bAdminScope = false)
{
$aResult = array();
if ($this->bIsEnabled)
{
$aJs = $bAdminScope ? $this->aAdminJs : $this->aJs;
foreach ($aJs as $sFile)
{
if (file_exists($sFile))
{
$aResult[] = file_get_contents($sFile);
}
}
}
return implode("\n", $aResult);
}
/**
* @todo
* @param bool $bAdminScope = false
*
* @return string
*/
public function CompileCss($bAdminScope = false)
{
return '';
}
/**
* @param bool $bAdminScope = false
* @return string
*/
public function CompileTemplate($bAdminScope = false)
{
$sResult = '';
if ($this->bIsEnabled)
{
$aTemplates = $bAdminScope ? $this->aAdminTemplates : $this->aTemplates;
foreach ($aTemplates as $sFile)
{
if (file_exists($sFile))
{
$sTemplateName = substr(basename($sFile), 0, -5);
$sResult .= '<script id="'.preg_replace('/[^a-zA-Z0-9]/', '', $sTemplateName).'" type="text/html">'.
$this->Actions()->ProcessTemplate($sTemplateName, file_get_contents($sFile)).'</script>';
}
}
}
return $sResult;
}
/**
* @param bool $bAdmin
* @param array $aAppData
*
* @return \RainLoop\Plugins\Manager
*/
public function InitAppData($bAdmin, &$aAppData)
{
if ($this->bIsEnabled && isset($aAppData['Plugins']) && is_array($aAppData['Plugins']))
{
$bAuth = isset($aAppData['Auth']) && !!$aAppData['Auth'];
foreach ($this->aPlugins as $oPlugin)
{
if ($oPlugin)
{
$aConfig = array();
$aMap = $oPlugin->ConfigMap();
if (\is_array($aMap))
{
foreach ($aMap as /* @var $oPluginProperty \RainLoop\Plugins\Property */$oPluginProperty)
{
if ($oPluginProperty && $oPluginProperty->AllowedInJs())
{
$aConfig[$oPluginProperty->Name()] =
$oPlugin->Config()->Get('plugin',
$oPluginProperty->Name(),
$oPluginProperty->DefaultValue());
}
}
}
$oPlugin->FilterAppDataPluginSection($bAdmin, $bAuth, $aConfig);
if (0 < \count($aConfig))
{
$aAppData['Plugins'][$oPlugin->Name()] = $aConfig;
}
}
}
$this->RunHook('filter.app-data', array($bAdmin, &$aAppData));
}
return $this;
}
/**
* @param string $sHookName
* @param mixed $mCallbak
*
* @return \RainLoop\Plugins\Manager
*/
public function AddHook($sHookName, $mCallbak)
{
if ($this->bIsEnabled && is_callable($mCallbak))
{
if (!isset($this->aHooks[$sHookName]))
{
$this->aHooks[$sHookName] = array();
}
$this->aHooks[$sHookName][] = $mCallbak;
}
return $this;
}
/**
* @param string $sHookName
* @param bool $bAdminScope = false
*
* @return \RainLoop\Plugins\Manager
*/
public function AddJs($sFile, $bAdminScope = false)
{
if ($this->bIsEnabled)
{
if ($bAdminScope)
{
$this->aAdminJs[$sFile] = $sFile;
}
else
{
$this->aJs[$sFile] = $sFile;
}
}
return $this;
}
/**
* @param string $sHookName
* @param bool $bAdminScope = false
*
* @return \RainLoop\Plugins\Manager
*/
public function AddTemplate($sFile, $bAdminScope = false)
{
if ($this->bIsEnabled)
{
if ($bAdminScope)
{
$this->aAdminTemplates[$sFile] = $sFile;
}
else
{
$this->aTemplates[$sFile] = $sFile;
}
}
return $this;
}
/**
* @param string $sHookName
* @param array $aArg = array()
* @param bool $bLogHook = true
*
* @return \RainLoop\Plugins\Manager
*/
public function RunHook($sHookName, $aArg = array(), $bLogHook = true)
{
if ($this->bIsEnabled)
{
if (isset($this->aHooks[$sHookName]))
{
if ($bLogHook)
{
$this->WriteLog('Hook: '.$sHookName, \MailSo\Log\Enumerations\Type::NOTE);
}
foreach ($this->aHooks[$sHookName] as $mCallbak)
{
call_user_func_array($mCallbak, $aArg);
}
}
}
return $this;
}
/**
* @param string $sActionName
* @param mixed $mCallbak
*
* @return \RainLoop\Plugins\Manager
*/
public function AddAdditionalPartAction($sActionName, $mCallbak)
{
if ($this->bIsEnabled && is_callable($mCallbak))
{
$sActionName = strtolower($sActionName);
if (!isset($this->aAdditionalParts[$sActionName]))
{
$this->aAdditionalParts[$sActionName] = array();
}
$this->aAdditionalParts[$sActionName][] = $mCallbak;
}
return $this;
}
/**
* @param string $sActionName
* @param array $aParts = array()
*
* @return \RainLoop\Plugins\Manager
*/
public function RunAdditionalPart($sActionName, $aParts = array())
{
$bResult = false;
if ($this->bIsEnabled)
{
$sActionName = strtolower($sActionName);
if (isset($this->aAdditionalParts[$sActionName]))
{
foreach ($this->aAdditionalParts[$sActionName] as $mCallbak)
{
$bCallResult = call_user_func_array($mCallbak, $aParts);
if ($bCallResult && !$bResult)
{
$bResult = true;
}
}
}
}
return $bResult;
}
/**
* @param string $sName
* @param string $sPlace
* @param string $sHtml
* @param bool $bPrepend = false
*
* @return \RainLoop\Plugins\Manager
*/
public function AddProcessTemplateAction($sName, $sPlace, $sHtml, $bPrepend = false)
{
if ($this->bIsEnabled)
{
if (!isset($this->aProcessTemplate[$sName]))
{
$this->aProcessTemplate[$sName] = array();
}
if (!isset($this->aProcessTemplate[$sName][$sPlace]))
{
$this->aProcessTemplate[$sName][$sPlace] = array();
}
if ($bPrepend)
{
array_unshift($this->aProcessTemplate[$sName][$sPlace], $sHtml);
}
else
{
array_push($this->aProcessTemplate[$sName][$sPlace], $sHtml);
}
}
return $this;
}
/**
* @param string $sActionName
* @param mixed $mCallbak
*
* @return \RainLoop\Plugins\Manager
*/
public function AddAdditionalAjaxAction($sActionName, $mCallbak)
{
if ($this->bIsEnabled && is_callable($mCallbak) && 0 < strlen($sActionName))
{
$sActionName = 'Do'.$sActionName;
if (!isset($this->aAdditionalAjax[$sActionName]))
{
$this->aAdditionalAjax[$sActionName] = $mCallbak;
}
}
return $this;
}
/**
* @param string $sActionName
*
* @return bool
*/
public function HasAdditionalAjax($sActionName)
{
return $this->bIsEnabled && isset($this->aAdditionalAjax[$sActionName]);
}
/**
* @param string $sActionName
*
* @return mixed
*/
public function RunAdditionalAjax($sActionName)
{
if ($this->bIsEnabled)
{
if (isset($this->aAdditionalAjax[$sActionName]))
{
return call_user_func($this->aAdditionalAjax[$sActionName]);
}
}
return false;
}
/**
* @param string $sLang
* @param array $sActionName
*
* @return \RainLoop\Plugins\Manager
*/
public function ReadLang($sLang, &$aLang)
{
if ($this->bIsEnabled)
{
foreach ($this->aPlugins as $oPlugin)
{
if ($oPlugin->UseLangs())
{
$sPath = $oPlugin->Path();
\RainLoop\Utils::ReadAndAddLang($sPath.'/langs/en.ini', $aLang);
if ('en' !== $sLang)
{
\RainLoop\Utils::ReadAndAddLang($sPath.'/langs/'.$sLang.'.ini', $aLang);
}
}
}
}
return $this;
}
/**
* @param string $sName
* @param string $sHtml
*
* @return string
*/
public function ProcessTemplate($sName, $sHtml)
{
if (isset($this->aProcessTemplate[$sName]))
{
foreach ($this->aProcessTemplate[$sName] as $sPlace => $aAddHtml)
{
if (is_array($aAddHtml) && 0 < count($aAddHtml))
{
foreach ($aAddHtml as $sAddHtml)
{
$sHtml = str_replace('{{INCLUDE/'.$sPlace.'/PLACE}}', $sAddHtml.'{{INCLUDE/'.$sPlace.'/PLACE}}', $sHtml);
}
}
}
}
return $sHtml;
}
/**
* @return bool
*/
public function bIsEnabled()
{
return $this->bIsEnabled;
}
/**
* @return int
*/
public function Count()
{
return $this->bIsEnabled ? \count($this->aPlugins) : 0;
}
/**
* @param \MailSo\Log\Logger $oLogger
*
* @return \RainLoop\Plugins\Manager
*
* @throws \MailSo\Base\Exceptions\InvalidArgumentException
*/
public function SetLogger($oLogger)
{
if (!($oLogger instanceof \MailSo\Log\Logger))
{
throw new \MailSo\Base\Exceptions\InvalidArgumentException();
}
$this->oLogger = $oLogger;
return $this;
}
/**
* @param string $sDesc
* @param int $iDescType = \MailSo\Log\Enumerations\Type::INFO
*
* @return void
*/
public function WriteLog($sDesc, $iDescType = \MailSo\Log\Enumerations\Type::INFO)
{
if ($this->oLogger)
{
$this->oLogger->Write($sDesc, $iDescType, 'PLUGIN');
}
}
/**
* @param string $sDesc
* @param int $iDescType = \MailSo\Log\Enumerations\Type::INFO
*
* @return void
*/
public function WriteException($sDesc, $iDescType = \MailSo\Log\Enumerations\Type::INFO)
{
if ($this->oLogger)
{
$this->oLogger->WriteException($sDesc, $iDescType, 'PLUGIN');
}
}
}

View file

@ -0,0 +1,178 @@
<?php
namespace RainLoop\Plugins;
class Property
{
/**
* @var string
*/
private $sName;
/**
* @var string
*/
private $sLabel;
/**
* @var string
*/
private $sDesc;
/**
* @var int
*/
private $iType;
/**
* @var bool
*/
private $bAllowedInJs;
/**
* @var mixed
*/
private $mDefaultValue;
private function __construct($sName)
{
$this->sName = $sName;
$this->iType = \RainLoop\Enumerations\PluginPropertyType::STRING;
$this->mDefaultValue = '';
$this->sLabel = '';
$this->sDesc = '';
$this->bAllowedInJs = false;
}
/**
* @param string $sName
*
* @return \RainLoop\Plugins\Property
*/
public static function NewInstance($sName)
{
return new self($sName);
}
/**
* @param int $iType
*
* @return \RainLoop\Plugins\Property
*/
public function SetType($iType)
{
$this->iType = (int) $iType;
return $this;
}
/**
* @param mixed $mDefaultValue
*
* @return \RainLoop\Plugins\Property
*/
public function SetDefaultValue($mDefaultValue)
{
$this->mDefaultValue = $mDefaultValue;
return $this;
}
/**
* @param string $sLabel
*
* @return \RainLoop\Plugins\Property
*/
public function SetLabel($sLabel)
{
$this->sLabel = $sLabel;
return $this;
}
/**
* @param string $sDesc
*
* @return \RainLoop\Plugins\Property
*/
public function SetDescription($sDesc)
{
$this->sDesc = $sDesc;
return $this;
}
/**
* @param bool $bValue = true
* @return \RainLoop\Plugins\Property
*/
public function SetAllowedInJs($bValue = true)
{
$this->bAllowedInJs = !!$bValue;
return $this;
}
/**
* @return string
*/
public function Name()
{
return $this->sName;
}
/**
* @return bool
*/
public function AllowedInJs()
{
return $this->bAllowedInJs;
}
/**
* @return string
*/
public function Description()
{
return $this->sDesc;
}
/**
* @return string
*/
public function Label()
{
return $this->sLabel;
}
/**
* @return int
*/
public function Type()
{
return $this->iType;
}
/**
* @return mixed
*/
public function DefaultValue()
{
return $this->mDefaultValue;
}
/**
* @return array
*/
public function ToArray()
{
return array(
'',
$this->sName,
$this->iType,
$this->sLabel,
$this->mDefaultValue,
$this->sDesc
);
}
}

View file

@ -0,0 +1,14 @@
<?php
namespace RainLoop\Providers;
abstract class AbstractProvider
{
/**
* @return bool
*/
public function IsActive()
{
return false;
}
}

View file

@ -0,0 +1,73 @@
<?php
namespace RainLoop\Providers;
class ChangePassword extends \RainLoop\Providers\AbstractProvider
{
/**
* @var \RainLoop\Actions
*/
private $oActions;
/**
* @var \RainLoop\Providers\ChangePassword\ChangePasswordInterface
*/
private $oDriver;
/**
* @param \RainLoop\Actions $oActions
* @param \RainLoop\Providers\ChangePassword\ChangePasswordInterface|null $oDriver = null
*
* @return void
*/
public function __construct($oActions, $oDriver = null)
{
$this->oActions = $oActions;
$this->oDriver = $oDriver;
}
/**
* @param \RainLoop\Account $oAccount
*
* @return bool
*/
public function PasswordChangePossibility($oAccount)
{
return $this->IsActive() &&
$oAccount instanceof \RainLoop\Account &&
$this->oDriver && $this->oDriver->PasswordChangePossibility($oAccount)
;
}
/**
* @param \RainLoop\Account $oAccount
* @param string $sPrevPassword
* @param string $sNewPassword
*
* @return bool
*/
public function ChangePassword(\RainLoop\Account $oAccount, $sPrevPassword, $sNewPassword)
{
$bResult = false;
if ($this->oDriver instanceof \RainLoop\Providers\ChangePassword\ChangePasswordInterface &&
$this->PasswordChangePossibility($oAccount) && $sPrevPassword === $oAccount->Password())
{
if ($this->oDriver->ChangePassword($oAccount, $sPrevPassword, $sNewPassword))
{
$oAccount->SetPassword($sNewPassword);
$this->oActions->SetAuthToken($oAccount);
$bResult = true;
}
}
return $bResult;
}
/**
* @return bool
*/
public function IsActive()
{
return $this->oDriver instanceof \RainLoop\Providers\ChangePassword\ChangePasswordInterface;
}
}

View file

@ -0,0 +1,22 @@
<?php
namespace RainLoop\Providers\ChangePassword;
interface ChangePasswordInterface
{
/**
* @param \RainLoop\Account $oAccount
*
* @return bool
*/
public function PasswordChangePossibility($oAccount);
/**
* @param \RainLoop\Account $oAccount
* @param string $sPrevPassword
* @param string $sNewPassword
*
* @return bool
*/
public function ChangePassword(\RainLoop\Account $oAccount, $sPrevPassword, $sNewPassword);
}

View file

@ -0,0 +1,120 @@
<?php
namespace RainLoop\Providers;
class Contacts extends \RainLoop\Providers\AbstractProvider
{
/**
* @var \RainLoop\Providers\Contacts\ContactsInterface
*/
private $oDriver;
/**
* @param \RainLoop\Providers\Contacts\ContactsInterface $oDriver
*
* @return void
*/
public function __construct($oDriver)
{
$this->oDriver = null;
if ($oDriver instanceof \RainLoop\Providers\Contacts\ContactsInterface)
{
$this->oDriver = $oDriver;
}
}
/**
* @return bool
*/
public function IsActive()
{
return $this->oDriver instanceof \RainLoop\Providers\Contacts\ContactsInterface;
}
/**
* @return bool
*/
public function IsSupported()
{
return $this->oDriver instanceof \RainLoop\Providers\Contacts\ContactsInterface &&
$this->oDriver->IsSupported();
}
/**
* @param \RainLoop\Account $oAccount
* @param int $iIdContact
*
* @return array
*/
public function GetContactById($oAccount, $iIdContact)
{
return $this->oDriver ? $this->oDriver->GetContactById($oAccount, $iIdContact) : null;
}
/**
* @param \RainLoop\Account $oAccount
* @param int $iOffset = 0
* @param int $iLimit = 20
* @param string $sSearch = ''
*
* @return array
*/
public function GetContacts($oAccount, $iOffset = 0, $iLimit = 20, $sSearch = '')
{
return $this->oDriver ? $this->oDriver->GetContacts($oAccount, $iOffset, $iLimit, $sSearch) : array();
}
/**
* @param \RainLoop\Account $oAccount
*
* @return array
*/
public function GetContactsImageHashes($oAccount)
{
return $this->oDriver ? $this->oDriver->GetContactsImageHashes($oAccount) : array();
}
/**
* @param \RainLoop\Account $oAccount
* @param \RainLoop\Providers\Contacts\Classes\Contact $oContact
*
* @return bool
*/
public function CreateContact($oAccount, &$oContact)
{
return $this->oDriver ? $this->oDriver->CreateContact($oAccount, $oContact) : false;
}
/**
* @param \RainLoop\Account $oAccount
* @param \RainLoop\Providers\Contacts\Classes\Contact $oContact
*
* @return bool
*/
public function UpdateContact($oAccount, &$oContact)
{
return $this->oDriver ? $this->oDriver->UpdateContact($oAccount, $oContact) : false;
}
/**
* @param \RainLoop\Account $oAccount
* @param array $aContactIds
*
* @return bool
*/
public function DeleteContacts($oAccount, $aContactIds)
{
return $this->oDriver ? $this->oDriver->DeleteContacts($oAccount, $aContactIds) : false;
}
/**
* @param \RainLoop\Account $oAccount
* @param array $aContactIds
*
* @return bool
*/
public function IncFrec($oAccount, $aContactIds)
{
return $this->oDriver ? $this->oDriver->IncFrec($oAccount, $aContactIds) : false;
}
}

View file

@ -0,0 +1,111 @@
<?php
namespace RainLoop\Providers\Contacts\Classes;
class Contact
{
/**
* @var int
*/
public $IdContact;
/**
* @var int
*/
public $IdUser;
/**
* @var int
*/
public $Type;
/**
* @var int
*/
public $Frec;
/**
* @var string
*/
public $ListName;
/**
* @var string
*/
public $Name;
/**
* @var array
*/
public $Emails;
/**
* @var string
*/
public $ImageHash;
/**
* @var array
*/
public $Data;
public function __construct()
{
$this->Clear();
}
public function Clear()
{
$this->IdContact = 0;
$this->IdUser = 0;
$this->Type = 0;
$this->Frec = 0;
$this->ListName = '';
$this->Name = '';
$this->ImageHash = '';
$this->Emails = array();
$this->Data = array();
}
/**
* @return string
*/
public function GenarateListName()
{
return 0 < \strlen($this->Name) ? $this->Name : (!empty($this->Emails[0]) ? $this->Emails[0] : '');
}
/**
* @return string
*/
public function EmailsAsString()
{
return \trim(\implode(' ', $this->Emails));
}
/**
* @return string
*/
public function DataAsString()
{
return @\serialize($this->Data);
}
/**
* @param string $sData
*/
public function ParseData($sData)
{
$sData = (string) $sData;
$sData = \trim($sData);
if (!empty($sData))
{
$aData = @\unserialize($sData);
if (\is_array($aData))
{
$this->Data = $aData;
}
}
}
}

View file

@ -0,0 +1,38 @@
<?php
namespace RainLoop\Providers\Contacts\Classes;
class Db
{
/**
* @return int
*/
static public function Version()
{
return 1;
}
/**
* @return array
*/
static public function Strucure()
{
return array(
'rlContactsUsers' => array(
'IdUser' => 'INTEGER PRIMARY KEY',
'Email' => 'TEXT'
),
'rlContactsItems' => array(
'IdContact' => 'INTEGER PRIMARY KEY',
'IdUser' => 'INTEGER',
'Type' => 'INTEGER',
'Frec' => 'INTEGER',
'ImageHash' => 'TEXT',
'ListName' => 'TEXT',
'Name' => 'TEXT',
'Emails' => 'TEXT',
'Data' => 'TEXT'
)
);
}
}

View file

@ -0,0 +1,68 @@
<?php
namespace RainLoop\Providers\Contacts;
interface ContactsInterface
{
/**
* @param \RainLoop\Account $oAccount
* @param int $iIdContact
*
* @return $oContact|null
*/
public function GetContactById($oAccount, $iIdContact);
/**
* @param \RainLoop\Account $oAccount
* @param int $iOffset = 0
* @param int $iLimit = 20
* @param string $sSearch = ''
*
* @return array
*/
public function GetContacts($oAccount, $iOffset = 0, $iLimit = 20, $sSearch = '');
/**
* @param \RainLoop\Account $oAccount
*
* @return array
*/
public function GetContactsImageHashes($oAccount);
/**
* @param \RainLoop\Account $oAccount
* @param \RainLoop\Providers\Contacts\Classes\Contact $oContact
*
* @return bool
*/
public function CreateContact($oAccount, &$oContact);
/**
* @param \RainLoop\Account $oAccount
* @param \RainLoop\Providers\Contacts\Classes\Contact $oContact
*
* @return bool
*/
public function UpdateContact($oAccount, &$oContact);
/**
* @param \RainLoop\Account $oAccount
* @param array $aContactIds
*
* @return bool
*/
public function DeleteContacts($oAccount, $aContactIds);
/**
* @return bool
*/
public function IsSupported();
/**
* @param \RainLoop\Account $oAccount
* @param array $aContactIds
*
* @return bool
*/
public function IncFrec($oAccount, $aContactIds);
}

View file

@ -0,0 +1,600 @@
<?php
namespace RainLoop\Providers\Contacts;
class DefaultContacts implements \RainLoop\Providers\Contacts\ContactsInterface
{
/**
* @var \MailSo\Log\Logger
*/
private $oLogger;
/**
* @var bool
*/
private $bUseDbPerUser;
/**
* @param \MailSo\Log\Logger $oLogger = null
*/
public function __construct($oLogger = null)
{
$this->oLogger = $oLogger instanceof \MailSo\Log\Logger ? $oLogger : null;
$this->bUseDbPerUser = true;
}
/**
* @param \RainLoop\Account $oAccount
* @staticvar array $aPdoCache
* @return \PDO
*/
private function getPDO($oAccount)
{
static $aPdoCache = array();
$sEmail = $oAccount->ParentEmailHelper();
if (isset($aPdoCache[$sEmail]))
{
return $aPdoCache[$sEmail];
}
if (!\class_exists('PDO'))
{
throw new \Exception('class_exists=PDO');
}
$sVersionFile = '';
$sDsn = '';
if ($this->bUseDbPerUser)
{
$sSubPath = APP_PRIVATE_DATA.'storage/contacts/'.\rtrim(\substr($sEmail, 0, 2), '@').'/'.$sEmail.'/';
if (!\is_dir($sSubPath))
{
if (\mkdir($sSubPath, 0755, true) && \is_dir($sSubPath))
{
$sVersionFile = $sSubPath.'.version';
$sDsn = 'sqlite:'.$sSubPath.'contacts.sqlite';
}
}
else
{
$sVersionFile = $sSubPath.'.version';
$sDsn = 'sqlite:'.$sSubPath.'contacts.sqlite';
}
}
else
{
$sVersionFile = APP_PRIVATE_DATA.'.version';
$sDsn = 'sqlite:'.APP_PRIVATE_DATA.'contacts.sqlite';
}
$sDbLogin = '';
$sDbPassword = '';
$oPdo = false;
try
{
$oPdo = new \PDO($sDsn, $sDbLogin, $sDbPassword);
if ($oPdo)
{
$oPdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
if (!@\file_exists($sVersionFile) ||
(string) @file_get_contents($sVersionFile) !== (string) \RainLoop\Providers\Contacts\Classes\Db::Version())
{
$this->syncTables($oPdo, $sVersionFile);
}
$oPdo->sqliteCreateFunction('SIMPLESEARCH', function ($sEmailValue, $sNameValue, $sMask) {
return \preg_match('/'.\preg_quote($sMask, '/').'/ui',
$sEmailValue.' '.$sNameValue) ? 1 : 0;
});
}
}
catch (\Exception $oException)
{
throw $oException;
$oPdo = false;
}
if ($oPdo)
{
$aPdoCache[$oAccount->ParentEmailHelper()] = $oPdo;
}
return $oPdo;
}
protected function getWantedColumnsInfo($sTableName, $aCurrent)
{
$aColumns = array();
foreach ($aCurrent as $sName => $sType)
{
$sSql = $sName.' '.$sType;
switch ($sType)
{
case 'INTEGER':
$sSql .= ' DEFAILT \'0\'';
break;
case 'TEXT':
$sSql .= ' DEFAILT \'\'';
break;
}
$aColumns[$sName] = $sSql;
}
if (0 === \count($aColumns))
{
return '';
}
return 'CREATE TABLE '.$sTableName.' (' .\implode(', ', $aColumns).')';
}
/**
* @param \PDO $oAccount
* @param string $sTableName
*/
protected function getCurrentColumnsInfo($oPdo, $sTableName)
{
$oStmt = $this->prepareAndExecute($oPdo, 'SELECT `sql` FROM `sqlite_master` WHERE `tbl_name` = :TableName AND `type` = :Type', array(
':TableName' => array($sTableName, \PDO::PARAM_STR),
':Type' => array('table', \PDO::PARAM_STR)
));
if ($oStmt)
{
$mRow = $oStmt->fetch(\PDO::FETCH_ASSOC);
if ($mRow && isset($mRow['sql']))
{
return (string) $mRow['sql'];
}
}
return '';
}
/**
* @param \PDO $oPdo
* @param string $sVersionFile = ''
*/
private function syncTables($oPdo, $sVersionFile = '')
{
if ($this->oLogger)
{
$this->oLogger->Write('Start to sync', \MailSo\Log\Enumerations\Type::INFO);
}
$aStrucure = \RainLoop\Providers\Contacts\Classes\Db::Strucure();
foreach ($aStrucure as $sTableName => $aField)
{
$sCurrent = $this->getCurrentColumnsInfo($oPdo, $sTableName);
$sWanted = $this->getWantedColumnsInfo($sTableName, $aField);
if (empty($sCurrent))
{
$this->prepareAndExecute($oPdo, $sWanted);
}
else if ($sCurrent !== $sWanted)
{
$this->prepareAndExecute($oPdo, 'DROP TABLE IF EXISTS `'.$sTableName.'_old`');
$this->prepareAndExecute($oPdo, 'ALTER TABLE `'.$sTableName.'` RENAME TO `'.$sTableName.'_old`');
$this->prepareAndExecute($oPdo, $sWanted);
$aNewKeys = array();
$aOldKeys = array();
foreach ($aField as $sKey => $sType)
{
$aNewKeys[] = $sKey;
$aOldKeys[] = false !== \strpos($sCurrent, $sKey.' ') ? $sKey :
(0 === \strpos($sType, 'INT') ? '\'0\'' : '\'\'');
}
$sNewKeys = \implode(', ', $aNewKeys);
$sOldKeys = \implode(', ', $aOldKeys);
$this->prepareAndExecute($oPdo, 'INSERT INTO `'.$sTableName.'` ('.$sNewKeys.') SELECT '.$sOldKeys.' FROM `'.$sTableName.'_old`');
$this->prepareAndExecute($oPdo, 'DROP TABLE `'.$sTableName.'_old`');
}
}
@\file_put_contents($sVersionFile, \RainLoop\Providers\Contacts\Classes\Db::Version());
if ($this->oLogger)
{
$this->oLogger->Write('Stop to sync', \MailSo\Log\Enumerations\Type::INFO);
}
}
/**
* @param \RainLoop\Account|\PDO $oAccountOrPdo
* @param string $sSql
* @param array $aParams
*
* @return \PDOStatement|null
*/
private function prepareAndExecute($oAccountOrPdo, $sSql, $aParams = array())
{
if ($this->oLogger)
{
$this->oLogger->Write($sSql, \MailSo\Log\Enumerations\Type::INFO, 'SQLITE');
}
$oPdo = $oAccountOrPdo instanceof \PDO ? $oAccountOrPdo : $this->getPDO($oAccountOrPdo);
$oStmt = $oPdo->prepare($sSql);
foreach ($aParams as $sName => $aValue)
{
$oStmt->bindValue($sName, $aValue[0], $aValue[1]);
}
// $sLogSql = $sSql;
// foreach($aParams as $sName => $aValue)
// {
// $sLogSql = \str_replace($sName, $aValue[1] === \PDO::PARAM_INT ? $aValue[0] : '\''.$aValue[0].'\'', $sLogSql);
// }
//
// if ($this->oLogger)
// {
// $this->oLogger->Write($sLogSql, \MailSo\Log\Enumerations\Type::INFO, 'SQLITE');
// }
$mResult = $oStmt->execute() ? $oStmt : null;
// if ($this->oLogger)
// {
// $this->oLogger->Write('RESULT: '.($mResult ? 'true' : 'false'), \MailSo\Log\Enumerations\Type::INFO, 'SQLITE');
// }
return $mResult;
}
/**
* @param \RainLoop\Account|null $oAccount
* @param bool $bSkipInsert = false
*
* @return int
*/
private function getUserId($oAccount, $bSkipInsert = false)
{
if (!$this->bUseDbPerUser)
{
$oStmt = $this->prepareAndExecute($oAccount,
'SELECT IdUser FROM rlContactsUsers WHERE Email = :Email LIMIT 1',
array(
':Email' => array($oAccount->ParentEmailHelper(), \PDO::PARAM_STR)
));
$mRow = $oStmt->fetch(\PDO::FETCH_ASSOC);
if ($mRow && isset($mRow['IdUser']) && \is_numeric($mRow['IdUser']))
{
return (int) $mRow['IdUser'];
}
if (!$bSkipInsert)
{
$oStmt->closeCursor();
$oStmt = $this->prepareAndExecute($oAccount,
'INSERT INTO rlContactsUsers (Email) VALUES (:Email)',
array(
':Email' => array($oAccount->ParentEmailHelper(), \PDO::PARAM_STR)
));
return $this->getUserId($oAccount, true);
}
throw new \Exception('IdUser=0');
}
return 0;
}
/**
* @param string $sSearch
* @return string
*/
private function convertSearchValue($sSearch)
{
return '%'.$sSearch.'%';
}
private function populateContactFromDB($iUserID, $aItem)
{
$oContact = null;
if (isset($aItem['IdContact']))
{
$oContact = new \RainLoop\Providers\Contacts\Classes\Contact();
$oContact->IdContact = (int) $aItem['IdContact'];
$oContact->IdUser = $iUserID;
$oContact->Type = (int) $aItem['Type'];
$oContact->Frec = (int) $aItem['Frec'];
$oContact->ListName = (string) $aItem['ListName'];
$oContact->Name = (string) $aItem['Name'];
$oContact->Emails = \explode(' ', \trim((string) $aItem['Emails']));
$oContact->ImageHash = (string) $aItem['ImageHash'];
$oContact->ParseData($aItem['Data']);
}
return $oContact;
}
/**
* @param \RainLoop\Account $oAccount
* @param int $iIdContact
*
* @return $oContact|null
*/
public function GetContactById($oAccount, $iIdContact)
{
$oResultContact = null;
$iUserID = $this->getUserId($oAccount);
$oStmt = $this->prepareAndExecute($oAccount,
'SELECT IdContact, Type, Frec, ListName, Name, Emails, ImageHash, Data'.
' FROM rlContactsItems WHERE IdContact = :IdContact AND IdUser = :IdUser LIMIT 1',
array(
':IdContact' => array($iIdContact, \PDO::PARAM_INT),
':IdUser' => array($iUserID, \PDO::PARAM_INT)
));
$aFetch = $oStmt->fetchAll(\PDO::FETCH_ASSOC);
if (\is_array($aFetch) && isset($aFetch[0]) && \is_array($aFetch[0]))
{
$oContact = $this->populateContactFromDB($iUserID, $aFetch[0]);
if ($oContact instanceof \RainLoop\Providers\Contacts\Classes\Contact)
{
$oResultContact = $oContact;
}
}
return $oResultContact;
}
/**
* @param \RainLoop\Account $oAccount
* @param int $iOffset = 0
* @param int $iLimit = 20
* @param string $sSearch = ''
*
* @return array
*/
public function GetContacts($oAccount, $iOffset = 0, $iLimit = 20, $sSearch = '')
{
$iOffset = 0 <= $iOffset ? $iOffset : 0;
$iLimit = 0 < $iLimit ? (int) $iLimit : 0;
$sSearch = \trim($sSearch);
$iUserID = $this->getUserId($oAccount);
$sSql = 'SELECT IdContact, Type, Frec, ListName, Name, Emails, ImageHash, Data'.
' FROM rlContactsItems WHERE IdUser = :IdUser'
;
$aParams = array(
':IdUser' => array($iUserID, \PDO::PARAM_INT),
':limit' => array($iLimit, \PDO::PARAM_INT),
':offset' => array($iOffset, \PDO::PARAM_INT)
);
if (0 < strlen($sSearch))
{
if (\MailSo\Base\Utils::IsAscii($sSearch))
{
$sSql .= ' AND Name LIKE :Search OR Emails LIKE :Search';
$aParams[':Search'] = array($this->convertSearchValue($sSearch), \PDO::PARAM_STR);
}
else
{
$sSql .= ' AND SIMPLESEARCH(Emails, Name, :Search)';
$aParams[':Search'] = array($sSearch, \PDO::PARAM_STR);
}
}
$sSql .= ' ORDER BY ListName ASC LIMIT :limit OFFSET :offset';
$oStmt = $this->prepareAndExecute($oAccount, $sSql, $aParams);
$aFetch = $oStmt->fetchAll(\PDO::FETCH_ASSOC);
$aResult = array();
if (\is_array($aFetch) && 0 < \count($aFetch))
{
foreach ($aFetch as $aItem)
{
$oContact = $this->populateContactFromDB($iUserID, $aItem);
if ($oContact instanceof \RainLoop\Providers\Contacts\Classes\Contact)
{
$aResult[] = $oContact;
}
}
}
unset($aFetch);
return $aResult;
}
/**
* @param \RainLoop\Account $oAccount
*
* @return array
*/
public function GetContactsImageHashes($oAccount)
{
$iUserID = $this->getUserId($oAccount);
$oStmt = $this->prepareAndExecute($oAccount,
'SELECT Emails, ImageHash FROM rlContactsItems WHERE IdUser = :IdUser AND ImageHash <> :ImageHash',
array(
':IdUser' => array($iUserID, \PDO::PARAM_INT),
':ImageHash' => array('', \PDO::PARAM_STR)
));
$aFetch = $oStmt->fetchAll(\PDO::FETCH_ASSOC);
$aResult = array();
if (\is_array($aFetch) && 0 < \count($aFetch))
{
foreach ($aFetch as $aItem)
{
if (!empty($aItem['Emails']) && !empty($aItem['ImageHash']))
{
$aEmails = \explode(' ', $aItem['Emails']);
foreach ($aEmails as $sEmail)
{
$sEmail = \trim($sEmail);
if (0 < strlen($sEmail))
{
$aResult[$sEmail] = $aItem['ImageHash'];
}
}
}
}
}
unset($aFetch);
return $aResult;
}
/**
* @param \RainLoop\Account $oAccount
* @param \RainLoop\Providers\Contacts\Classes\Contact $oContact
*
* @return bool
*/
public function CreateContact($oAccount, &$oContact)
{
$iUserID = $this->getUserId($oAccount);
$oContact->IdUser = $iUserID;
$oStmt = $this->prepareAndExecute($oAccount,
'INSERT INTO rlContactsItems '.
'( IdUser, Type, Frec, ListName, Name, Emails, ImageHash, Data) VALUES '.
'(:IdUser, :Type, 0, :ListName, :Name, :Emails, :ImageHash, :Data)',
array(
':IdUser' => array($oContact->IdUser, \PDO::PARAM_INT),
':Type' => array($oContact->Type, \PDO::PARAM_INT),
':ListName' => array($oContact->GenarateListName(), \PDO::PARAM_STR),
':Name' => array($oContact->Name, \PDO::PARAM_STR),
':Emails' => array($oContact->EmailsAsString(), \PDO::PARAM_STR),
':ImageHash' => array($oContact->ImageHash, \PDO::PARAM_STR),
':Data' => array($oContact->DataAsString(), \PDO::PARAM_STR),
));
if ($oStmt)
{
$iContactID = $this->getPDO($oAccount)->lastInsertId('IdContact');
if (is_numeric($iContactID) && 0 < (int) $iContactID)
{
$oContact->IdContact = (int) $iContactID;
return true;
}
}
throw new \Exception('CreateContact');
}
/**
* @param \RainLoop\Account $oAccount
* @param \RainLoop\Providers\Contacts\Classes\Contact $oContact
*
* @return bool
*/
public function UpdateContact($oAccount, &$oContact)
{
$iUserID = $this->getUserId($oAccount);
$oContact->IdUser = $iUserID;
return !!$this->prepareAndExecute($oAccount,
'UPDATE rlContactsItems SET'.
' Type = :Type, ListName = :ListName, Name = :Name, Emails = :Emails,'.
' ImageHash = :ImageHash, Data = :Data'.
' WHERE IdContact = :IdContact AND IdUser = :IdUser',
array(
':IdContact' => array($oContact->IdContact, \PDO::PARAM_INT),
':IdUser' => array($oContact->IdUser, \PDO::PARAM_INT),
':Type' => array($oContact->Type, \PDO::PARAM_INT),
':ListName' => array($oContact->GenarateListName(), \PDO::PARAM_STR),
':Name' => array($oContact->Name, \PDO::PARAM_STR),
':Emails' => array($oContact->EmailsAsString(), \PDO::PARAM_STR),
':ImageHash' => array($oContact->ImageHash, \PDO::PARAM_STR),
':Data' => array($oContact->DataAsString(), \PDO::PARAM_STR),
));
}
/**
* @param \RainLoop\Account $oAccount
* @param array $aContactIds
*
* @return bool
*/
public function DeleteContacts($oAccount, $aContactIds)
{
$iUserID = $this->getUserId($oAccount);
$aParams = array(
':IdUser' => array($iUserID, \PDO::PARAM_INT),
);
$aInQuery = array();
foreach ($aContactIds as $iIndex => $iId)
{
$aInQuery[] = ':IdContact_'.$iIndex;
$aParams[':IdContact_'.$iIndex] = array($iId, \PDO::PARAM_INT);
}
if (0 === \count($aInQuery))
{
return false;
}
return !!$this->prepareAndExecute($oAccount,
'DELETE FROM rlContactsItems WHERE IdUser = :IdUser AND IdContact IN ('.\implode(', ', $aInQuery).')',
$aParams);
}
/**
* @return bool
*/
public function IsSupported()
{
$aDrivers = \class_exists('PDO') ? \PDO::getAvailableDrivers() : array();
return \is_array($aDrivers) ? \in_array('sqlite', $aDrivers) : false;
}
/**
* @param \RainLoop\Account $oAccount
* @param array $aContactIds
*
* @return bool
*/
public function IncFrec($oAccount, $aContactIds)
{
if (\is_array($aContactIds) && 0 < \count($aContactIds))
{
$iUserID = $this->getUserId($oAccount);
$aParams = array(
':IdUser' => array($iUserID, \PDO::PARAM_INT),
);
$aInQuery = array();
foreach ($aContactIds as $iIndex => $iId)
{
$aInQuery[] = ':IdContact_'.$iIndex;
$aParams[':IdContact_'.$iIndex] = array($iId, \PDO::PARAM_INT);
}
return !!$this->prepareAndExecute($oAccount,
'UPDATE rlContactsItems SET Frec = Frec + 1 WHERE IdUser = :IdUser AND IdContact IN ('.\implode(', ', $aInQuery).')',
$aParams);
}
return false;
}
}

View file

@ -0,0 +1,161 @@
<?php
namespace RainLoop\Providers;
class Domain extends \RainLoop\Providers\AbstractProvider
{
/**
* @var \RainLoop\Providers\Domain\DomainInterface
*/
private $oDriver;
/**
* @var bool
*/
private $bAdmin;
/**
* @param \RainLoop\Providers\Domain\DomainInterface $oDriver
*
* @return void
*/
public function __construct(\RainLoop\Providers\Domain\DomainInterface $oDriver)
{
$this->oDriver = $oDriver;
$this->bAdmin = $this->oDriver instanceof \RainLoop\Providers\Domain\DomainAdminInterface;
}
/**
* @return bool
*/
public function IsAdmin()
{
return $this->bAdmin;
}
/**
* @param string $sName
*
* @return \RainLoop\Domain | null
*/
public function Load($sName)
{
return $this->oDriver->Load($sName);
}
/**
* @param \RainLoop\Domain $oDomain
*
* @return bool
*/
public function Save(\RainLoop\Domain $oDomain)
{
return $this->bAdmin ? $this->oDriver->Save($oDomain) : false;
}
/**
* @param string $sName
*
* @return bool
*/
public function Delete($sName)
{
return $this->bAdmin ? $this->oDriver->Delete($sName) : false;
}
/**
* @param string $sName
* @param bool $bDisabled
*
* @return bool
*/
public function Disable($sName, $bDisabled)
{
return $this->bAdmin ? $this->oDriver->Disable($sName, $bDisabled) : false;
}
/**
* @param int $iOffset = 0
* @param int $iLimit = 20
* @param string $sSearch = ''
*
* @return array
*/
public function GetList($iOffset = 0, $iLimit = 20, $sSearch = '')
{
return $this->bAdmin ? $this->oDriver->GetList($iOffset, $iLimit, $sSearch) : array();
}
/**
* @param string $sSearch = ''
*
* @return int
*/
public function Count($sSearch = '')
{
return $this->oDriver->Count($sSearch);
}
/**
* @param \RainLoop\Actions $oActions
* @param string $sNameForTest = ''
*
* @return \RainLoop\Domain | null
*/
public function LoadOrCreateNewFromAction(\RainLoop\Actions $oActions, $sNameForTest = '')
{
$oDomain = null;
if ($this->bAdmin)
{
$bCreate = '1' === (string) $oActions->GetActionParam('Create', '0');
$sName = (string) $oActions->GetActionParam('Name', '');
$sIncHost = (string) $oActions->GetActionParam('IncHost', '');
$iIncPort = (int) $oActions->GetActionParam('IncPort', 143);
$iIncSecure = (int) $oActions->GetActionParam('IncSecure', \MailSo\Net\Enumerations\ConnectionSecurityType::NONE);
$bIncShortLogin = '1' === (string) $oActions->GetActionParam('IncShortLogin', '0');
$sOutHost = (string) $oActions->GetActionParam('OutHost', '');
$iOutPort = (int) $oActions->GetActionParam('OutPort', 25);
$iOutSecure = (int) $oActions->GetActionParam('OutSecure', \MailSo\Net\Enumerations\ConnectionSecurityType::NONE);
$bOutShortLogin = '1' === (string) $oActions->GetActionParam('OutShortLogin', '0');
$bOutAuth = '1' === (string) $oActions->GetActionParam('OutAuth', '1');
$sWhiteList = (string) $oActions->GetActionParam('WhiteList', '');
if (0 < strlen($sName) || 0 < strlen($sNameForTest))
{
$oDomain = 0 < strlen($sNameForTest) ? null : $this->Load($sName);
if ($oDomain instanceof \RainLoop\Domain)
{
if ($bCreate)
{
throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::DomainAlreadyExists);
}
else
{
$oDomain->UpdateInstance(
$sIncHost, $iIncPort, $iIncSecure, $bIncShortLogin,
$sOutHost, $iOutPort, $iOutSecure, $bOutShortLogin, $bOutAuth,
\RainLoop\Domain::DEFAULT_FORWARDED_FLAG, $sWhiteList);
}
}
else
{
$oDomain = \RainLoop\Domain::NewInstance(0 < strlen($sNameForTest) ? $sNameForTest : $sName,
$sIncHost, $iIncPort, $iIncSecure, $bIncShortLogin,
$sOutHost, $iOutPort, $iOutSecure, $bOutShortLogin, $bOutAuth,
\RainLoop\Domain::DEFAULT_FORWARDED_FLAG, $sWhiteList);
}
}
}
return $oDomain;
}
/**
* @return bool
*/
public function IsActive()
{
return $this->oDriver instanceof \RainLoop\Providers\Domain\DomainInterface;
}
}

View file

@ -0,0 +1,172 @@
<?php
namespace RainLoop\Providers\Domain;
class DefaultDomain implements \RainLoop\Providers\Domain\DomainAdminInterface
{
/**
* @var string
*/
protected $sDomainPath;
/**
* @param string $sDomainPath
*
* @return void
*/
public function __construct($sDomainPath)
{
$this->sDomainPath = rtrim(trim($sDomainPath), '\\/');
}
/**
* @param string $sName
* @param bool $bDisable
*
* @return bool
*/
public function Disable($sName, $bDisable)
{
$sFile = '';
if (file_exists($this->sDomainPath.'/disabled'))
{
$sFile = @file_get_contents($this->sDomainPath.'/disabled');
}
$aResult = array();
$aNames = explode(',', $sFile);
if ($bDisable)
{
array_push($aNames, $sName);
$aResult = $aNames;
}
else
{
foreach ($aNames as $sItem)
{
if ($sName !== $sItem)
{
$aResult[] = $sItem;
}
}
}
$aResult = array_unique($aResult);
return false !== file_put_contents($this->sDomainPath.'/disabled', trim(implode(',', $aResult), ', '));
}
/**
* @param string $sName
*
* @return \RainLoop\Domain | null
*/
public function Load($sName)
{
$mResult = null;
$sName = strtolower($sName);
if (file_exists($this->sDomainPath.'/'.$sName.'.ini'))
{
$mResult = \RainLoop\Domain::NewInstanceFromDomainConfigArray(
$sName, @parse_ini_file($this->sDomainPath.'/'.$sName.'.ini'));
if ($mResult instanceof \RainLoop\Domain)
{
if (file_exists($this->sDomainPath.'/disabled'))
{
$sDisabled = @file_get_contents($this->sDomainPath.'/disabled');
if (false !== $sDisabled && 0 < strlen($sDisabled))
{
$mResult->SetDisabled(false !== strpos(strtolower(','.$sDisabled.','), strtolower(','.$sName.',')));
}
}
}
}
return $mResult;
}
/**
* @param \RainLoop\Domain $oDomain
*
* @return bool
*/
public function Save(\RainLoop\Domain $oDomain)
{
$mResult = file_put_contents($this->sDomainPath.'/'.strtolower($oDomain->Name()).'.ini', $oDomain->ToIniString());
return is_int($mResult) && 0 < $mResult;
}
/**
* @param string $sName
*
* @return bool
*/
public function Delete($sName)
{
$bResult = true;
$sName = strtolower($sName);
if (0 < strlen($sName) && file_exists($this->sDomainPath.'/'.$sName.'.ini'))
{
$bResult = unlink($this->sDomainPath.'/'.$sName.'.ini');
}
return $bResult;
}
/**
* @param int $iOffset
* @param int $iLimit = 20
* @param string $sSearch = ''
*
* @return array
*/
public function GetList($iOffset, $iLimit = 20, $sSearch = '')
{
$aResult = array();
$aList = glob($this->sDomainPath.'/*.ini');
$sSearch = strtolower($sSearch);
foreach ($aList as $sFile)
{
$sName = strtolower(substr(basename($sFile), 0, -4));
if (0 === strlen($sSearch) || false !== strpos($sName, $sSearch))
{
$aResult[] = $sName;
}
}
$iOffset = (0 > $iOffset) ? 0 : $iOffset;
$iLimit = (0 > $iLimit) ? 0 : ((999 < $iLimit) ? 999 : $iLimit);
$aResult = array_slice($aResult, $iOffset, $iLimit);
$aDisabledNames = array();
if (0 < count($aResult) && file_exists($this->sDomainPath.'/disabled'))
{
$sDisabled = @file_get_contents($this->sDomainPath.'/disabled');
if (false !== $sDisabled && 0 < strlen($sDisabled))
{
$aDisabledNames = explode(',', strtolower($sDisabled));
$aDisabledNames = array_unique($aDisabledNames);
}
}
$aReturn = array();
foreach ($aResult as $sName)
{
$aReturn[$sName] = !in_array(strtolower($sName), $aDisabledNames);
}
return $aReturn;
}
/**
* @param string $sSearch = ''
*
* @return int
*/
public function Count($sSearch = '')
{
return count($this->GetList(0, 999, $sSearch));
}
}

View file

@ -0,0 +1,52 @@
<?php
namespace RainLoop\Providers\Domain;
interface DomainAdminInterface extends DomainInterface
{
/**
* @param string $sName
* @param bool $bDisable
*
* @return bool
*/
public function Disable($sName, $bDisable);
/**
* @param string $sName
*
* @return \RainLoop\Domain | null
*/
public function Load($sName);
/**
* @param \RainLoop\Domain $oDomain
*
* @return bool
*/
public function Save(\RainLoop\Domain $oDomain);
/**
* @param string $sName
*
* @return bool
*/
public function Delete($sName);
/**
* @param int $iOffset
* @param int $iLimit = 20
* @param string $sSearch = ''
*
* @return array
*/
public function GetList($iOffset, $iLimit = 20, $sSearch = '');
/**
* @param string $sSearch = ''
*
* @return int
*/
public function Count($sSearch = '');
}

View file

@ -0,0 +1,7 @@
<?php
namespace RainLoop\Providers\Domain;
interface DomainInterface
{
}

View file

@ -0,0 +1,13 @@
<?php
namespace RainLoop\Providers\Domain;
interface DomainSimpleInterface extends DomainInterface
{
/**
* @param string $sName
*
* @return \RainLoop\Domain | null
*/
public function Load($sName);
}

View file

@ -0,0 +1,117 @@
<?php
namespace RainLoop\Providers;
class Files extends \RainLoop\Providers\AbstractProvider
{
/**
* @var \RainLoop\Providers\Files\FilesInterface
*/
private $oDriver;
/**
* @return void
*/
public function __construct(\RainLoop\Providers\Files\FilesInterface $oDriver)
{
$this->oDriver = $oDriver;
}
/**
* @param \RainLoop\Account $oAccount
* @param string $sKey
* @param resource $rSource
*
* @return bool
*/
public function PutFile($oAccount, $sKey, $rSource)
{
return $this->oDriver->PutFile($oAccount, $sKey, $rSource);
}
/**
* @param \RainLoop\Account $oAccount
* @param string $sKey
* @param string $sSource
*
* @return bool
*/
public function MoveUploadedFile($oAccount, $sKey, $sSource)
{
return $this->oDriver->MoveUploadedFile($oAccount, $sKey, $sSource);
}
/**
* @param \RainLoop\Account $oAccount
* @param string $sKey
* @param string $sOpenMode = 'rb'
*
* @return resource|bool
*/
public function GetFile($oAccount, $sKey, $sOpenMode = 'rb')
{
return $this->oDriver->GetFile($oAccount, $sKey, $sOpenMode);
}
/**
* @param \RainLoop\Account $oAccount
* @param string $sKey
*
* @return string | bool
*/
public function GetFileName($oAccount, $sKey)
{
return $this->oDriver->GetFileName($oAccount, $sKey);
}
/**
* @param \RainLoop\Account $oAccount
* @param string $sKey
*
* @return bool
*/
public function Clear($oAccount, $sKey)
{
return $this->oDriver->Clear($oAccount, $sKey);
}
/**
* @param \RainLoop\Account $oAccount
* @param string $sKey
*
* @return int|bool
*/
public function FileSize($oAccount, $sKey)
{
return $this->oDriver->FileSize($oAccount, $sKey);
}
/**
* @param \RainLoop\Account $oAccount
* @param string $sKey
*
* @return bool
*/
public function FileExists($oAccount, $sKey)
{
return $this->oDriver->FileExists($oAccount, $sKey);
}
/**
* @param int $iTimeToClearInHours = 24
*
* @return bool
*/
public function GC($iTimeToClearInHours = 24)
{
return $this->oDriver ? $this->oDriver->GC($iTimeToClearInHours) : false;
}
/**
* @return bool
*/
public function IsActive()
{
return $this->oDriver instanceof \RainLoop\Providers\Files\FilesInterface;
}
}

View file

@ -0,0 +1,186 @@
<?php
namespace RainLoop\Providers\Files;
class DefaultStorage implements \RainLoop\Providers\Files\FilesInterface
{
/**
* @var string
*/
private $sDataPath;
/**
* @param string $sStoragePath
*
* @return void
*/
public function __construct($sStoragePath)
{
$this->sDataPath = \rtrim(\trim($sStoragePath), '\\/');
}
/**
* @param \RainLoop\Account $oAccount
* @param string $sKey
* @param resource $rSource
*
* @return bool
*/
public function PutFile($oAccount, $sKey, $rSource)
{
$bResult = false;
if ($rSource)
{
$rOpenOutput = @\fopen($this->generateFileName($oAccount, $sKey, true), 'w+b');
if ($rOpenOutput)
{
$bResult = (false !== \MailSo\Base\Utils::MultipleStreamWriter($rSource, array($rOpenOutput)));
@\fclose($rOpenOutput);
}
}
return $bResult;
}
/**
* @param \RainLoop\Account $oAccount
* @param string $sKey
* @param string $sSource
*
* @return bool
*/
public function MoveUploadedFile($oAccount, $sKey, $sSource)
{
return @\move_uploaded_file($sSource,
$this->generateFileName($oAccount, $sKey, true));
}
/**
* @param \RainLoop\Account $oAccount
* @param string $sKey
* @param string $sOpenMode = 'rb'
*
* @return resource|bool
*/
public function GetFile($oAccount, $sKey, $sOpenMode = 'rb')
{
$mResult = false;
$bCreate = !!\preg_match('/[wac]/', $sOpenMode);
$sFileName = $this->generateFileName($oAccount, $sKey, $bCreate);
if ($bCreate || \file_exists($sFileName))
{
$mResult = @\fopen($sFileName, $sOpenMode);
}
return $mResult;
}
/**
* @param \RainLoop\Account $oAccount
* @param string $sKey
*
* @return string|bool
*/
public function GetFileName($oAccount, $sKey)
{
$mResult = false;
$sFileName = $this->generateFileName($oAccount, $sKey);
if (\file_exists($sFileName))
{
$mResult = $sFileName;
}
return $mResult;
}
/**
* @param \RainLoop\Account $oAccount
* @param string $sKey
*
* @return bool
*/
public function Clear($oAccount, $sKey)
{
$mResult = true;
$sFileName = $this->generateFileName($oAccount, $sKey);
if (\file_exists($sFileName))
{
$mResult = @\unlink($sFileName);
}
return $mResult;
}
/**
* @param \RainLoop\Account $oAccount
* @param string $sKey
*
* @return int|bool
*/
public function FileSize($oAccount, $sKey)
{
$mResult = false;
$sFileName = $this->generateFileName($oAccount, $sKey);
if (\file_exists($sFileName))
{
$mResult = \filesize($sFileName);
}
return $mResult;
}
/**
* @param \RainLoop\Account $oAccount
* @param string $sKey
*
* @return bool
*/
public function FileExists($oAccount, $sKey)
{
return @\file_exists($this->generateFileName($oAccount, $sKey));
}
/**
* @param int $iTimeToClearInHours = 24
*
* @return bool
*/
public function GC($iTimeToClearInHours = 24)
{
if (0 < $iTimeToClearInHours)
{
\MailSo\Base\Utils::RecTimeDirRemove($this->sDataPath, 60 * 60 * $iTimeToClearInHours, \time());
return true;
}
return false;
}
/**
* @param \RainLoop\Account $oAccount
* @param string $sKey
* @param bool $bMkDir = false
*
* @return string
*/
private function generateFileName($oAccount, $sKey, $bMkDir = false)
{
$sEmail = \preg_replace('/[^a-z0-9\-\.@]+/', '_',
('' === $oAccount->ParentEmail() ? '' : $oAccount->ParentEmail().'/').$oAccount->Email());
$sKeyPath = \sha1($sKey);
$sKeyPath = \substr($sKeyPath, 0, 2).'/'.\substr($sKeyPath, 2, 2).'/'.$sKeyPath;
$sFilePath = $this->sDataPath.'/'.rtrim(substr($sEmail, 0, 2), '@').'/'.$sEmail.'/'.$sKeyPath;
if ($bMkDir && !empty($sFilePath) && !@\is_dir(\dirname($sFilePath)))
{
if (!@\mkdir(\dirname($sFilePath), 0755, true))
{
throw new \RainLoop\Exceptions\Exception('Can\'t make storage directory "'.$sFilePath.'"');
}
}
return $sFilePath;
}
}

View file

@ -0,0 +1,72 @@
<?php
namespace RainLoop\Providers\Files;
interface FilesInterface
{
/**
* @param \RainLoop\Account $oAccount
* @param string $sKey
* @param resource $rSource
*
* @return bool
*/
public function PutFile($oAccount, $sKey, $rSource);
/**
* @param CAccount $oAccount
* @param string $sKey
* @param string $sSource
*
* @return bool
*/
public function MoveUploadedFile($oAccount, $sKey, $sSource);
/**
* @param \RainLoop\Account $oAccount
* @param string $sKey
* @param string $sOpenMode = 'rb'
*
* @return resource|bool
*/
public function GetFile($oAccount, $sKey, $sOpenMode = 'rb');
/**
* @param \RainLoop\Account $oAccount
* @param string $sKey
*
* @return string|bool
*/
public function GetFileName($oAccount, $sKey);
/**
* @param \RainLoop\Account $oAccount
* @param string $sKey
*
* @return bool
*/
public function Clear($oAccount, $sKey);
/**
* @param \RainLoop\Account $oAccount
* @param string $sKey
*
* @return int | bool
*/
public function FileSize($oAccount, $sKey);
/**
* @param \RainLoop\Account $oAccount
* @param string $sKey
*
* @return bool
*/
public function FileExists($oAccount, $sKey);
/**
* @param int $iTimeToClearInHours = 24
* @return bool
*/
public function GC($iTimeToClearInHours = 24);
}

View file

@ -0,0 +1,61 @@
<?php
namespace RainLoop\Providers;
class Login extends \RainLoop\Providers\AbstractProvider
{
/**
* @var \RainLoop\Providers\Login\LoginInterface
*/
private $oDriver;
/**
* @var \RainLoop\Providers\Domain
*/
private $oDomainProvider;
/**
* @param \RainLoop\Providers\Login\LoginInterface $oDriver
* @param \RainLoop\Providers\Domain $oDomainProvider
*
* @return void
*/
public function __construct(\RainLoop\Providers\Login\LoginInterface $oDriver,
\RainLoop\Providers\Domain $oDomainProvider)
{
$this->oDriver = $oDriver;
$this->oDomainProvider = $oDomainProvider;
}
/**
* @param string $sEmail
* @param string $sLogin
* @param string $sPassword
* @param bool $sSignMeToken = ''
*
* @return \RainLoop\Account|null
*/
public function Provide($sEmail, $sLogin, $sPassword, $sSignMeToken = '')
{
$oResult = null;
if ($this->oDriver->ProvideParameters($sEmail, $sLogin, $sPassword))
{
$oDomain = $this->oDomainProvider->Load(\MailSo\Base\Utils::GetDomainFromEmail($sEmail));
if ($oDomain instanceof \RainLoop\Domain && !$oDomain->Disabled() && $oDomain->ValidateWhiteList($sEmail, $sLogin))
{
$oResult = \RainLoop\Account::NewInstance($sEmail, $sLogin, $sPassword, $oDomain, $sSignMeToken);
}
}
return $oResult;
}
/**
* @return bool
*/
public function IsActive()
{
return $this->oDriver instanceof \RainLoop\Providers\Login\LoginInterface;
}
}

View file

@ -0,0 +1,18 @@
<?php
namespace RainLoop\Providers\Login;
class DefaultLogin implements \RainLoop\Providers\Login\LoginInterface
{
/**
* @param string $sEmail
* @param string $sLogin
* @param string $sPassword
*
* @return bool
*/
public function ProvideParameters(&$sEmail, &$sLogin, &$sPassword)
{
return 0 < strlen($sEmail) && 0 < strlen($sLogin) && 0 < strlen($sPassword);
}
}

View file

@ -0,0 +1,15 @@
<?php
namespace RainLoop\Providers\Login;
interface LoginInterface
{
/**
* @param string $sEmail
* @param string $sLogin
* @param string $sPassword
*
* @return bool
*/
public function ProvideParameters(&$sEmail, &$sLogin, &$sPassword);
}

View file

@ -0,0 +1,52 @@
<?php
namespace RainLoop\Providers;
class Settings extends \RainLoop\Providers\AbstractProvider
{
/**
* @var \RainLoop\Providers\Settings\SettingsInterface
*/
private $oDriver;
/**
* @param \RainLoop\Providers\Settings\SettingsInterface $oDriver
*
* @return void
*/
public function __construct(\RainLoop\Providers\Settings\SettingsInterface $oDriver)
{
$this->oDriver = $oDriver;
}
/**
* @param \RainLoop\Account $oAccount
*
* @return \RainLoop\Settings
*/
public function Load(\RainLoop\Account $oAccount)
{
$oSettings = new \RainLoop\Settings();
$oSettings->InitData($this->oDriver->Load($oAccount));
return $oSettings;
}
/**
* @param \RainLoop\Account $oAccount
* @param \RainLoop\Settings $oSettings
*
* @return bool
*/
public function Save(\RainLoop\Account $oAccount, \RainLoop\Settings $oSettings)
{
return $this->oDriver->Save($oAccount, $oSettings->DataAsArray());
}
/**
* @return bool
*/
public function IsActive()
{
return $this->oDriver instanceof \RainLoop\Providers\Settings\SettingsInterface;
}
}

View file

@ -0,0 +1,59 @@
<?php
namespace RainLoop\Providers\Settings;
class DefaultSettings implements \RainLoop\Providers\Settings\SettingsInterface
{
const FILE_NAME = 'settings';
/**
* @var \RainLoop\Providers\Storage
*/
private $oStorageProvider;
/**
* @param \RainLoop\Providers\Storage $oStorageProvider
*/
public function __construct(\RainLoop\Providers\Storage $oStorageProvider)
{
$this->oStorageProvider = $oStorageProvider;
}
/**
* @param \RainLoop\Account $oAccount
*
* @return array
*/
public function Load(\RainLoop\Account $oAccount)
{
$sValue = $this->oStorageProvider->Get($oAccount,
\RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
\RainLoop\Providers\Settings\DefaultSettings::FILE_NAME);
$aSettings = array();
if (\is_string($sValue))
{
$aData = \json_decode($sValue, true);
if (\is_array($aData))
{
$aSettings = $aData;
}
}
return $aSettings;
}
/**
* @param \RainLoop\Account $oAccount
* @param array $aSettings
*
* @return bool
*/
public function Save(\RainLoop\Account $oAccount, array $aSettings)
{
return $this->oStorageProvider->Put($oAccount,
\RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
\RainLoop\Providers\Settings\DefaultSettings::FILE_NAME,
\json_encode($aSettings));
}
}

View file

@ -0,0 +1,21 @@
<?php
namespace RainLoop\Providers\Settings;
interface SettingsInterface
{
/**
* @param \RainLoop\Account $oAccount
*
* @return array
*/
public function Load(\RainLoop\Account $oAccount);
/**
* @param \RainLoop\Account $oAccount
* @param array $aSettings
*
* @return bool
*/
public function Save(\RainLoop\Account $oAccount, array $aSettings);
}

View file

@ -0,0 +1,80 @@
<?php
namespace RainLoop\Providers;
class Storage extends \RainLoop\Providers\AbstractProvider
{
/**
* @var \RainLoop\Providers\Storage\StorageInterface
*/
private $oDriver;
/**
* @return void
*/
public function __construct(\RainLoop\Providers\Storage\StorageInterface $oDriver)
{
$this->oDriver = $oDriver;
}
/**
* @param \RainLoop\Account|null $oAccount
* @param int $iStorageType
* @param string $iStorageType
* @param string $sValue
*
* @return bool
*/
public function Put($oAccount, $iStorageType, $sKey, $sValue)
{
if (\RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY !== $iStorageType && !($oAccount instanceof \RainLoop\Account))
{
return false;
}
return $this->oDriver->Put($oAccount, $iStorageType, $sKey, $sValue);
}
/**
* @param \RainLoop\Account|null $oAccount
* @param int $iStorageType
* @param string $sKey
* @param mixed $mDefault = false
*
* @return mixed
*/
public function Get($oAccount, $iStorageType, $sKey, $mDefault = false)
{
if (\RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY !== $iStorageType && !($oAccount instanceof \RainLoop\Account))
{
return $mDefault;
}
return $this->oDriver->Get($oAccount, $iStorageType, $sKey, $mDefault);
}
/**
* @param \RainLoop\Account|null $oAccount
* @param int $iStorageType
* @param string $sKey
*
* @return bool
*/
public function Clear($oAccount, $iStorageType, $sKey)
{
if (\RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY !== $iStorageType && !($oAccount instanceof \RainLoop\Account))
{
return false;
}
return $this->oDriver->Clear($oAccount, $iStorageType, $sKey);
}
/**
* @return bool
*/
public function IsActive()
{
return $this->oDriver instanceof \RainLoop\Providers\Storage\StorageInterface;
}
}

View file

@ -0,0 +1,129 @@
<?php
namespace RainLoop\Providers\Storage;
class DefaultStorage implements \RainLoop\Providers\Storage\StorageInterface
{
/**
* @var string
*/
private $sDataPath;
/**
* @param string $sStoragePath
*
* @return void
*/
public function __construct($sStoragePath)
{
$this->sDataPath = \rtrim(\trim($sStoragePath), '\\/');
}
/**
* @param \RainLoop\Account|null $oAccount
* @param int $iStorageType
* @param string $sKey
* @param string $sValue
*
* @return bool
*/
public function Put($oAccount, $iStorageType, $sKey, $sValue)
{
return false !== @\file_put_contents(
$this->generateFileName($oAccount, $iStorageType, $sKey, true), $sValue);
}
/**
* @param \RainLoop\Account|null $oAccount
* @param int $iStorageType
* @param string $sKey
* @param mixed $mDefault = false
*
* @return mixed
*/
public function Get($oAccount, $iStorageType, $sKey, $mDefault = false)
{
$mValue = false;
$sFileName = $this->generateFileName($oAccount, $iStorageType, $sKey);
if (\file_exists($sFileName))
{
$mValue = \file_get_contents($sFileName);
}
return false === $mValue ? $mDefault : $mValue;
}
/**
* @param \RainLoop\Account|null $oAccount
* @param int $iStorageType
* @param string $sKey
*
* @return bool
*/
public function Clear($oAccount, $iStorageType, $sKey)
{
$mResult = true;
$sFileName = $this->generateFileName($oAccount, $iStorageType, $sKey);
if (\file_exists($sFileName))
{
$mResult = @\unlink($sFileName);
}
return $mResult;
}
/**
* @param \RainLoop\Account|null $oAccount
* @param int $iStorageType
* @param string $sKey
* @param bool $bMkDir = false
*
* @return string
*/
private function generateFileName($oAccount, $iStorageType, $sKey, $bMkDir = false)
{
if (!$oAccount)
{
$iStorageType = \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY;
}
$sEmail = $oAccount ? \preg_replace('/[^a-z0-9\-\.@]+/', '_',
('' === $oAccount->ParentEmail() ? '' : $oAccount->ParentEmail().'/').$oAccount->Email()) : '';
$sTypePath = $sKeyPath = '';
switch ($iStorageType)
{
default:
case \RainLoop\Providers\Storage\Enumerations\StorageType::USER:
case \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY:
$sTypePath = 'data';
$sKeyPath = \md5($sKey);
$sKeyPath = \substr($sKeyPath, 0, 2).'/'.$sKeyPath;
break;
case \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG:
$sTypePath = 'cfg';
$sKeyPath = \preg_replace('/[_]+/', '_', \preg_replace('/[^a-zA-Z0-9\/]/', '_', $sKey));
break;
}
$sFilePath = '';
if (\RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY === $iStorageType)
{
$sFilePath = $this->sDataPath.'/'.$sTypePath.'/__nobody__/'.$sKeyPath;
}
else if (!empty($sEmail))
{
$sFilePath = $this->sDataPath.'/'.$sTypePath.'/'.rtrim(substr($sEmail, 0, 2), '@').'/'.$sEmail.'/'.$sKeyPath;
}
if ($bMkDir && !empty($sFilePath) && !@\is_dir(\dirname($sFilePath)))
{
if (!@\mkdir(\dirname($sFilePath), 0755, true))
{
throw new \RainLoop\Exceptions\Exception('Can\'t make storage directory "'.$sFilePath.'"');
}
}
return $sFilePath;
}
}

View file

@ -0,0 +1,10 @@
<?php
namespace RainLoop\Providers\Storage\Enumerations;
class StorageType
{
const USER = 1;
const CONFIG = 2;
const NOBODY = 3;
}

View file

@ -0,0 +1,35 @@
<?php
namespace RainLoop\Providers\Storage;
interface StorageInterface
{
/**
* @param \RainLoop\Account|null $oAccount
* @param int $iStorageType
* @param string $sKey
* @param string $sValue
*
* @return bool
*/
public function Put($oAccount, $iStorageType, $sKey, $sValue);
/**
* @param \RainLoop\Account|null $oAccount
* @param int $iStorageType
* @param string $sKey
* @param mixed $mDefault = false
*
* @return mixed
*/
public function Get($oAccount, $iStorageType, $sKey, $mDefault = false);
/**
* @param \RainLoop\Account|null $oAccount
* @param int $iStorageType
* @param string $sKey
*
* @return bool
*/
public function Clear($oAccount, $iStorageType, $sKey);
}

View file

@ -0,0 +1,40 @@
<?php
namespace RainLoop\Providers;
class Suggestions extends \RainLoop\Providers\AbstractProvider
{
/**
* @var \RainLoop\Providers\Suggestions\SuggestionsInterface
*/
private $oDriver;
/**
* @param \RainLoop\Providers\Suggestions\SuggestionsInterface|null $oDriver = null
*
* @return void
*/
public function __construct($oDriver = null)
{
$this->oDriver = $oDriver;
}
/**
* @param \RainLoop\Account $oAccount
* @param string $sQuery
*
* @return array
*/
public function Process(\RainLoop\Account $oAccount, $sQuery)
{
return $this->oDriver && $this->IsActive() && 0 < \strlen($sQuery) ? $this->oDriver->Process($oAccount, $sQuery) : array();
}
/**
* @return bool
*/
public function IsActive()
{
return $this->oDriver instanceof \RainLoop\Providers\Suggestions\SuggestionsInterface;
}
}

View file

@ -0,0 +1,14 @@
<?php
namespace RainLoop\Providers\Suggestions;
interface SuggestionsInterface
{
/**
* @param \RainLoop\Account $oAccount
* @param string $sQuery
*
* @return array
*/
public function Process(\RainLoop\Account $oAccount, $sQuery);
}

View file

@ -0,0 +1,244 @@
<?php
namespace RainLoop;
class Service
{
/**
* @var \MailSo\Base\Http
*/
private $oHttp;
/**
* @var \RainLoop\Actions
*/
private $oActions;
/**
* @var \RainLoop\ServiceActions
*/
private $oServiceActions;
/**
* @return void
*/
private function __construct()
{
$this->oHttp = \MailSo\Base\Http::SingletonInstance();
$this->oActions = Actions::NewInstance();
\set_error_handler(array(&$this, 'LogPhpErrorHandler'));
$this->oServiceActions = new \RainLoop\ServiceActions($this->oHttp, $this->oActions);
if ($this->oActions->Config()->Get('debug', 'enable', false))
{
\error_reporting(E_ALL);
\ini_set('display_errors', 1);
}
$sServer = \trim($this->oActions->Config()->Get('security', 'custom_server_signature', ''));
if (0 < \strlen($sServer))
{
@\header('Server: '.$sServer, true);
}
}
/**
* @return \RainLoop\Service
*/
public static function NewInstance()
{
return new self();
}
/**
* @param int $iErrNo
* @param string $sErrStr
* @param string $sErrFile
* @param int $iErrLine
*
* @return bool
*/
public function LogPhpErrorHandler($iErrNo, $sErrStr, $sErrFile, $iErrLine)
{
$iType = \MailSo\Log\Enumerations\Type::NOTICE;
switch ($iErrNo)
{
case E_USER_ERROR:
$iType = \MailSo\Log\Enumerations\Type::ERROR;
break;
case E_USER_WARNING:
$iType = \MailSo\Log\Enumerations\Type::WARNING;
break;
}
if (!\in_array($sErrStr, array('iconv(): Detected an illegal character in input string')))
{
$this->oActions->Logger()->Write($sErrFile.' [line:'.$iErrLine.', code:'.$iErrNo.']', $iType, 'PHP');
$this->oActions->Logger()->Write('Error: '.$sErrStr, $iType, 'PHP');
}
return false;
}
/**
* @return \RainLoop\Service
*/
public function Handle()
{
if (!\class_exists('MailSo\Version'))
{
return $this;
}
$this->oActions->ParseQueryAuthString();
if (defined('APP_INSTALLED_START') && defined('APP_INSTALLED_VERSION') && APP_INSTALLED_START &&
$this->oActions->Config()->Get('labs', 'usage_statistics', true))
{
$this->oActions->KeenIO(APP_INSTALLED_VERSION ? 'Upgrade' : 'Install',
APP_INSTALLED_VERSION ? array('previos-version' => APP_INSTALLED_VERSION) : array());
}
$bCached = false;
$sResult = '';
$sQuery = \trim(\trim($this->oHttp->GetServer('QUERY_STRING', '')), ' /');
$iPos = \strpos($sQuery, '&');
if (0 < $iPos)
{
$sQuery = \substr($sQuery, 0, $iPos);
}
$this->oActions->Plugins()->RunHook('filter.http-query', array(&$sQuery));
$aPaths = \explode('/', $sQuery);
$this->oActions->Plugins()->RunHook('filter.http-paths', array(&$aPaths));
$bAdmin = !empty($aPaths[0]) && \in_array(\strtolower($aPaths[0]), array('admin', 'cp'));
if (0 < \count($aPaths) && !empty($aPaths[0]) && !$bAdmin)
{
$sMethodName = 'Service'.$aPaths[0];
if (\method_exists($this->oServiceActions, $sMethodName) &&
\is_callable(array($this->oServiceActions, $sMethodName)))
{
$this->oServiceActions->SetQuery($sQuery)->SetPaths($aPaths);
$sResult = \call_user_func(array($this->oServiceActions, $sMethodName));
}
else if (!$this->oActions->Plugins()->RunAdditionalPart($aPaths[0], $aPaths))
{
$this->oActions->Logger()->Write('Unknown request', \MailSo\Log\Enumerations\Type::WARNING, 'RESPONSE');
}
}
else
{
@header('Content-Type: text/html; charset=utf-8');
$aData = $this->startUpData($bAdmin);
$bCacheEnabled = $this->oActions->Config()->Get('labs', 'cache_system_data', true);
$sCacheFileName = '';
if ($bCacheEnabled)
{
$sCacheFileName = 'TMPL:'.$aData['Hash'];
$sResult = $this->oActions->Cacher()->Get($sCacheFileName);
}
if (0 === \strlen($sResult))
{
$sJsBoot = \file_get_contents(APP_VERSION_ROOT_PATH.'static/js/boot.js');
$sResult = \strtr(\file_get_contents(APP_VERSION_ROOT_PATH.'app/templates/Index.html'), array(
'{{BaseAppDataScriptLink}}' => ($bAdmin ? APP_INDEX_FILE.'?/AdminAppData/' : APP_INDEX_FILE.'?/AppData/'),
'{{BaseAppIndexFile}}' => APP_INDEX_FILE,
'{{BaseAppFaviconFile}}' => $aData['FaviconLink'],
'{{BaseAppMainCssLink}}' => $aData['AppCssLink'],
'{{BaseAppBootScriptSource}}' => $sJsBoot,
'{{BaseAppLibsScriptLink}}' => $aData['LibJsLink'],
'{{BaseAppMainScriptLink}}' => $aData['AppJsLink'],
'{{BaseAppLoadingDescription}}' => \htmlspecialchars($aData['LoadingDescription'], ENT_QUOTES|ENT_IGNORE, 'UTF-8'),
'{{BaseDir}}' => \in_array($aData['Language'], array('ar', 'he', 'ur')) ? 'rtl' : 'ltr'
));
$sResult = \RainLoop\Utils::ClearHtmlOutput($sResult);
if (0 < \strlen($sCacheFileName))
{
$this->oActions->Cacher()->Set($sCacheFileName, $sResult);
}
}
else
{
$bCached = true;
}
$sResult .= '<!--';
$sResult .= ' [version:'.APP_VERSION;
$sResult .= '][time:'.substr(\microtime(true) - APP_START, 0, 6);
$sResult .= '][cached:'.($bCached ? 'true' : 'false');
$sResult .= '][session:'.md5(\RainLoop\Utils::GetShortToken());
$sResult .= '] -->';
}
// Output result
echo $sResult;
unset($sResult);
return $this;
}
/**
* @param bool $bAppJsDebug
* @param bool $bAdmin
*
* @return string
*/
private function generateIndexCacheHash($bAppJsDebug, $bAdmin)
{
return \md5(APP_WEB_PATH.
$this->oActions->Config()->Get('webmail', 'loading_description', 'RainLoop').
$this->oActions->Config()->Get('labs', 'cdn_static_domain', '').
\md5($this->oActions->Config()->Get('cache', 'index', '')).
$this->oActions->Plugins()->Hash().
APP_VERSION.($bAppJsDebug ? 'd' : 'm').($bAdmin ? 'a' : 'w'));
}
/**
* @param bool $bAdmin
*
* @return array
*/
private function startUpData($bAdmin)
{
$sLanguage = 'en';
$sTheme = 'Default';
if (!$bAdmin)
{
list($sLanguage, $sTheme) = $this->oActions->GetLanguageAndTheme();
}
$sLanguage = $this->oActions->ValidateLanguage($sLanguage);
$sTheme = $this->oActions->ValidateTheme($sTheme);
$bAppJsDebug = !!$this->oActions->Config()->Get('labs', 'use_app_debug_js', false);
$bAppCssDebug = !!$this->oActions->Config()->Get('labs', 'use_app_debug_css', false);
$sCdnStaticDomain = $this->oActions->Config()->Get('labs', 'cdn_static_domain', '');
$sStaticPrefix = APP_WEB_STATIC_PATH;
if (0 < \strlen($sCdnStaticDomain))
{
$sStaticPrefix = \trim($sCdnStaticDomain, ' /\\').'/'.APP_VERSION.'/static/';
}
return array(
'Language' => $sLanguage,
'Theme' => $sTheme,
'Hash' => $this->generateIndexCacheHash($bAppJsDebug, $bAdmin),
'LoadingDescription' => $this->oActions->Config()->Get('webmail', 'loading_description', 'RainLoop'),
'FaviconLink' => $sStaticPrefix.'favicon.png',
'AppCssLink' => $sStaticPrefix.'css/app'.($bAppCssDebug ? '' : '.min').'.css',
'LibJsLink' => $sStaticPrefix.'js/libs.js',
'AppJsLink' => $sStaticPrefix.'js/'.($bAdmin ? 'admin' : 'app').($bAppJsDebug ? '' : '.min').'.js'
);
}
}

View file

@ -0,0 +1,941 @@
<?php
namespace RainLoop;
class ServiceActions
{
/**
* @var \MailSo\Base\Http
*/
protected $oHttp;
/**
* @var \RainLoop\Actions
*/
protected $oActions;
/**
* @var array
*/
protected $aPaths;
/**
* @param \MailSo\Base\Http $oHttp
* @param \RainLoop\Actions $oActions
*
* @return void
*/
public function __construct($oHttp, $oActions)
{
$this->oHttp = $oHttp;
$this->oActions = $oActions;
$this->aPaths = array();
}
/**
* @return \MailSo\Log\Logger
*/
public function Logger()
{
return $this->oActions->Logger();
}
/**
* @return \RainLoop\Plugins\Manager
*/
public function Plugins()
{
return $this->oActions->Plugins();
}
/**
* @return \RainLoop\Application
*/
public function Config()
{
return $this->oActions->Config();
}
/**
* @return \MailSo\Cache\CacheClient
*/
public function Cacher()
{
return $this->oActions->Cacher();
}
/**
* @return \RainLoop\Providers\Storage
*/
public function StorageProvider()
{
return $this->oActions->StorageProvider();
}
/**
* @param array $aPaths
*
* @return \RainLoop\ServiceActions
*/
public function SetPaths($aPaths)
{
$this->aPaths = \is_array($aPaths) ? $aPaths : array();
return $this;
}
/**
* @param string $sQuery
*
* @return \RainLoop\ServiceActions
*/
public function SetQuery($sQuery)
{
$this->sQuery = $sQuery;
return $this;
}
/**
* @return string
*/
public function ServiceAjax()
{
@\ob_start();
$aResponseItem = null;
$oException = null;
$sAction = $this->oHttp->GetPost('Action', null);
if (empty($sAction) && $this->oHttp->IsGet() && !empty($this->aPaths[2]))
{
$sAction = $this->aPaths[2];
}
try
{
if ($this->oHttp->IsPost() &&
$this->Config()->Get('security', 'csrf_protection', false)
&& $this->oHttp->GetPost('XToken', '') !== \RainLoop\Utils::GetCsrfToken())
{
throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::InvalidToken);
}
else if (!empty($sAction))
{
$sMethodName = 'Do'.$sAction;
$this->Logger()->Write('Action: '.$sMethodName, \MailSo\Log\Enumerations\Type::NOTE, 'AJAX');
$aPost = $this->oHttp->GetPostAsArray();
if (\is_array($aPost) && 0 < \count($aPost))
{
$this->oActions->SetActionParams($aPost, $sMethodName);
switch ($sMethodName)
{
case 'DoLogin':
case 'DoAdminLogin':
case 'DoAccountAdd':
$this->Logger()->AddSecret($this->oActions->GetActionParam('Password', ''));
break;
case 'DoChangePassword':
$this->Logger()->AddSecret($this->oActions->GetActionParam('PrevPassword', ''));
$this->Logger()->AddSecret($this->oActions->GetActionParam('NewPassword', ''));
break;
}
$this->Logger()->Write(\MailSo\Base\Utils::Php2js($aPost), \MailSo\Log\Enumerations\Type::INFO, 'POST', true);
}
else if (3 < \count($this->aPaths) && $this->oHttp->IsGet())
{
$this->oActions->SetActionParams(array(
'RawKey' => empty($this->aPaths[3]) ? '' : $this->aPaths[3]
), $sMethodName);
}
if (\method_exists($this->oActions, $sMethodName) &&
\is_callable(array($this->oActions, $sMethodName)))
{
$this->Plugins()->RunHook('ajax.action-pre-call', array($sAction));
$aResponseItem = \call_user_func(array($this->oActions, $sMethodName));
$this->Plugins()->RunHook('ajax.action-post-call', array($sAction, &$aResponseItem));
}
else if ($this->Plugins()->HasAdditionalAjax($sMethodName))
{
$this->Plugins()->RunHook('ajax.action-pre-call', array($sAction));
$aResponseItem = $this->Plugins()->RunAdditionalAjax($sMethodName);
$this->Plugins()->RunHook('ajax.action-post-call', array($sAction, &$aResponseItem));
}
}
if (!\is_array($aResponseItem))
{
throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::UnknownError);
}
}
catch (\Exception $oException)
{
$aResponseItem = $this->oActions->ExceptionResponse(
empty($sAction) ? 'Unknown' : $sAction, $oException);
if (\is_array($aResponseItem) && 'Folders' === $sAction && $oException instanceof \RainLoop\Exceptions\ClientException)
{
$aResponseItem['Logout'] = true;
}
}
if (\is_array($aResponseItem))
{
$aResponseItem['Time'] = (int) ((\microtime(true) - APP_START) * 1000);
}
$this->Plugins()->RunHook('filter.ajax-response', array($sAction, &$aResponseItem));
@\header('Content-Type: application/json; charset=utf-8');
$sResult = \MailSo\Base\Utils::Php2js($aResponseItem);
$sObResult = @\ob_get_clean();
if ($this->Logger()->IsEnabled())
{
if (0 < \strlen($sObResult))
{
$this->Logger()->Write($sObResult, \MailSo\Log\Enumerations\Type::ERROR, 'OB-DATA');
}
if ($oException)
{
$this->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR);
}
$iLimit = (int) $this->Config()->Get('labs', 'log_ajax_response_write_limit', 0);
$this->Logger()->Write(0 < $iLimit && $iLimit < \strlen($sResult)
? \substr($sResult, 0, $iLimit).'...' : $sResult, \MailSo\Log\Enumerations\Type::INFO, 'AJAX');
}
return $sResult;
}
/**
* @return string
*/
public function ServiceAppend()
{
@\ob_start();
$bResponse = false;
$oException = null;
try
{
if (\method_exists($this->oActions, 'Append') &&
\is_callable(array($this->oActions, 'Append')))
{
$this->oActions->SetActionParams($this->oHttp->GetPostAsArray(), 'Append');
$bResponse = \call_user_func(array($this->oActions, 'Append'));
}
}
catch (\Exception $oException)
{
$bResponse = false;
}
@\header('Content-Type: text/plain; charset=utf-8');
$sResult = true === $bResponse ? '1' : '0';
$sObResult = @\ob_get_clean();
if (0 < \strlen($sObResult))
{
$this->Logger()->Write($sObResult, \MailSo\Log\Enumerations\Type::ERROR, 'OB-DATA');
}
if ($oException)
{
$this->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR);
}
$this->Logger()->Write($sResult, \MailSo\Log\Enumerations\Type::INFO, 'APPEND');
return $sResult;
}
/**
* @param string $sAction
*
* @return string
*/
private function privateUpload($sAction)
{
@\ob_start();
$aResponseItem = null;
try
{
if (\method_exists($this->oActions, $sAction) &&
\is_callable(array($this->oActions, $sAction)))
{
$this->oActions->SetActionParams($this->oHttp->GetQueryAsArray(), $sAction);
$aResponseItem = \call_user_func(array($this->oActions, $sAction));
}
if (!is_array($aResponseItem))
{
throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::UnknownError);
}
}
catch (\Exception $oException)
{
$aResponseItem = $this->oActions->ExceptionResponse($sAction, $oException);
}
if ('iframe' === $this->oHttp->GetPost('jua-post-type', ''))
{
@\header('Content-Type: text/html; charset=utf-8');
}
else
{
@\header('Content-Type: application/json; charset=utf-8');
}
$this->Plugins()->RunHook('filter.upload-response', array(&$aResponseItem));
$sResult = \MailSo\Base\Utils::Php2js($aResponseItem);
$sObResult = @\ob_get_clean();
if (0 < \strlen($sObResult))
{
$this->Logger()->Write($sObResult, \MailSo\Log\Enumerations\Type::ERROR, 'OB-DATA');
}
$this->Logger()->Write($sResult, \MailSo\Log\Enumerations\Type::INFO, 'UPLOAD');
return $sResult;
}
/**
* @return string
*/
public function ServiceUpload()
{
return $this->privateUpload('Upload');
}
/**
* @return string
*/
public function ServiceUploadBackground()
{
return $this->privateUpload('UploadBackground');
}
/**
* @return string
*/
public function ServiceRaw()
{
$sResult = '';
$sRawError = '';
$sAction = empty($this->aPaths[2]) ? '' : $this->aPaths[2];
$oException = null;
try
{
$sRawError = 'Invalid action';
if (0 !== \strlen($sAction))
{
$sMethodName = 'Raw'.$sAction;
if (\method_exists($this->oActions, $sMethodName))
{
$sRawError = '';
$this->oActions->SetActionParams(array(
'RawKey' => empty($this->aPaths[3]) ? '' : $this->aPaths[3]
), $sMethodName);
if (!\call_user_func(array($this->oActions, $sMethodName)))
{
$sRawError = 'False result';
}
else
{
$sRawError = '';
}
}
}
}
catch (\RainLoop\Exceptions\ClientException $oException)
{
$sRawError = 'Exception as result';
switch ($oException->getCode())
{
case \RainLoop\Notifications::AuthError:
$sRawError = 'Authentication failed';
break;
}
}
catch (\Exception $oException)
{
$sRawError = 'Exception as result';
}
if (0 < \strlen($sRawError))
{
$this->oActions->Logger()->Write($sRawError, \MailSo\Log\Enumerations\Type::ERROR);
}
if ($oException)
{
$this->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR, 'RAW');
}
return $sResult;
}
/**
* @return string
*/
public function ServiceLang()
{
$sResult = '';
@\header('Content-Type: application/javascript; charset=utf-8');
if (!empty($this->aPaths[2]))
{
$sLanguage = $this->oActions->ValidateLanguage($this->aPaths[2]);
$bCacheEnabled = $this->Config()->Get('labs', 'cache_system_data', true);
if (!empty($sLanguage) && $bCacheEnabled)
{
$this->oActions->verifyCacheByKey($this->sQuery);
}
$sCacheFileName = '';
if ($bCacheEnabled)
{
$sCacheFileName = 'LANG:'.$this->oActions->Plugins()->Hash().$sLanguage.APP_VERSION;
$sResult = $this->Cacher()->Get($sCacheFileName);
}
if (0 === \strlen($sResult))
{
$sResult = $this->compileLanguage($sLanguage, false);
if ($bCacheEnabled && 0 < \strlen($sCacheFileName))
{
$this->Cacher()->Set($sCacheFileName, $sResult);
}
}
if ($bCacheEnabled)
{
$this->oActions->cacheByKey($this->sQuery);
}
}
return $sResult;
}
/**
* @return string
*/
public function ServiceTemplates()
{
$sResult = '';
@\header('Content-Type: application/javascript; charset=utf-8');
$bCacheEnabled = $this->Config()->Get('labs', 'cache_system_data', true);
if ($bCacheEnabled)
{
$this->oActions->verifyCacheByKey($this->sQuery);
}
$sCacheFileName = '';
if ($bCacheEnabled)
{
$sCacheFileName = 'TEMPLATES:'.$this->oActions->Plugins()->Hash().APP_VERSION;
$sResult = $this->Cacher()->Get($sCacheFileName);
}
if (0 === \strlen($sResult))
{
$sResult = $this->compileTemplates(false);
if ($bCacheEnabled && 0 < \strlen($sCacheFileName))
{
$this->Cacher()->Set($sCacheFileName, $sResult);
}
}
if ($bCacheEnabled)
{
$this->oActions->cacheByKey($this->sQuery);
}
return $sResult;
}
/**
* @return string
*/
public function ServicePlugins()
{
$sResult = '';
$bAdmin = !empty($this->aPaths[2]) && 'Admin' === $this->aPaths[2];
@\header('Content-Type: application/javascript; charset=utf-8');
$bCacheEnabled = $this->Config()->Get('labs', 'cache_system_data', true);
if ($bCacheEnabled)
{
$this->oActions->verifyCacheByKey($this->sQuery);
}
$sCacheFileName = '';
if ($bCacheEnabled)
{
$sCacheFileName = 'PLUGIN:'.$this->oActions->Plugins()->Hash().APP_VERSION;
$sResult = $this->Cacher()->Get($sCacheFileName);
}
if (0 === strlen($sResult))
{
$sResult = $this->Plugins()->CompileJs($bAdmin);
if ($bCacheEnabled && 0 < \strlen($sCacheFileName))
{
$this->Cacher()->Set($sCacheFileName, $sResult);
}
}
if ($bCacheEnabled)
{
$this->oActions->cacheByKey($this->sQuery);
}
return $sResult;
}
/**
* @return string
*/
public function ServiceCss()
{
$sResult = '';
$bCustom = false;
$oAccount = null;
$oSettings = null;
$bAdmin = !empty($this->aPaths[2]) && 'Admin' === $this->aPaths[2];
$bJson = !empty($this->aPaths[7]) && 'Json' === $this->aPaths[7];
if ($bJson)
{
@\header('Content-Type: application/json; charset=utf-8');
}
else
{
@\header('Content-Type: text/css; charset=utf-8');
}
$sTheme = '';
if (!empty($this->aPaths[4]))
{
$sTheme = $this->oActions->ValidateTheme($this->aPaths[4]);
if ('Custom' === $sTheme && !empty($this->aPaths[1]) && '0' !== $this->aPaths[1])
{
$bCustom = true;
$oAccount = $this->oActions->GetAccount(false);
if ($oAccount)
{
$oSettings = $this->oActions->SettingsProvider()->Load($oAccount);
}
}
$bCacheEnabled = $this->Config()->Get('labs', 'cache_system_data', true);
if ($bCacheEnabled && !$bCustom)
{
$this->oActions->verifyCacheByKey($this->sQuery);
}
$sCacheFileName = '';
if ($bCacheEnabled && !$bCustom)
{
$sCacheFileName = 'THEMES/PLUGINS:'.$sTheme.':'.$this->Plugins()->Hash();
$sResult = $this->Cacher()->Get($sCacheFileName);
}
if (0 === \strlen($sResult))
{
try
{
include_once APP_VERSION_ROOT_PATH.'app/libraries/lessphp/ctype.php';
include_once APP_VERSION_ROOT_PATH.'app/libraries/lessphp/lessc.inc.php';
$oLess = new \lessc();
$oLess->setFormatter('compressed');
$aResult = array();
$sThemeValuesFile = APP_VERSION_ROOT_PATH.'app/templates/Themes/values.less';
if ($bCustom)
{
$sThemeFile = APP_VERSION_ROOT_PATH.'app/templates/Themes/custom-values-light.less';
if ($oSettings)
{
if (\RainLoop\Enumerations\CustomThemeType::LIGHT === (string) $oSettings->GetConf('CustomThemeType', \RainLoop\Enumerations\CustomThemeType::LIGHT))
{
$sThemeFile = APP_VERSION_ROOT_PATH.'app/templates/Themes/custom-values-light.less';
}
else
{
$sThemeFile = APP_VERSION_ROOT_PATH.'app/templates/Themes/custom-values-dark.less';
}
}
}
else
{
$sThemeFile = APP_VERSION_ROOT_PATH.'themes/'.$sTheme.'/styles.less';
}
$sThemeTemplateFile = APP_VERSION_ROOT_PATH.'app/templates/Themes/template.less';
if (\file_exists($sThemeFile) && \file_exists($sThemeTemplateFile) && \file_exists($sThemeValuesFile))
{
$aResult[] = '@base: "'.APP_WEB_PATH.'themes/'.$sTheme.'/";';
$aResult[] = \file_get_contents($sThemeValuesFile);
$aResult[] = \file_get_contents($sThemeFile);
$aResult[] = \file_get_contents($sThemeTemplateFile);
if (\file_exists(APP_VERSION_ROOT_PATH.'themes/'.$sTheme.'/ext.less'))
{
$aResult[] = \file_get_contents(APP_VERSION_ROOT_PATH.'themes/'.$sTheme.'/ext.less');
}
}
$aResult[] = $this->Plugins()->CompileCss($bAdmin);
$sResult = $oLess->compile(\implode("\n", $aResult));
if ($bCustom && $oAccount)
{
$mData = $this->oActions->StorageProvider()->Get($oAccount, \RainLoop\Providers\Storage\Enumerations\StorageType::USER, 'CustomThemeBackground', '');
if (!empty($mData) && 'data:' === \substr($mData, 0, 5))
{
$sResult = \str_replace('background-image:link', 'background-image:url("'.$mData.'")', $sResult);
}
}
if ($bCacheEnabled && !$bCustom)
{
if (0 < \strlen($sCacheFileName))
{
$this->Cacher()->Set($sCacheFileName, $sResult);
}
}
}
catch (\Exception $oException)
{
$this->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR, 'LESS');
}
}
if ($bCacheEnabled && !$bCustom)
{
$this->oActions->cacheByKey($this->sQuery);
}
}
return $bJson ? \MailSo\Base\Utils::Php2js(array($sTheme, $sResult)) : $sResult;
}
/**
* @return string
*/
public function ServiceSocialGoogle()
{
return $this->oActions->Social()->GooglePopupService();
}
/**
* @return string
*/
public function ServiceSocialFacebook()
{
return $this->oActions->Social()->FacebookPopupService();
}
/**
* @return string
*/
public function ServiceSocialTwitter()
{
return $this->oActions->Social()->TwitterPopupService();
}
/**
* @return string
*/
public function ServiceAppData()
{
return $this->localAppData(false);
}
/**
* @return string
*/
public function ServiceAdminAppData()
{
return $this->localAppData(true);
}
/**
* @return string
*/
public function ServiceNoScript()
{
return $this->localError($this->oActions->StaticI18N('STATIC/NO_SCRIPT_TITLE'), $this->oActions->StaticI18N('STATIC/NO_SCRIPT_DESC'));
}
/**
* @return string
*/
public function ServiceNoCookie()
{
return $this->localError($this->oActions->StaticI18N('STATIC/NO_COOKIE_TITLE'), $this->oActions->StaticI18N('STATIC/NO_COOKIE_DESC'));
}
/**
* @return string
*/
public function ServiceBadBrowser()
{
$sTitle = $this->oActions->StaticI18N('STATIC/BAD_BROWSER_TITLE');
$sDesc = \nl2br($this->oActions->StaticI18N('STATIC/BAD_BROWSER_DESC'));
@\header('Content-Type: text/html; charset=utf-8');
return \strtr(\file_get_contents(APP_VERSION_ROOT_PATH.'app/templates/BadBrowser.html'), array(
'{{BaseWebStaticPath}}' => APP_WEB_STATIC_PATH,
'{{ErrorTitle}}' => $sTitle,
'{{ErrorHeader}}' => $sTitle,
'{{ErrorDesc}}' => $sDesc
));
}
/**
* @return string
*/
public function ServicePing()
{
@\header('Content-Type: text/plain; charset=utf-8');
$this->oActions->Logger()->Write('Pong', \MailSo\Log\Enumerations\Type::INFO, 'PING');
return 'Pong';
}
/**
* @return string
*/
public function ServiceInfo()
{
if ($this->oActions->IsAdminLoggined(false))
{
@\header('Content-Type: text/html; charset=utf-8');
\phpinfo();
}
}
/**
* @return string
*/
public function ServiceExternalLogin()
{
if ($this->oActions->Config()->Get('labs', 'allow_external_login', false))
{
$oException = null;
try
{
$sEmail = trim($this->oHttp->GetRequest('Email', ''));
$sLogin = trim($this->oHttp->GetRequest('Login', ''));
$sPassword = $this->oHttp->GetRequest('Password', '');
$this->oActions->Logger()->AddSecret($sPassword);
if (0 === \strlen($sLogin))
{
$sLogin = $sEmail;
}
$oAccount = $this->oActions->LoginProcess($sEmail, $sLogin, $sPassword);
$this->oActions->AuthProcess($oAccount);
}
catch (\Exception $oException)
{
$this->oActions->Logger()->WriteException($oException);
}
}
$this->oActions->Location('./');
return '';
}
/**
* @return string
*/
public function ServiceChange()
{
if ($this->Config()->Get('webmail', 'allow_additional_accounts', true))
{
$oAccountToLogin = null;
$sEmail = empty($this->aPaths[2]) ? '' : \strtolower(\urldecode(\trim($this->aPaths[2])));
if (!empty($sEmail))
{
$oAccount = $this->oActions->GetAccount();
if ($oAccount)
{
$aAccounts = $this->oActions->GetAccounts($oAccount);
if (isset($aAccounts[$sEmail]))
{
$oAccountToLogin = $this->oActions->GetAccountFromCustomToken($aAccounts[$sEmail], false, false);
}
}
}
if ($oAccountToLogin)
{
$this->oActions->AuthProcess($oAccountToLogin);
}
}
$this->oActions->Location('./');
return '';
}
/**
* @param string $sTitle
* @param string $sDesc
*
* @return string
*/
private function localError($sTitle, $sDesc)
{
@header('Content-Type: text/html; charset=utf-8');
return $this->oActions->ErrorTemplates($sTitle, \nl2br($sDesc));
}
/**
* @param bool $bAdmin = true
*
* @return string
*/
private function localAppData($bAdmin = false)
{
@\header('Content-Type: application/javascript; charset=utf-8');
@\header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
@\header('Last-Modified: '.\gmdate('D, d M Y H:i:s').' GMT');
@\header('Cache-Control: no-store, no-cache, must-revalidate');
@\header('Cache-Control: post-check=0, pre-check=0', false);
@\header('Pragma: no-cache');
$sAuthAccountHash = '';
if (!$bAdmin)
{
$sAuthAccountHash = $this->oActions->GetSpecAuthTokenWithDeletion();
if (empty($sAuthAccountHash))
{
$sAuthAccountHash = $this->oActions->GetSpecAuthToken();
}
if (empty($sAuthAccountHash))
{
$sSignMeToken = \RainLoop\Utils::GetCookie(\RainLoop\Actions::AUTH_SIGN_ME_TOKEN_KEY, '');
if (!empty($sSignMeToken))
{
$oAccount = $this->oActions->GetAccountFromCustomToken($this->StorageProvider()->Get(null,
\RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY,
'SignMe/UserToken/'.$sSignMeToken
), false, false);
if ($oAccount)
{
$this->oActions->AuthProcess($oAccount);
$sAuthAccountHash = $this->oActions->GetSpecAuthToken();
}
}
}
$this->oActions->SetSpecAuthToken($sAuthAccountHash);
}
$sResult = $this->compileAppData($this->oActions->AppData($bAdmin, $sAuthAccountHash), false);
$this->Logger()->Write($sResult, \MailSo\Log\Enumerations\Type::INFO, 'APPDATA');
return $sResult;
}
/**
* @param bool $bAdmin = false
* @param bool $bWrapByScriptTag = true
*
* @return string
*/
private function compileTemplates($bAdmin = false, $bWrapByScriptTag = false)
{
$sHtml = \RainLoop\Utils::CompileTemplates(APP_VERSION_ROOT_PATH.'app/templates/Views', $this->oActions).
$this->oActions->Plugins()->CompileTemplate($bAdmin);
return
($bWrapByScriptTag ? '<script type="text/javascript">' : '').
'window.rainloopTEMPLATES='.\MailSo\Base\Utils::Php2js(array($sHtml)).';'.
($bWrapByScriptTag ? '</script>' : '')
;
}
/**
* @param string $sLanguage
* @param bool $bWrapByScriptTag = true
*
* @return string
*/
private function compileLanguage($sLanguage, $bWrapByScriptTag = true)
{
$aResultLang = array();
$sMoment = 'window.moment && window.moment.lang && window.moment.lang(\'en\');';
$sMomentFileName = APP_VERSION_ROOT_PATH.'app/i18n/moment/'.$sLanguage.'.js';
if (\file_exists($sMomentFileName))
{
$sMoment = \file_get_contents($sMomentFileName);
$sMoment = \preg_replace('/\/\/[^\n]+\n/', '', $sMoment);
}
\RainLoop\Utils::ReadAndAddLang(APP_VERSION_ROOT_PATH.'app/i18n/langs.ini', $aResultLang);
\RainLoop\Utils::ReadAndAddLang(APP_VERSION_ROOT_PATH.'langs/'.$sLanguage.'.ini', $aResultLang);
$this->Plugins()->ReadLang($sLanguage, $aResultLang);
$sLangJs = '';
$aLangKeys = \array_keys($aResultLang);
foreach ($aLangKeys as $sKey)
{
$sString = isset($aResultLang[$sKey]) ? $aResultLang[$sKey] : $sKey;
$sLangJs .= '"'.\str_replace('"', '\\"', \str_replace('\\', '\\\\', $sKey)).'":'
.'"'.\str_replace(array("\r", "\n", "\t"), array('\r', '\n', '\t'),
\str_replace('"', '\\"', \str_replace('\\', '\\\\', $sString))).'",';
}
$sResult = empty($sLangJs) ? 'null' : '{'.\substr($sLangJs, 0, -1).'}';
return
($bWrapByScriptTag ? '<script type="text/javascript">' : '').
'window.rainloopI18N='.$sResult.';'.$sMoment.
($bWrapByScriptTag ? '</script>' : '')
;
}
/**
* @param array $aAppData
* @param bool $bWrapByScriptTag = true
*
* @return string
*/
private function compileAppData($aAppData, $bWrapByScriptTag = true)
{
return
($bWrapByScriptTag ? '<script>' : '').
'window.rainloopAppData='.\json_encode($aAppData).';'.
'if(window.__rlah_set){__rlah_set()};'.
($bWrapByScriptTag ? '</script>' : '')
;
}
}

View file

@ -0,0 +1,64 @@
<?php
namespace RainLoop;
class Settings
{
/**
* @var array
*/
protected $aData;
/**
* @return void
*/
public function __construct()
{
$this->aData = array();
}
/**
* @param array $aData
*
* @return \RainLoop\Settings
*/
public function InitData($aData)
{
if (\is_array($aData))
{
$this->aData = $aData;
}
return $this;
}
/**
* @return array
*/
public function DataAsArray()
{
return $this->aData;
}
/**
* @param string $sName
* @param mixed $mDefValue = null
*
* @return mixed
*/
public function GetConf($sName, $mDefValue = null)
{
return isset($this->aData[$sName]) ? $this->aData[$sName] : $mDefValue;
}
/**
* @param string $sName
* @param mixed $mValue
*
* @return void
*/
public function SetConf($sName, $mValue)
{
$this->aData[$sName] = $mValue;
}
}

View file

@ -0,0 +1,894 @@
<?php
namespace RainLoop;
class Social
{
/**
* @var \MailSo\Base\Http
*/
private $oHttp;
/**
* @var \RainLoop\Actions
*/
private $oActions;
/**
*
* @param \MailSo\Base\Http $oHttp
* @param \RainLoop\Actions $oActions
*/
public function __construct($oHttp, $oActions)
{
$this->oHttp = $oHttp;
$this->oActions = $oActions;
}
/**
* @param array $oItem
* @param array $aPics
*
* @return array|null
*/
private function convertGoogleJsonContactToResponseContact($oItem, &$aPics)
{
$mResult = null;
if (!empty($oItem['gd$email'][0]['address']))
{
$mEmail = \strtolower($oItem['gd$email'][0]['address']);
if (\is_array($oItem['gd$email']) && 1 <\count($oItem['gd$email']))
{
$mEmail = array();
foreach ($oItem['gd$email'] as $oEmail)
{
if (!empty($oEmail['address']))
{
$mEmail[] = \strtolower($oEmail['address']);
}
}
}
$sImg = '';
if (!empty($oItem['link']) && is_array($oItem['link']))
{
foreach ($oItem['link'] as $oLink)
{
if ($oLink && isset($oLink['type'], $oLink['href'], $oLink['rel']) &&
'image/*' === $oLink['type'] && '#photo' === \substr($oLink['rel'], -6))
{
$sImg = $oLink['href'];
break;
}
}
}
$mResult = array(
'email' => $mEmail,
'name' => !empty($oItem['title']['$t']) ? $oItem['title']['$t'] : ''
);
if (0 < \strlen($sImg))
{
$sHash = \RainLoop\Utils::EncodeKeyValues(array(
'url' => $sImg,
'type' => 'google_access_token'
));
$mData = array();
if (isset($aPics[$sHash]))
{
$mData = $aPics[$sHash];
if (!is_array($mData))
{
$mData = array($mData);
}
}
if (is_array($mEmail))
{
$mData = array_merge($mData, $mEmail);
$mData = array_unique($mData);
}
else if (0 < strlen($mEmail))
{
$mData[] = $mEmail;
}
if (is_array($mData))
{
if (1 === count($mData) && !empty($mData[0]))
{
$aPics[$sHash] = $mData[0];
}
else if (1 < count($mData))
{
$aPics[$sHash] = $mData;
}
}
}
}
return $mResult;
}
/**
* @return array
*/
public function GoogleUserContacts($oAccount)
{
$mResult = false;
$oGoogle = $this->GoogleConnector();
$aPics = array();
if ($oAccount && $oGoogle)
{
$sAccessToken = $this->GoogleAccessToken($oAccount, $oGoogle);
if (!empty($sAccessToken))
{
$oGoogle->setAccessToken($sAccessToken);
$aResponse = $oGoogle->fetch('https://www.google.com/m8/feeds/contacts/default/full', array(
'alt' => 'json'
));
if (!empty($aResponse['result']['feed']['entry']) && is_array($aResponse['result']['feed']['entry']))
{
$mResult = array();
foreach ($aResponse['result']['feed']['entry'] as $oItem)
{
$aItem = $this->convertGoogleJsonContactToResponseContact($oItem, $aPics);
if ($aItem)
{
if (is_array($aItem['email']))
{
$aNewItem = $aItem;
unset($aNewItem['email']);
foreach ($aItem['email'] as $sEmail)
{
$aNewItem['email'] = $sEmail;
$mResult[] = $aNewItem;
}
}
else
{
$mResult[] = $aItem;
}
}
}
}
}
else
{
$this->oActions->Logger()->Write('Empty Google Access Token', \MailSo\Log\Enumerations\Type::ERROR);
}
}
return false !== $mResult ? array(
'List' => $mResult,
'Pics' => $aPics
) : false;
}
/**
* @return bool
*/
public function GoogleDisconnect($oAccount)
{
$oGoogle = $this->GoogleConnector();
if ($oAccount && $oGoogle)
{
$oSettings = $this->oActions->SettingsProvider()->Load($oAccount);
$sEncodedeData = $oSettings->GetConf('GoogleAccessToken', '');
if (!empty($sEncodedeData))
{
$aData = \RainLoop\Utils::DecodeKeyValues($sEncodedeData);
if (is_array($aData) && isset($aData['access_token'], $aData['id']))
{
$this->oActions->StorageProvider()->Clear(null,
\RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY,
$this->GoogleUserLoginStorageKey($oGoogle, $aData['id'])
);
}
}
$oSettings->SetConf('GoogleAccessToken', '');
$oSettings->SetConf('GoogleSocialName', '');
return $this->oActions->SettingsProvider()->Save($oAccount, $oSettings);
}
return false;
}
/**
* @return bool
*/
public function FacebookDisconnect($oAccount)
{
$oFacebook = $this->FacebookConnector($oAccount ? $oAccount : null);
if ($oAccount && $oFacebook)
{
$oUser = $oFacebook->getUser();
if ($oUser)
{
$mData = false;
try
{
$aData = $oFacebook->api(array(
'method' => 'fql.query',
'query' => 'SELECT uid FROM user WHERE uid = me()'
));
$mData = isset($aData[0], $aData[0]['uid']) ? $aData[0]['uid'] : false;
}
catch (\Exception $oException)
{
$this->oActions->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR);
}
if (false !== $mData && 0 < \strlen($mData))
{
$this->oActions->StorageProvider()->Clear(null,
\RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY,
$this->FacebookUserLoginStorageKey($oFacebook, $mData));
}
}
$oFacebook->UserLogout();
$oSettings = $this->oActions->SettingsProvider()->Load($oAccount);
$oSettings->SetConf('FacebookSocialName', '');
return $this->oActions->SettingsProvider()->Save($oAccount, $oSettings);
}
return false;
}
/**
* @return bool
*/
public function TwitterDisconnect($oAccount)
{
$oTwitter = $this->TwitterConnector();
if ($oAccount && $oTwitter)
{
$oSettings = $this->oActions->SettingsProvider()->Load($oAccount);
$sEncodedeData = $oSettings->GetConf('TwitterAccessToken', '');
if (!empty($sEncodedeData))
{
$aData = \RainLoop\Utils::DecodeKeyValues($sEncodedeData);
if (is_array($aData) && isset($aData['user_id']))
{
$this->oActions->StorageProvider()->Clear(null,
\RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY,
$this->TwitterUserLoginStorageKey($oTwitter, $aData['user_id'])
);
}
}
$oSettings->SetConf('TwitterAccessToken', '');
$oSettings->SetConf('TwitterSocialName', '');
return $this->oActions->SettingsProvider()->Save($oAccount, $oSettings);
}
return false;
}
/**
* @return string
*/
public function GooglePopupService()
{
$sResult = '';
$sLoginUrl = '';
$bLogin = false;
$iErrorCode = \RainLoop\Notifications::UnknownError;
try
{
$oGoogle = $this->GoogleConnector();
if ($this->oHttp->HasQuery('error'))
{
$iErrorCode = ('access_denied' === $this->oHttp->GetQuery('error')) ?
\RainLoop\Notifications::SocialGoogleLoginAccessDisable : \RainLoop\Notifications::UnknownError;
}
else if ($oGoogle)
{
$oAccount = $this->oActions->GetAccount();
$bLogin = !$oAccount;
$sCheckToken = '';
$sCheckAuth = '';
$sState = $this->oHttp->GetQuery('state');
if (!empty($sState))
{
$aParts = explode('|', $sState, 2);
$sCheckToken = !empty($aParts[0]) ? $aParts[0] : '';
$sCheckAuth = !empty($aParts[1]) ? $aParts[1] : '';
}
$sRedirectUrl = $this->oHttp->GetFullUrl().'?SocialGoogle';
if (!$this->oHttp->HasQuery('code'))
{
// https://www.google.com/m8/feeds/
$aParams = array(
'scope' => 'https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile',
'state' => \RainLoop\Utils::GetConnectionToken().'|'.$this->oActions->GetSpecAuthToken(),
// 'access_type' => 'offline',
// 'approval_prompt' => 'force',
'response_type' => 'code'
);
$sLoginUrl = $oGoogle->getAuthenticationUrl('https://accounts.google.com/o/oauth2/auth', $sRedirectUrl, $aParams);
}
else if (!empty($sState) && $sCheckToken === \RainLoop\Utils::GetConnectionToken())
{
if (!empty($sCheckAuth))
{
$this->oActions->SetSpecAuthToken($sCheckAuth);
$oAccount = $this->oActions->GetAccount();
$bLogin = !$oAccount;
}
$aParams = array('code' => $this->oHttp->GetQuery('code'), 'redirect_uri' => $sRedirectUrl);
$aAuthorizationResponse = $oGoogle->getAccessToken('https://accounts.google.com/o/oauth2/token', 'authorization_code', $aParams);
if (!empty($aAuthorizationResponse['result']['access_token']))
{
$oGoogle->setAccessToken($aAuthorizationResponse['result']['access_token']);
$aUserinfoResponse = $oGoogle->fetch('https://www.googleapis.com/oauth2/v2/userinfo');
if (!empty($aUserinfoResponse['result']['id']))
{
if ($bLogin)
{
$sUserData = $this->oActions->StorageProvider()->Get(null,
\RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY,
$this->GoogleUserLoginStorageKey($oGoogle, $aUserinfoResponse['result']['id'])
);
$aUserData = \RainLoop\Utils::DecodeKeyValues($sUserData);
if ($aUserData && \is_array($aUserData) &&
!empty($aUserData['Email']) &&
!empty($aUserData['Login']) &&
isset($aUserData['Password']))
{
$oAccount = $this->oActions->LoginProcess($aUserData['Email'], $aUserData['Login'], $aUserData['Password']);
if ($oAccount instanceof \RainLoop\Account)
{
$this->oActions->AuthProcess($oAccount);
$iErrorCode = 0;
}
}
else
{
$iErrorCode = \RainLoop\Notifications::SocialGoogleLoginAccessDisable;
}
}
if ($oAccount)
{
$aUserData = array(
'Email' => $oAccount->Email(),
'Login' => $oAccount->Login(),
'Password' => $oAccount->Password()
);
$sSocialName = !empty($aUserinfoResponse['result']['name']) ? $aUserinfoResponse['result']['name'] : '';
$sSocialName .= !empty($aUserinfoResponse['result']['email']) ? ' ('.$aUserinfoResponse['result']['email'].')' : '';
$sSocialName = \trim($sSocialName);
$oSettings = $this->oActions->SettingsProvider()->Load($oAccount);
$oSettings->SetConf('GoogleSocialName', $sSocialName);
$this->oActions->SettingsProvider()->Save($oAccount, $oSettings);
$this->oActions->StorageProvider()->Put(null,
\RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY,
$this->GoogleUserLoginStorageKey($oGoogle, $aUserinfoResponse['result']['id']),
\RainLoop\Utils::EncodeKeyValues($aUserData));
$iErrorCode = 0;
}
}
}
}
}
}
catch (\Exception $oException)
{
$this->oActions->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR);
}
if ($sLoginUrl)
{
$this->oActions->Location($sLoginUrl);
}
else
{
@\header('Content-Type: text/html; charset=utf-8');
$sCallBackType = $bLogin ? '_login' : '';
$sConnectionFunc = 'rl_'.\md5(\RainLoop\Utils::GetConnectionToken()).'_google'.$sCallBackType.'_service';
$sResult = '<script>opener && opener.'.$sConnectionFunc.' && opener.'.
$sConnectionFunc.'('.$iErrorCode.'); self && self.close && self.close();</script>';
}
return $sResult;
}
/**
* @return string
*/
public function FacebookPopupService()
{
$sResult = '';
$sLoginUrl = '';
$sSocialName = '';
$mData = false;
$aUserData = false;
$bLogin = false;
$iErrorCode = \RainLoop\Notifications::UnknownError;
$sRedirectUrl = $this->oHttp->GetFullUrl().'?SocialFacebook';
if (0 < strlen($this->oActions->GetSpecAuthToken()))
{
$sRedirectUrl .= '&rlah='.$this->oActions->GetSpecAuthToken();
}
else if ($this->oHttp->HasQuery('rlah'))
{
$this->oActions->SetSpecAuthToken($this->oHttp->GetQuery('rlah', ''));
$sRedirectUrl .= '&rlah='.$this->oActions->GetSpecAuthToken();
}
try
{
$oAccount = $this->oActions->GetAccount();
$oFacebook = $this->FacebookConnector($oAccount ? $oAccount : null);
if ($oFacebook)
{
if ($oAccount)
{
$oUser = $oFacebook->getUser();
if (!$oUser && !$this->oHttp->HasQuery('state'))
{
$sLoginUrl = $oFacebook->getLoginUrl(array(
'display' => 'popup',
'redirect_uri' => $sRedirectUrl
));
}
else
{
try
{
$aData = $oFacebook->api(array(
'method' => 'fql.query',
'query' => 'SELECT uid, name, username FROM user WHERE uid = me()'
));
$mData = isset($aData[0], $aData[0]['uid']) ? $aData[0]['uid'] : false;
$sSocialName = !empty($aData[0]['name']) ? $aData[0]['name'] : '';
$sSocialName .= !empty($aData[0]['username']) ? ' ('.$aData[0]['username'].')' : '';
$sSocialName = \trim($sSocialName);
}
catch (\FacebookApiException $oException)
{
$this->oActions->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR);
}
if (false !== $mData && 0 < \strlen($mData))
{
$aUserData = array(
'Email' => $oAccount->Email(),
'Login' => $oAccount->Login(),
'Password' => $oAccount->Password()
);
$oSettings = $this->oActions->SettingsProvider()->Load($oAccount);
$oSettings->SetConf('FacebookSocialName', $sSocialName);
$this->oActions->SettingsProvider()->Save($oAccount, $oSettings);
$this->oActions->StorageProvider()->Put(null,
\RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY,
$this->FacebookUserLoginStorageKey($oFacebook, $mData),
\RainLoop\Utils::EncodeKeyValues($aUserData));
$iErrorCode = 0;
}
}
}
else
{
$bLogin = true;
$oUser = $oFacebook->getUser();
if ($oUser)
{
try
{
$aData = $oFacebook->api(array(
'method' => 'fql.query',
'query' => 'SELECT uid FROM user WHERE uid = me()'
));
$mData = isset($aData[0], $aData[0]['uid']) ? $aData[0]['uid'] : false;
}
catch (\FacebookApiException $oException)
{
}
if (false !== $mData && 0 < \strlen($mData))
{
$sUserData = $this->oActions->StorageProvider()->Get(null,
\RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY,
$this->FacebookUserLoginStorageKey($oFacebook, $mData));
if ($sUserData)
{
$aUserData = \RainLoop\Utils::DecodeKeyValues($sUserData);
}
}
if ($aUserData && \is_array($aUserData) &&
!empty($aUserData['Email']) &&
!empty($aUserData['Login']) &&
isset($aUserData['Password']))
{
$oAccount = $this->oActions->LoginProcess($aUserData['Email'], $aUserData['Login'], $aUserData['Password']);
if ($oAccount instanceof \RainLoop\Account)
{
$this->oActions->AuthProcess($oAccount);
$iErrorCode = 0;
}
}
else
{
$iErrorCode = \RainLoop\Notifications::SocialFacebookLoginAccessDisable;
}
}
else
{
$sLoginUrl = $oFacebook->getLoginUrl(array(
'display' => 'popup',
'redirect_uri' => $sRedirectUrl
));
}
}
}
}
catch (\Exception $oException)
{
$this->oActions->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR);
}
if ($sLoginUrl)
{
$this->oActions->Location($sLoginUrl);
}
else
{
@\header('Content-Type: text/html; charset=utf-8');
$sCallBackType = $bLogin ? '_login' : '';
$sConnectionFunc = 'rl_'.\md5(\RainLoop\Utils::GetConnectionToken()).'_facebook'.$sCallBackType.'_service';
$sResult = '<script>opener && opener.'.$sConnectionFunc.' && opener.'.
$sConnectionFunc.'('.$iErrorCode.'); self && self.close && self.close();</script>';
}
return $sResult;
}
/**
* @return string
*/
public function TwitterPopupService()
{
$sResult = '';
$sLoginUrl = '';
$sSocialName = '';
$bLogin = false;
$iErrorCode = \RainLoop\Notifications::UnknownError;
$sRedirectUrl = $this->oHttp->GetFullUrl().'?SocialTwitter';
if (0 < strlen($this->oActions->GetSpecAuthToken()))
{
$sRedirectUrl .= '&rlah='.$this->oActions->GetSpecAuthToken();
}
else if ($this->oHttp->HasQuery('rlah'))
{
$this->oActions->SetSpecAuthToken($this->oHttp->GetQuery('rlah', ''));
$sRedirectUrl .= '&rlah='.$this->oActions->GetSpecAuthToken();
}
try
{
$oTwitter = $this->TwitterConnector();
if ($oTwitter)
{
$sSessionKey = \implode('_', array('twitter',
\md5($oTwitter->config['consumer_secret']), \md5(\RainLoop\Utils::GetConnectionToken()), 'AuthSessionData'));
$oAccount = $this->oActions->GetAccount();
if ($oAccount)
{
if (isset($_REQUEST['oauth_verifier']))
{
$sAuth = $this->oActions->Cacher()->Get($sSessionKey);
$oAuth = $sAuth ? \json_decode($sAuth, true) : null;
if ($oAuth && !empty($oAuth['oauth_token']) && !empty($oAuth['oauth_token_secret']))
{
$oTwitter->config['user_token'] = $oAuth['oauth_token'];
$oTwitter->config['user_secret'] = $oAuth['oauth_token_secret'];
$iCode = $oTwitter->request('POST', $oTwitter->url('oauth/access_token', ''), array(
'oauth_callback' => $sRedirectUrl,
'oauth_verifier' => $_REQUEST['oauth_verifier']
));
if (200 === $iCode && isset($oTwitter->response['response']))
{
$this->oActions->Logger()->WriteDump($oTwitter->response['response']);
$aAccessToken = $oTwitter->extract_params($oTwitter->response['response']);
$this->oActions->Logger()->WriteDump($aAccessToken);
if ($aAccessToken && isset($aAccessToken['oauth_token']) && !empty($aAccessToken['user_id']))
{
$oTwitter->config['user_token'] = $aAccessToken['oauth_token'];
$oTwitter->config['user_secret'] = $aAccessToken['oauth_token_secret'];
$sSocialName = !empty($aAccessToken['screen_name']) ? '@'.$aAccessToken['screen_name'] : $aAccessToken['user_id'];
$sSocialName = \trim($sSocialName);
$aUserData = array(
'Email' => $oAccount->Email(),
'Login' => $oAccount->Login(),
'Password' => $oAccount->Password()
);
$oSettings = $this->oActions->SettingsProvider()->Load($oAccount);
$oSettings->SetConf('TwitterAccessToken', \RainLoop\Utils::EncodeKeyValues($aAccessToken));
$oSettings->SetConf('TwitterSocialName', $sSocialName);
$this->oActions->SettingsProvider()->Save($oAccount, $oSettings);
$this->oActions->StorageProvider()->Put(null,
\RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY,
$this->TwitterUserLoginStorageKey($oTwitter, $aAccessToken['user_id']),
\RainLoop\Utils::EncodeKeyValues($aUserData));
$iErrorCode = 0;
}
}
}
}
else
{
$aParams = array(
'oauth_callback' => $sRedirectUrl,
'x_auth_access_type' => 'read'
);
$iCode = $oTwitter->request('POST', $oTwitter->url('oauth/request_token', ''), $aParams);
if (200 === $iCode && isset($oTwitter->response['response']))
{
$oAuth = $oTwitter->extract_params($oTwitter->response['response']);
if (!empty($oAuth['oauth_token']))
{
$this->oActions->Cacher()->Set($sSessionKey, \json_encode($oAuth));
$sLoginUrl = $oTwitter->url('oauth/authenticate', '').'?oauth_token='.$oAuth['oauth_token'];
}
}
}
}
else
{
$bLogin = true;
if (isset($_REQUEST['oauth_verifier']))
{
$sAuth = $this->oActions->Cacher()->Get($sSessionKey);
$oAuth = $sAuth ? \json_decode($sAuth, true) : null;
if ($oAuth && !empty($oAuth['oauth_token']) && !empty($oAuth['oauth_token_secret']))
{
$oTwitter->config['user_token'] = $oAuth['oauth_token'];
$oTwitter->config['user_secret'] = $oAuth['oauth_token_secret'];
$iCode = $oTwitter->request('POST', $oTwitter->url('oauth/access_token', ''), array(
'oauth_callback' => $sRedirectUrl,
'oauth_verifier' => $_REQUEST['oauth_verifier']
));
if (200 === $iCode && isset($oTwitter->response['response']))
{
$aAccessToken = $oTwitter->extract_params($oTwitter->response['response']);
if ($aAccessToken && isset($aAccessToken['oauth_token']) && !empty($aAccessToken['user_id']))
{
$sUserData = $this->oActions->StorageProvider()->Get(null,
\RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY,
$this->TwitterUserLoginStorageKey($oTwitter, $aAccessToken['user_id'])
);
$aUserData = \RainLoop\Utils::DecodeKeyValues($sUserData);
if ($aUserData && \is_array($aUserData) &&
!empty($aUserData['Email']) &&
!empty($aUserData['Login']) &&
isset($aUserData['Password']))
{
$oAccount = $this->oActions->LoginProcess($aUserData['Email'], $aUserData['Login'], $aUserData['Password']);
if ($oAccount instanceof \RainLoop\Account)
{
$this->oActions->AuthProcess($oAccount);
$iErrorCode = 0;
}
}
else
{
$iErrorCode = \RainLoop\Notifications::SocialTwitterLoginAccessDisable;
}
$this->oActions->Cacher()->Delete($sSessionKey);
}
}
}
}
else
{
$aParams = array(
'oauth_callback' => $sRedirectUrl,
'x_auth_access_type' => 'read'
);
$iCode = $oTwitter->request('POST', $oTwitter->url('oauth/request_token', ''), $aParams);
if (200 === $iCode && isset($oTwitter->response['response']))
{
$oAuth = $oTwitter->extract_params($oTwitter->response['response']);
if (!empty($oAuth['oauth_token']))
{
$this->oActions->Cacher()->Set($sSessionKey, \json_encode($oAuth));
$sLoginUrl = $oTwitter->url('oauth/authenticate', '').'?oauth_token='.$oAuth['oauth_token'];
}
}
}
}
}
}
catch (\Exception $oException)
{
$this->oActions->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR);
}
if ($sLoginUrl)
{
$this->oActions->Location($sLoginUrl);
}
else
{
@\header('Content-Type: text/html; charset=utf-8');
$sCallBackType = $bLogin ? '_login' : '';
$sConnectionFunc = 'rl_'.\md5(\RainLoop\Utils::GetConnectionToken()).'_twitter'.$sCallBackType.'_service';
$sResult = '<script>opener && opener.'.$sConnectionFunc.' && opener.'.
$sConnectionFunc.'('.$iErrorCode.'); self && self.close && self.close();</script>';
}
return $sResult;
}
/**
* @return \OAuth2\Client|null
*/
public function GoogleConnector()
{
$oGoogle = false;
$oConfig = $this->oActions->Config();
if ($oConfig->Get('social', 'google_enable', false) &&
'' !== \trim($oConfig->Get('social', 'google_client_id', '')) &&
'' !== \trim($oConfig->Get('social', 'google_client_secret', '')))
{
include_once APP_VERSION_ROOT_PATH.'app/libraries/PHP-OAuth2/Client.php';
include_once APP_VERSION_ROOT_PATH.'app/libraries/PHP-OAuth2/GrantType/IGrantType.php';
include_once APP_VERSION_ROOT_PATH.'app/libraries/PHP-OAuth2/GrantType/AuthorizationCode.php';
include_once APP_VERSION_ROOT_PATH.'app/libraries/PHP-OAuth2/GrantType/RefreshToken.php';
try
{
$oGoogle = new \OAuth2\Client(
\trim($oConfig->Get('social', 'google_client_id', '')),
\trim($oConfig->Get('social', 'google_client_secret', '')));
}
catch (\Exception $oException)
{
$this->oActions->Logger()->WriteException($oException, \MailSo\Log\Enumerations\Type::ERROR);
}
}
return false === $oGoogle ? null : $oGoogle;
}
/**
* @return \tmhOAuth|null
*/
public function TwitterConnector()
{
$oTwitter = false;
$oConfig = $this->oActions->Config();
if ($oConfig->Get('social', 'twitter_enable', false) &&
'' !== \trim($oConfig->Get('social', 'twitter_consumer_key', '')) &&
'' !== \trim($oConfig->Get('social', 'twitter_consumer_secret', '')))
{
include_once APP_VERSION_ROOT_PATH.'app/libraries/tmhOAuth/tmhOAuth.php';
include_once APP_VERSION_ROOT_PATH.'app/libraries/tmhOAuth/tmhUtilities.php';
$oTwitter = new \tmhOAuth(array(
'consumer_key' => \trim($oConfig->Get('social', 'twitter_consumer_key', '')),
'consumer_secret' => \trim($oConfig->Get('social', 'twitter_consumer_secret', ''))
));
}
return false === $oTwitter ? null : $oTwitter;
}
/**
* @param \RainLoop\Account|null $oAccount = null
*
* @return \Facebook|null
*/
public function FacebookConnector($oAccount = null)
{
$oFacebook = false;
$oConfig = $this->oActions->Config();
if ($oConfig->Get('social', 'fb_enable', false) &&
'' !== \trim($oConfig->Get('social', 'fb_app_id', '')) &&
'' !== \trim($oConfig->Get('social', 'fb_app_secret', '')))
{
include_once APP_VERSION_ROOT_PATH.'app/libraries/facebook/facebook.php';
$oFacebook = new \RainLoopFacebook(array(
'rlAccount' => $oAccount,
'rlUserHash' => \RainLoop\Utils::GetConnectionToken(),
'rlStorageProvaider' => $this->oActions->StorageProvider(),
'appId' => \trim($oConfig->Get('social', 'fb_app_id', '')),
'secret' => \trim($oConfig->Get('social', 'fb_app_secret', '')),
'fileUpload' => false,
'cookie' => true
));
}
return false === $oFacebook ? null : $oFacebook;
}
/**
* @return string
*/
public function GoogleUserLoginStorageKey($oGoogle, $sGoogleUserId)
{
return \implode('_', array('google', \md5($oGoogle->getClientId()), $sGoogleUserId, APP_SALT));
}
/**
* @return string
*/
public function FacebookUserLoginStorageKey($oFacebook, $sFacebookUserId)
{
return \implode('_', array('facebook', \md5($oFacebook->getAppId()), $sFacebookUserId, APP_SALT));
}
/**
* @return string
*/
public function TwitterUserLoginStorageKey($oTwitter, $sTwitterUserId)
{
return \implode('_', array('twitter', \md5($oTwitter->config['consumer_secret']), $sTwitterUserId, APP_SALT));
}
}

View file

@ -0,0 +1,409 @@
<?php
namespace RainLoop;
class Utils
{
static $Cookies = null;
/**
* @return void
*/
private function __construct()
{
}
/**
* @param string $sString
* @param string $sKey
*
* @return string
*/
static public function EncryptString($sString, $sKey)
{
return \MailSo\Base\Crypt::XxteaEncrypt($sString, $sKey);
}
/**
* @param string $sEncriptedString
* @param string $sKey
*
* @return string
*/
static public function DecryptString($sEncriptedString, $sKey)
{
return \MailSo\Base\Crypt::XxteaDecrypt($sEncriptedString, $sKey);
}
/**
* @param array $aValues
* @param string $sCustomKey = ''
*
* @return string
*/
static public function EncodeKeyValues(array $aValues, $sCustomKey = '')
{
return \MailSo\Base\Utils::UrlSafeBase64Encode(
\RainLoop\Utils::EncryptString(\serialize($aValues), \md5(APP_SALT.$sCustomKey)));
}
/**
* @param string $sEncodedValues
* @param string $sCustomKey = ''
*
* @return array
*/
static public function DecodeKeyValues($sEncodedValues, $sCustomKey = '')
{
$aResult = \unserialize(
\RainLoop\Utils::DecryptString(
\MailSo\Base\Utils::UrlSafeBase64Decode($sEncodedValues), \md5(APP_SALT.$sCustomKey)));
return \is_array($aResult) ? $aResult : array();
}
/**
* @return string
*/
static public function GetConnectionToken()
{
$sKey = 'rltoken';
$sToken = \RainLoop\Utils::GetCookie($sKey, null);
if (null === $sToken)
{
$sToken = \md5(\rand(10000, 99999).\microtime(true).APP_SALT);
\RainLoop\Utils::SetCookie($sKey, $sToken, \time() + 60 * 60 * 24 * 30, '/', null, null, true);
}
return \md5('Connection'.APP_SALT.$sToken.'Token'.APP_SALT);
}
/**
* @return string
*/
static public function GetShortToken()
{
$sKey = 'rlsession';
$sToken = \RainLoop\Utils::GetCookie($sKey, null);
if (null === $sToken)
{
$sToken = \md5(\rand(10000, 99999).\microtime(true).APP_SALT);
\RainLoop\Utils::SetCookie($sKey, $sToken, 0, '/', null, null, true);
}
return \md5('Session'.APP_SALT.$sToken.'Token'.APP_SALT);
}
/**
* @return void
*/
static public function UpdateConnectionToken()
{
$sKey = 'rltoken';
$sToken = \RainLoop\Utils::GetCookie($sKey, '');
if (!empty($sToken))
{
\RainLoop\Utils::SetCookie($sKey, $sToken, \time() + 60 * 60 * 24 * 30, '/', null, null, true);
}
}
/**
* @return string
*/
static public function GetCsrfToken()
{
return \md5('Csrf'.APP_SALT.self::GetConnectionToken().'Token'.APP_SALT);
}
/**
* @param string $sPath
*
* @return string
*/
public static function PathMD5($sPath)
{
$sResult = '';
if (@\is_dir($sPath))
{
$oDirIterator = new \RecursiveDirectoryIterator($sPath);
$oIterator = new \RecursiveIteratorIterator($oDirIterator, \RecursiveIteratorIterator::SELF_FIRST);
foreach ($oIterator as $oFile)
{
$sResult = \md5($sResult.($oFile->isFile() ? \md5_file($oFile) : $oFile));
}
}
return $sResult;
}
/**
* @param string $FileName
* @param array $aResultLang
*
* @return void
*/
public static function ReadAndAddLang($FileName, &$aResultLang)
{
if (\file_exists($FileName))
{
$aLang = @\parse_ini_file($FileName, true);
if (\is_array($aLang))
{
foreach ($aLang as $sKey => $mValue)
{
if (\is_array($mValue))
{
foreach ($mValue as $sSecKey => $mSecValue)
{
$aResultLang[$sKey.'/'.$sSecKey] = $mSecValue;
}
}
else
{
$aResultLang[$sKey] = $mValue;
}
}
}
}
}
/**
* @param string $sDir
* @param string $sType = ''
* @return array
*/
public static function FolderFiles($sDir, $sType = '')
{
$aResult = array();
if (@\is_dir($sDir))
{
if (false !== ($rDirHandle = @\opendir($sDir)))
{
while (false !== ($sFile = @\readdir($rDirHandle)))
{
if (empty($sType) || $sType === \substr($sFile, -\strlen($sType)))
{
if (\is_file($sDir.'/'.$sFile))
{
$aResult[] = $sFile;
}
}
}
@\closedir($rDirHandle);
}
}
return $aResult;
}
/**
* @param string $sHtml
*
* @return string
*/
public static function ClearHtmlOutput($sHtml)
{
// return $sHtml;
return \str_replace('> <', '><',
\preg_replace('/[\s]+&nbsp;/i', '&nbsp;',
\preg_replace('/&nbsp;[\s]+/i', '&nbsp;',
\preg_replace('/[\r\n\t]+/', ' ',
$sHtml
))));
}
/**
* @param string $sKey
* @return bool
*/
public static function FastCheck($sKey)
{
$bResult = false;
$aMatches = array();
if (!empty($sKey) && 0 < \strlen($sKey) && \preg_match('/^(RL[\d]+)\-(.+)\-([^\-]+)$/', $sKey, $aMatches) && 3 === \count($aMatches))
{
$bResult = $aMatches[3] === \strtoupper(\base_convert(\crc32(\md5(
$aMatches[1].'-'.$aMatches[2].'-')), 10, 32));
}
return $bResult;
}
/**
* @param string $sDirName
*
* @return string
*/
public static function CompileTemplates($sDirName, $oAction)
{
$sResult = '';
if (\file_exists($sDirName))
{
$aList = \RainLoop\Utils::FolderFiles($sDirName, '.html');
foreach ($aList as $sName)
{
$sTemplateName = \substr($sName, 0, -5);
$sResult .= '<script id="'.\preg_replace('/[^a-zA-Z0-9]/', '', $sTemplateName).'" type="text/html">'.
$oAction->ProcessTemplate($sTemplateName, \file_get_contents($sDirName.'/'.$sName)).'</script>';
}
$sResult = \trim($sResult);
}
return $sResult;
}
/**
* @param string $sName
* @param mixed $mDefault = null
* @return mixed
*/
public static function GetCookie($sName, $mDefault = null)
{
if (null === self::$Cookies)
{
self::$Cookies = is_array($_COOKIE) ? $_COOKIE : array();
}
return isset(self::$Cookies[$sName]) ? self::$Cookies[$sName] : $mDefault;
}
public static function SetCookie($sName, $sValue = '', $iExpire = 0, $sPath = '/', $sDomain = '', $sSecure = false, $bHttpOnly = false)
{
if (null === self::$Cookies)
{
self::$Cookies = is_array($_COOKIE) ? $_COOKIE : array();
}
self::$Cookies[$sName] = $sValue;
@\setcookie($sName, $sValue, $iExpire, $sPath, $sDomain, $sSecure, $bHttpOnly);
}
public static function ClearCookie($sName)
{
if (null === self::$Cookies)
{
self::$Cookies = is_array($_COOKIE) ? $_COOKIE : array();
}
unset(self::$Cookies[$sName]);
@\setcookie($sName, '', \time() - 3600 * 24 * 30, '/');
}
/**
* @return array
*/
public static function ServicesPics()
{
return array(
'ebay.com' => 'ebay.jpg',
'reply.ebay.com' => 'ebay.jpg',
'reply1.ebay.com' => 'ebay.jpg',
'reply2.ebay.com' => 'ebay.jpg',
'reply3.ebay.com' => 'ebay.jpg',
'facebook.com' => 'facebook.png',
'facebookmail.com' => 'facebook.png',
'cnet.online.com' => 'cnet.jpg',
'github.com' => 'github.png',
'steampowered.com' => 'steam.png',
'myspace.com' => 'myspace.png',
'new.myspace.com' => 'myspace.png',
'youtube.com' => 'youtube.gif',
'amazon.com' => 'amazon.png',
'ted.com' => 'ted.png',
'icloud.com' => 'icloud.jpg',
'google.com' => 'google.png',
'plus.google.com' => 'google-plus.png',
'email.microsoft.com' => 'microsoft.jpg',
'microsoftonline.com' => 'microsoft.jpg',
'microsoft.com' => 'microsoft.jpg',
'paypal.com' => 'paypal.jpg',
'intl.paypal.com' => 'paypal.jpg',
'e.paypal.com' => 'paypal.jpg',
'ea.com' => 'ea.png',
'em.ea.com' => 'ea.png',
'battlefieldheroes.com' => 'ea.png',
'battle.net' => 'battle.net.png',
'blizzard.com' => 'battle.net.png',
'email.blizzard.com' => 'battle.net.png',
'battlefieldheroes.com' => 'battle.net.png',
'twitter.com' => 'twitter.jpg',
'postmaster.twitter.com' => 'twitter.jpg',
'skype.com' => 'skype.png',
'email.skype.com' => 'skype.png',
'apple.com' => 'apple.jpg',
'id.apple.com' => 'apple.jpg',
'onlive.com' => 'onlive.png',
'news.onlive.com' => 'onlive.png',
'asana.com' => 'asana.png',
'connect.asana.com' => 'asana.png',
);
}
public static function CustomBaseConvert($sNumberInput, $sFromBaseInput = '0123456789', $sToBaseInput = '0123456789')
{
if ($sFromBaseInput === $sToBaseInput)
{
return $sNumberInput;
}
$mFromBase = \str_split($sFromBaseInput, 1);
$mToBase = \str_split($sToBaseInput, 1);
$aNumber = \str_split($sNumberInput, 1);
$iFromLen = \strlen($sFromBaseInput);
$iToLen = \strlen($sToBaseInput);
$numberLen = \strlen($sNumberInput);
$mRetVal = '';
if ($sToBaseInput === '0123456789')
{
$mRetVal = 0;
for ($iIndex = 1; $iIndex <= $numberLen; $iIndex++)
{
$mRetVal = \bcadd($mRetVal, \bcmul(\array_search($aNumber[$iIndex - 1], $mFromBase), \bcpow($iFromLen, $numberLen - $iIndex)));
}
return $mRetVal;
}
if ($sFromBaseInput != '0123456789')
{
$sBase10 = \RainLoop\Utils::CustomBaseConvert($sNumberInput, $sFromBaseInput, '0123456789');
}
else
{
$sBase10 = $sNumberInput;
}
if ($sBase10 < \strlen($sToBaseInput))
{
return $mToBase[$sBase10];
}
while ($sBase10 !== '0')
{
$mRetVal = $mToBase[\bcmod($sBase10, $iToLen)].$mRetVal;
$sBase10 = \bcdiv($sBase10, $iToLen, 0);
}
return $mRetVal;
}
}