mirror of
https://github.com/the-djmaze/snappymail.git
synced 2025-01-01 04:22:15 +08:00
Many fixes
New ownCloud package with a built-in webmail
This commit is contained in:
parent
323dd34c8b
commit
6116597f6f
56 changed files with 1137 additions and 232 deletions
|
@ -1,26 +1,23 @@
|
|||
************************************************************************
|
||||
*
|
||||
* ownCloud - RainLoop Webmail mail plugin
|
||||
*
|
||||
* @author RainLoop Team
|
||||
* @copyright 2014 RainLoop Team
|
||||
*
|
||||
* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud
|
||||
*
|
||||
************************************************************************
|
||||
|
||||
REQUIREMENTS:
|
||||
- Installed and configured RainLoop Webmail (standalone)
|
||||
- ownCloud version 6 or higher
|
||||
- Both apps (RainLoop & ownCloud) running on the same domain
|
||||
|
||||
|
||||
INSTALL:
|
||||
- Unpack the RainLoop Webmail application package in the apps directory of your OwnCloud instance
|
||||
|
||||
|
||||
CONFIGURATION:
|
||||
- ownCloud:
|
||||
1) In the Apps > Enable 'RainLoop' plugin
|
||||
2) In the Settings > Admin > Enter "RainLoop Webmail URL" and "Absolute (full) path to RainLoop Webmail installation"
|
||||
3) In the Settings > Personal > Type your mail server email (login) and password
|
||||
************************************************************************
|
||||
*
|
||||
* ownCloud - RainLoop Webmail package
|
||||
*
|
||||
* @author RainLoop Team
|
||||
* @copyright 2015 RainLoop Team
|
||||
*
|
||||
* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud
|
||||
*
|
||||
************************************************************************
|
||||
|
||||
REQUIREMENTS:
|
||||
- ownCloud version 6 or higher
|
||||
|
||||
|
||||
INSTALL:
|
||||
- Unpack the RainLoop Webmail application package in the apps directory of your OwnCloud instance
|
||||
|
||||
|
||||
CONFIGURATION:
|
||||
- ownCloud:
|
||||
1) In the Apps > Enable 'RainLoop' plugin
|
||||
2) In the Settings > Personal > Type your mail server email (login) and password
|
||||
|
|
|
@ -1,20 +1,32 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* ownCloud - RainLoop mail plugin
|
||||
*
|
||||
* @author RainLoop Team
|
||||
* @copyright 2014 RainLoop Team
|
||||
*
|
||||
* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud
|
||||
*/
|
||||
|
||||
OCP\User::checkAdminUser();
|
||||
|
||||
OCP\Util::addScript('rainloop', 'admin');
|
||||
|
||||
$oTemplate = new OCP\Template('rainloop', 'admin');
|
||||
$oTemplate->assign('rainloop-url', OCP\Config::getAppValue('rainloop', 'rainloop-url', ''));
|
||||
$oTemplate->assign('rainloop-path', OCP\Config::getAppValue('rainloop', 'rainloop-path', ''));
|
||||
$oTemplate->assign('rainloop-autologin', OCP\Config::getAppValue('rainloop', 'rainloop-autologin', false));
|
||||
return $oTemplate->fetchPage();
|
||||
<?php
|
||||
|
||||
/**
|
||||
* ownCloud - RainLoop mail plugin
|
||||
*
|
||||
* @author RainLoop Team
|
||||
* @copyright 2015 RainLoop Team
|
||||
*
|
||||
* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud
|
||||
*/
|
||||
|
||||
OCP\User::checkAdminUser();
|
||||
|
||||
OCP\Util::addScript('rainloop', 'admin');
|
||||
|
||||
$bInstalledLocaly = file_exists(__DIR__.'/app/index.php');
|
||||
if ($bInstalledLocaly)
|
||||
{
|
||||
$oTemplate = new OCP\Template('rainloop', 'admin-local');
|
||||
$oTemplate->assign('rainloop-admin-panel-link',
|
||||
OC_RainLoop_Helper::getAppUrl().'?admin');
|
||||
}
|
||||
else
|
||||
{
|
||||
$oTemplate = new OCP\Template('rainloop', 'admin');
|
||||
$oTemplate->assign('rainloop-admin-panel-link', '');
|
||||
$oTemplate->assign('rainloop-url', OCP\Config::getAppValue('rainloop', 'rainloop-url', ''));
|
||||
$oTemplate->assign('rainloop-path', OCP\Config::getAppValue('rainloop', 'rainloop-path', ''));
|
||||
}
|
||||
|
||||
$oTemplate->assign('rainloop-autologin', OCP\Config::getAppValue('rainloop', 'rainloop-autologin', false));
|
||||
return $oTemplate->fetchPage();
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* ownCloud - RainLoop mail plugin
|
||||
*
|
||||
* @author RainLoop Team
|
||||
* @copyright 2014 RainLoop Team
|
||||
* @copyright 2015 RainLoop Team
|
||||
*
|
||||
* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud
|
||||
*/
|
||||
|
@ -17,22 +17,32 @@ $sUrl = '';
|
|||
$sPath = '';
|
||||
$bAutologin = false;
|
||||
|
||||
if (isset($_POST['appname'], $_POST['rainloop-url'], $_POST['rainloop-path']) && 'rainloop' === $_POST['appname'])
|
||||
$bInstalledLocaly = file_exists(__DIR__.'/../app/index.php');
|
||||
|
||||
if (isset($_POST['appname']) && 'rainloop' === $_POST['appname'] &&
|
||||
($bInstalledLocaly ? true : isset($_POST['rainloop-url'], $_POST['rainloop-path'])))
|
||||
{
|
||||
OCP\Config::setAppValue('rainloop', 'rainloop-url', $_POST['rainloop-url']);
|
||||
OCP\Config::setAppValue('rainloop', 'rainloop-path', $_POST['rainloop-path']);
|
||||
OCP\Config::setAppValue('rainloop', 'rainloop-autologin', isset($_POST['rainloop-autologin']) ?
|
||||
'1' === $_POST['rainloop-autologin'] : false);
|
||||
|
||||
$sUrl = OCP\Config::getAppValue('rainloop', 'rainloop-url', '');
|
||||
$sPath = OCP\Config::getAppValue('rainloop', 'rainloop-path', '');
|
||||
if (!$bInstalledLocaly)
|
||||
{
|
||||
OCP\Config::setAppValue('rainloop', 'rainloop-url', $_POST['rainloop-url']);
|
||||
OCP\Config::setAppValue('rainloop', 'rainloop-path', $_POST['rainloop-path']);
|
||||
|
||||
$sUrl = OCP\Config::getAppValue('rainloop', 'rainloop-url', '');
|
||||
$sPath = OCP\Config::getAppValue('rainloop', 'rainloop-path', '');
|
||||
}
|
||||
|
||||
$bAutologin = OCP\Config::getAppValue('rainloop', 'rainloop-autologin', false);
|
||||
}
|
||||
else
|
||||
{
|
||||
sleep(1);
|
||||
OC_JSON::error(array('Message' => 'Invalid Argument(s)', 'Url' => $sUrl, 'Path' => $sPath));
|
||||
return false;
|
||||
}
|
||||
|
||||
sleep(1);
|
||||
OCP\JSON::success(array('Message' => 'Saved successfully', 'Url' => $sUrl, 'Path' => $sPath));
|
||||
return true;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* ownCloud - RainLoop mail plugin
|
||||
*
|
||||
* @author RainLoop Team
|
||||
* @copyright 2014 RainLoop Team
|
||||
* @copyright 2015 RainLoop Team
|
||||
*
|
||||
* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud
|
||||
*/
|
||||
|
@ -37,9 +37,11 @@ if (isset($_POST['appname'], $_POST['rainloop-password'], $_POST['rainloop-email
|
|||
}
|
||||
else
|
||||
{
|
||||
sleep(1);
|
||||
OC_JSON::error(array('Message' => 'Invalid argument(s)', 'Email' => $sEmail));
|
||||
return false;
|
||||
}
|
||||
|
||||
sleep(1);
|
||||
OCP\JSON::success(array('Message' => 'Saved successfully', 'Email' => $sEmail));
|
||||
return true;
|
||||
|
|
10
build/owncloud/rainloop-app/app.php
Normal file
10
build/owncloud/rainloop-app/app.php
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
if (@file_exists(__DIR__.'/app/index.php'))
|
||||
{
|
||||
include_once OC_App::getAppPath('rainloop').'/lib/RainLoopHelper.php';
|
||||
|
||||
OC_RainLoop_Helper::regRainLoopDataFunction();
|
||||
|
||||
include __DIR__.'/app/index.php';
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
* ownCloud - RainLoop mail plugin
|
||||
*
|
||||
* @author RainLoop Team
|
||||
* @copyright 2014 RainLoop Team
|
||||
* @copyright 2015 RainLoop Team
|
||||
*
|
||||
* https://github.com/RainLoop/owncloud
|
||||
*/
|
||||
|
|
|
@ -2,7 +2,10 @@
|
|||
<info>
|
||||
<id>rainloop</id>
|
||||
<name>RainLoop</name>
|
||||
<description>RainLoop Webmail</description>
|
||||
<description>Simple, modern & fast web-based email client.
|
||||
|
||||
Modest system requirements, decent performance, simple installation and upgrade, no database required -
|
||||
all these make RainLoop Webmail a perfect choice for your email solution.</description>
|
||||
<version>0.0</version>
|
||||
<licence>CC BY-NC-SA 3.0</licence>
|
||||
<author>RainLoop Team</author>
|
||||
|
|
13
build/owncloud/rainloop-app/appinfo/routes.php
Normal file
13
build/owncloud/rainloop-app/appinfo/routes.php
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
$this->create('rainloop_index', '/')
|
||||
->actionInclude('rainloop/index.php');
|
||||
|
||||
$this->create('rainloop_app', '/app/')
|
||||
->actionInclude('rainloop/app.php');
|
||||
|
||||
$this->create('rainloop_ajax_personal', 'ajax/personal.php')
|
||||
->actionInclude('rainloop/ajax/personal.php');
|
||||
|
||||
$this->create('rainloop_ajax_admin', 'ajax/admin.php')
|
||||
->actionInclude('rainloop/ajax/admin.php');
|
|
@ -4,7 +4,7 @@
|
|||
* ownCloud - RainLoop mail plugin
|
||||
*
|
||||
* @author RainLoop Team
|
||||
* @copyright 2014 RainLoop Team
|
||||
* @copyright 2015 RainLoop Team
|
||||
*
|
||||
* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud
|
||||
*/
|
||||
|
@ -13,8 +13,23 @@ OCP\User::checkLoggedIn();
|
|||
OCP\App::checkAppEnabled('rainloop');
|
||||
OCP\App::setActiveNavigationEntry('rainloop_index');
|
||||
|
||||
$sUrl = trim(OCP\Config::getAppValue('rainloop', 'rainloop-url', ''));
|
||||
$sPath = trim(OCP\Config::getAppValue('rainloop', 'rainloop-path', ''));
|
||||
include_once OC_App::getAppPath('rainloop').'/lib/RainLoopHelper.php';
|
||||
|
||||
$sUrl = '';
|
||||
$sPath = '';
|
||||
|
||||
$bInstalledLocaly = file_exists(__DIR__.'/app/index.php');
|
||||
if ($bInstalledLocaly)
|
||||
{
|
||||
$sUrl = OC_RainLoop_Helper::getAppUrl();
|
||||
$sPath = __DIR__.'/app/';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sUrl = trim(OCP\Config::getAppValue('rainloop', 'rainloop-url', ''));
|
||||
$sPath = trim(OCP\Config::getAppValue('rainloop', 'rainloop-path', ''));
|
||||
}
|
||||
|
||||
$bAutologin = OCP\Config::getAppValue('rainloop', 'rainloop-autologin', false);
|
||||
|
||||
if ('' === $sUrl || '' === $sPath)
|
||||
|
@ -23,10 +38,6 @@ if ('' === $sUrl || '' === $sPath)
|
|||
}
|
||||
else
|
||||
{
|
||||
include_once OC_App::getAppPath('rainloop').'/lib/RainLoopHelper.php';
|
||||
|
||||
OC_Config::setValue('xframe_restriction', false);
|
||||
|
||||
$sUser = OCP\User::getUser();
|
||||
|
||||
if ($bAutologin)
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
|
||||
/**
|
||||
* ownCloud - RainLoop mail plugin
|
||||
*
|
||||
* @author RainLoop Team
|
||||
* @copyright 2014 RainLoop Team
|
||||
*
|
||||
* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud
|
||||
*/
|
||||
|
||||
$(function() {
|
||||
RainLoopFormHelper('#mail-rainloop-admin-form', 'admin.php');
|
||||
});
|
||||
|
||||
/**
|
||||
* ownCloud - RainLoop mail plugin
|
||||
*
|
||||
* @author RainLoop Team
|
||||
* @copyright 2015 RainLoop Team
|
||||
*
|
||||
* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud
|
||||
*/
|
||||
|
||||
$(function() {
|
||||
RainLoopFormHelper('#mail-rainloop-admin-form', 'admin.php');
|
||||
});
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
|
||||
/**
|
||||
* ownCloud - RainLoop mail plugin
|
||||
*
|
||||
* @author RainLoop Team
|
||||
* @copyright 2014 RainLoop Team
|
||||
*
|
||||
* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud
|
||||
*/
|
||||
|
||||
$(function() {
|
||||
RainLoopFormHelper('#mail-rainloop-personal-form', 'personal.php');
|
||||
});
|
||||
|
||||
/**
|
||||
* ownCloud - RainLoop mail plugin
|
||||
*
|
||||
* @author RainLoop Team
|
||||
* @copyright 2015 RainLoop Team
|
||||
*
|
||||
* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud
|
||||
*/
|
||||
|
||||
$(function() {
|
||||
RainLoopFormHelper('#mail-rainloop-personal-form', 'personal.php');
|
||||
});
|
||||
|
|
|
@ -2,6 +2,18 @@
|
|||
|
||||
class OC_RainLoop_Helper
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function getAppUrl()
|
||||
{
|
||||
$sRequestUri = empty($_SERVER['REQUEST_URI']) ? '': trim($_SERVER['REQUEST_URI']);
|
||||
$sRequestUri = preg_replace('/index.php\/.+$/', 'index.php/', $sRequestUri);
|
||||
$sRequestUri = $sRequestUri.'apps/rainloop/app/';
|
||||
|
||||
return '/'.ltrim($sRequestUri, '/\\');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sPath
|
||||
* @param string $sEmail
|
||||
|
@ -16,6 +28,8 @@ class OC_RainLoop_Helper
|
|||
$sPath = rtrim(trim($sPath), '\\/').'/index.php';
|
||||
if (file_exists($sPath))
|
||||
{
|
||||
self::regRainLoopDataFunction();
|
||||
|
||||
$_ENV['RAINLOOP_INCLUDE_AS_API'] = true;
|
||||
include $sPath;
|
||||
|
||||
|
@ -124,4 +138,102 @@ class OC_RainLoop_Helper
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function regRainLoopDataFunction()
|
||||
{
|
||||
if (!@function_exists('__get_custom_data_full_path'))
|
||||
{
|
||||
$_ENV['RAINLOOP_OWNCLOUD'] = true;
|
||||
|
||||
function __get_custom_data_full_path()
|
||||
{
|
||||
$sData = __DIR__.'/../../data/';
|
||||
if (class_exists('OC_Config'))
|
||||
{
|
||||
$sData = rtrim(trim(OC_Config::getValue('datadirectory', '')), '\\/').'/';
|
||||
}
|
||||
|
||||
return @is_dir($sData) ? $sData.'rainloop-storage' : '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function mimeContentType($filename) {
|
||||
|
||||
$mime_types = array(
|
||||
|
||||
'woff' => 'application/font-woff',
|
||||
|
||||
'txt' => 'text/plain',
|
||||
'htm' => 'text/html',
|
||||
'html' => 'text/html',
|
||||
'php' => 'text/html',
|
||||
'css' => 'text/css',
|
||||
'js' => 'application/javascript',
|
||||
'json' => 'application/json',
|
||||
'xml' => 'application/xml',
|
||||
'swf' => 'application/x-shockwave-flash',
|
||||
'flv' => 'video/x-flv',
|
||||
|
||||
// images
|
||||
'png' => 'image/png',
|
||||
'jpe' => 'image/jpeg',
|
||||
'jpeg' => 'image/jpeg',
|
||||
'jpg' => 'image/jpeg',
|
||||
'gif' => 'image/gif',
|
||||
'bmp' => 'image/bmp',
|
||||
'ico' => 'image/vnd.microsoft.icon',
|
||||
'tiff' => 'image/tiff',
|
||||
'tif' => 'image/tiff',
|
||||
'svg' => 'image/svg+xml',
|
||||
'svgz' => 'image/svg+xml',
|
||||
|
||||
// archives
|
||||
'zip' => 'application/zip',
|
||||
'rar' => 'application/x-rar-compressed',
|
||||
'exe' => 'application/x-msdownload',
|
||||
'msi' => 'application/x-msdownload',
|
||||
'cab' => 'application/vnd.ms-cab-compressed',
|
||||
|
||||
// audio/video
|
||||
'mp3' => 'audio/mpeg',
|
||||
'qt' => 'video/quicktime',
|
||||
'mov' => 'video/quicktime',
|
||||
|
||||
// adobe
|
||||
'pdf' => 'application/pdf',
|
||||
'psd' => 'image/vnd.adobe.photoshop',
|
||||
'ai' => 'application/postscript',
|
||||
'eps' => 'application/postscript',
|
||||
'ps' => 'application/postscript',
|
||||
|
||||
// ms office
|
||||
'doc' => 'application/msword',
|
||||
'rtf' => 'application/rtf',
|
||||
'xls' => 'application/vnd.ms-excel',
|
||||
'ppt' => 'application/vnd.ms-powerpoint',
|
||||
|
||||
// open office
|
||||
'odt' => 'application/vnd.oasis.opendocument.text',
|
||||
'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
|
||||
);
|
||||
|
||||
if (0 < strpos($filename, '.'))
|
||||
{
|
||||
$ext = strtolower(array_pop(explode('.',$filename)));
|
||||
if (array_key_exists($ext, $mime_types))
|
||||
{
|
||||
return $mime_types[$ext];
|
||||
}
|
||||
else if (function_exists('finfo_open'))
|
||||
{
|
||||
$finfo = finfo_open(FILEINFO_MIME);
|
||||
$mimetype = finfo_file($finfo, $filename);
|
||||
finfo_close($finfo);
|
||||
return $mimetype;
|
||||
}
|
||||
}
|
||||
|
||||
return 'application/octet-stream';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* ownCloud - RainLoop mail plugin
|
||||
*
|
||||
* @author RainLoop Team
|
||||
* @copyright 2014 RainLoop Team
|
||||
* @copyright 2015 RainLoop Team
|
||||
*
|
||||
* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud
|
||||
*/
|
||||
|
@ -14,11 +14,19 @@ OCP\App::checkAppEnabled('rainloop');
|
|||
|
||||
OCP\Util::addScript('rainloop', 'personal');
|
||||
|
||||
$sUrl = trim(OCP\Config::getAppValue('rainloop', 'rainloop-url', ''));
|
||||
$sPath = trim(OCP\Config::getAppValue('rainloop', 'rainloop-path', ''));
|
||||
$sUrl = '';
|
||||
$sPath = '';
|
||||
|
||||
$bAutologin = OCP\Config::getAppValue('rainloop', 'rainloop-autologin', false);
|
||||
|
||||
if ($bAutologin || '' === $sUrl || '' === $sPath)
|
||||
$bInstalledLocaly = file_exists(__DIR__.'/app/index.php');
|
||||
if (!$bInstalledLocaly)
|
||||
{
|
||||
$sUrl = trim(OCP\Config::getAppValue('rainloop', 'rainloop-url', ''));
|
||||
$sPath = trim(OCP\Config::getAppValue('rainloop', 'rainloop-path', ''));
|
||||
}
|
||||
|
||||
if ($bAutologin || (!$bInstalledLocaly && ('' === $sUrl || '' === $sPath)))
|
||||
{
|
||||
$oTemplate = new OCP\Template('rainloop', 'empty');
|
||||
}
|
||||
|
|
29
build/owncloud/rainloop-app/templates/admin-local.php
Normal file
29
build/owncloud/rainloop-app/templates/admin-local.php
Normal file
|
@ -0,0 +1,29 @@
|
|||
<div class="section">
|
||||
<form id="mail-rainloop-admin-form" action="#" method="post">
|
||||
<input type="hidden" name="requesttoken" value="<?php echo $_['requesttoken'] ?>" id="requesttoken">
|
||||
<input type="hidden" name="appname" value="rainloop">
|
||||
|
||||
<fieldset class="personalblock">
|
||||
<h2><?php p($l->t('RainLoop Webmail')); ?></h2>
|
||||
<br />
|
||||
<?php if ($_['rainloop-admin-panel-link']): ?>
|
||||
<p>
|
||||
<a href="<?php echo $_['rainloop-admin-panel-link'] ?>" target="_blank" style="text-decoration: underline">
|
||||
<?php p($l->t('Go to RainLoop Webmail admin panel')); ?>
|
||||
</a>
|
||||
</p>
|
||||
<br />
|
||||
<?php endif; ?>
|
||||
<p>
|
||||
<input type="checkbox" id="rainloop-autologin" id="rainloop-autologin" name="rainloop-autologin" value="1" <?php if ($_['rainloop-autologin']): ?>checked="checked"<?php endif; ?> />
|
||||
<label for="rainloop-autologin">
|
||||
<?php p($l->t('Automatically login with ownCloud user credentials')); ?>
|
||||
</label>
|
||||
<br />
|
||||
<br />
|
||||
<input type="button" id="rainloop-save-button" name="rainloop-save-button" value="<?php p($l->t('Save')); ?>" />
|
||||
<span class="rainloop-result-desc"></span>
|
||||
</p>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
|
@ -50,6 +50,37 @@
|
|||
}
|
||||
});
|
||||
|
||||
Globals.$win.on('resize', function () {
|
||||
Events.pub('window.resize');
|
||||
});
|
||||
|
||||
Events.sub('window.resize', _.throttle(function () {
|
||||
|
||||
var
|
||||
iH = Globals.$win.height(),
|
||||
iW = Globals.$win.height()
|
||||
;
|
||||
|
||||
if (Globals.$win.__sizes[0] !== iH || Globals.$win.__sizes[1] !== iW)
|
||||
{
|
||||
Globals.$win.__sizes[0] = iH;
|
||||
Globals.$win.__sizes[1] = iW;
|
||||
|
||||
Events.pub('window.resize.real');
|
||||
}
|
||||
|
||||
}, 50));
|
||||
|
||||
// TODO
|
||||
// Events.sub({
|
||||
// 'window.resize': function () {
|
||||
// window.console.log('window.resize');
|
||||
// },
|
||||
// 'window.resize.real': function () {
|
||||
// window.console.log('window.resize.real');
|
||||
// }
|
||||
// });
|
||||
|
||||
Globals.$doc.on('keydown', function (oEvent) {
|
||||
if (oEvent && oEvent.ctrlKey)
|
||||
{
|
||||
|
@ -315,6 +346,8 @@
|
|||
|
||||
ssm.ready();
|
||||
|
||||
|
||||
|
||||
require('Stores/Language').populate();
|
||||
require('Stores/Theme').populate();
|
||||
require('Stores/Social').populate();
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
MessageModel = require('Model/Message'),
|
||||
AccountModel = require('Model/Account'),
|
||||
IdentityModel = require('Model/Identity'),
|
||||
TemplateModel = require('Model/Template'),
|
||||
OpenPgpKeyModel = require('Model/OpenPgpKey'),
|
||||
|
||||
AbstractApp = require('App/Abstract')
|
||||
|
@ -611,12 +612,10 @@
|
|||
{
|
||||
Utils.delegateRunOnDestroy(TemplateStore.templates());
|
||||
|
||||
IdentityStore.templates(_.map(oData.Result['Templates'], function (oIdentityData) {
|
||||
return {
|
||||
'id': Utils.pString(oIdentityData['Id']),
|
||||
'name': Utils.pString(oIdentityData['Name'])
|
||||
};
|
||||
}));
|
||||
TemplateStore.templates(_.compact(_.map(oData.Result['Templates'], function (oTemplateData) {
|
||||
var oTemplate = new TemplateModel();
|
||||
return oTemplate.parse(oTemplateData) ? oTemplate : null;
|
||||
})));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
'Sieve': 'SIEVE',
|
||||
'Filters': 'FILTERS',
|
||||
'AttachmentThumbnails': 'ATTACHMENT_THUMBNAILS',
|
||||
'Templates': 'TEMPLATES',
|
||||
'AdditionalAccounts': 'ADDITIONAL_ACCOUNTS'
|
||||
};
|
||||
|
||||
|
|
|
@ -28,12 +28,24 @@
|
|||
*/
|
||||
Events.prototype.sub = function (sName, fFunc, oContext)
|
||||
{
|
||||
if (Utils.isUnd(this.oSubs[sName]))
|
||||
if (Utils.isObject(sName))
|
||||
{
|
||||
this.oSubs[sName] = [];
|
||||
}
|
||||
oContext = fFunc || null;
|
||||
fFunc = null;
|
||||
|
||||
this.oSubs[sName].push([fFunc, oContext]);
|
||||
_.each(sName, function (fSubFunc, sSubName) {
|
||||
this.sub(sSubName, fSubFunc, oContext);
|
||||
}, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Utils.isUnd(this.oSubs[sName]))
|
||||
{
|
||||
this.oSubs[sName] = [];
|
||||
}
|
||||
|
||||
this.oSubs[sName].push([fFunc, oContext]);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
Globals.$html = $('html');
|
||||
Globals.$div = $('<div></div>');
|
||||
|
||||
Globals.$win.__sizes = [0, 0];
|
||||
|
||||
/**
|
||||
* @type {?}
|
||||
*/
|
||||
|
@ -255,7 +257,7 @@
|
|||
});
|
||||
|
||||
Globals.keyScopeReal.subscribe(function (sValue) {
|
||||
// window.console.log(sValue);
|
||||
// window.console.log(sValue); //TODO
|
||||
key.setScope(sValue);
|
||||
});
|
||||
|
||||
|
|
|
@ -106,8 +106,13 @@
|
|||
.replace("\u0002", '').replace("\u0002", '')
|
||||
.replace("\u0003", '').replace("\u0003", '')
|
||||
.replace("\u0003", '').replace("\u0003", '')
|
||||
.replace("\u0004", '').replace("\u0004", '')
|
||||
.replace("\u0004", '').replace("\u0004", '')
|
||||
.replace("\u0005", '').replace("\u0005", '')
|
||||
.replace("\u0005", '').replace("\u0005", '')
|
||||
;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {boolean=} bWrapIsHtml = false
|
||||
* @param {boolean=} bClearSignatureSigns = false
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
Utils.trim = $.trim;
|
||||
Utils.inArray = $.inArray;
|
||||
Utils.isArray = _.isArray;
|
||||
Utils.isObject = _.isObject;
|
||||
Utils.isFunc = _.isFunction;
|
||||
Utils.isUnd = _.isUndefined;
|
||||
Utils.isNull = _.isNull;
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
AbstractModel.prototype.onDestroy = function ()
|
||||
{
|
||||
Utils.disposeObject(this);
|
||||
// window.console.log('onDestroy: ' + this.sModelName);
|
||||
// window.console.log('onDestroy: ' + this.sModelName); // TODO
|
||||
};
|
||||
|
||||
module.exports = AbstractModel;
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
_ = require('_'),
|
||||
ko = require('ko'),
|
||||
|
||||
Utils = require('Common/Utils'),
|
||||
|
||||
AbstractModel = require('Knoin/AbstractModel')
|
||||
;
|
||||
|
||||
|
@ -24,6 +26,7 @@
|
|||
this.id = sID;
|
||||
this.name = sName;
|
||||
this.body = sBody;
|
||||
this.populated = true;
|
||||
|
||||
this.deleteAccess = ko.observable(false);
|
||||
}
|
||||
|
@ -45,6 +48,30 @@
|
|||
*/
|
||||
TemplateModel.prototype.body = '';
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
*/
|
||||
TemplateModel.prototype.populated = true;
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
*/
|
||||
TemplateModel.prototype.parse = function (oItem)
|
||||
{
|
||||
var bResult = false;
|
||||
if (oItem && 'Object/Template' === oItem['@Object'])
|
||||
{
|
||||
this.id = Utils.pString(oItem['ID']);
|
||||
this.name = Utils.pString(oItem['Name']);
|
||||
this.body = Utils.pString(oItem['Body']);
|
||||
this.populated = !!oItem['Populated'];
|
||||
|
||||
bResult = true;
|
||||
}
|
||||
|
||||
return bResult;
|
||||
};
|
||||
|
||||
module.exports = TemplateModel;
|
||||
|
||||
}());
|
|
@ -85,8 +85,11 @@
|
|||
'SettingsChangePassword', 'SETTINGS_LABELS/LABEL_CHANGE_PASSWORD_NAME', 'change-password');
|
||||
}
|
||||
|
||||
// kn.addSettingsViewModel(require('Settings/User/Templates'),
|
||||
// 'SettingsTemplates', 'SETTINGS_LABELS/LABEL_TEMPLATES_NAME', 'templates');
|
||||
if (Settings.capa(Enums.Capa.Templates))
|
||||
{
|
||||
kn.addSettingsViewModel(require('Settings/User/Templates'),
|
||||
'SettingsTemplates', 'SETTINGS_LABELS/LABEL_TEMPLATES_NAME', 'templates');
|
||||
}
|
||||
|
||||
kn.addSettingsViewModel(require('Settings/User/Folders'),
|
||||
'SettingsFolders', 'SETTINGS_LABELS/LABEL_FOLDERS_NAME', 'folders');
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
this.capaGravatar = CapaAdminStore.gravatar;
|
||||
this.capaAdditionalAccounts = CapaAdminStore.additionalAccounts;
|
||||
this.capaAttachmentThumbnails = CapaAdminStore.attachmentThumbnails;
|
||||
this.capaTemplates = CapaAdminStore.templates;
|
||||
|
||||
this.allowLanguagesOnSettings = AppAdminStore.allowLanguagesOnSettings;
|
||||
this.weakPassword = AppAdminStore.weakPassword;
|
||||
|
@ -105,6 +106,12 @@
|
|||
});
|
||||
});
|
||||
|
||||
self.capaTemplates.subscribe(function (bValue) {
|
||||
Remote.saveAdminConfig(null, {
|
||||
'CapaTemplates': bValue ? '1' : '0'
|
||||
});
|
||||
});
|
||||
|
||||
self.capaGravatar.subscribe(function (bValue) {
|
||||
Remote.saveAdminConfig(null, {
|
||||
'CapaGravatar': bValue ? '1' : '0'
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
ko = require('ko'),
|
||||
|
||||
Enums = require('Common/Enums'),
|
||||
Utils = require('Common/Utils'),
|
||||
Translator = require('Common/Translator'),
|
||||
Links = require('Common/Links'),
|
||||
|
||||
|
|
|
@ -293,7 +293,17 @@
|
|||
/**
|
||||
* @param {?Function} fCallback
|
||||
*/
|
||||
RemoteUserStorage.prototype.templateGetById = function (fCallback, sID, sName, sBody)
|
||||
RemoteUserStorage.prototype.templateDelete = function (fCallback, sID)
|
||||
{
|
||||
this.defaultRequest(fCallback, 'TemplateDelete', {
|
||||
'IdToDelete': sID
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {?Function} fCallback
|
||||
*/
|
||||
RemoteUserStorage.prototype.templateSetup = function (fCallback, sID, sName, sBody)
|
||||
{
|
||||
this.defaultRequest(fCallback, 'TemplateSetup', {
|
||||
'ID': sID,
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
this.userBackground = ko.observable(false);
|
||||
this.openPGP = ko.observable(false);
|
||||
this.twoFactorAuth = ko.observable(false);
|
||||
this.templates = ko.observable(false);
|
||||
}
|
||||
|
||||
CapaAdminStore.prototype.populate = function()
|
||||
|
@ -38,6 +39,7 @@
|
|||
this.userBackground(Settings.capa(Enums.Capa.UserBackground));
|
||||
this.openPGP(Settings.capa(Enums.Capa.OpenPGP));
|
||||
this.twoFactorAuth(Settings.capa(Enums.Capa.TwoFactor));
|
||||
this.templates(Settings.capa(Enums.Capa.Templates));
|
||||
};
|
||||
|
||||
module.exports = new CapaAdminStore();
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
|
||||
var
|
||||
_ = require('_'),
|
||||
ko = require('ko'),
|
||||
ko = require('ko')
|
||||
|
||||
Remote = require('Storage/User/Remote')
|
||||
// Remote = require('Storage/User/Remote')
|
||||
;
|
||||
|
||||
/**
|
||||
|
@ -27,16 +27,16 @@
|
|||
})));
|
||||
}, this);
|
||||
|
||||
this.templatesNames.subscribe(function (aList) {
|
||||
if (this.templatesNames.skipFirst)
|
||||
{
|
||||
this.templatesNames.skipFirst = false;
|
||||
}
|
||||
else if (aList && 1 < aList.length)
|
||||
{
|
||||
Remote.templatesSortOrder(null, aList);
|
||||
}
|
||||
}, this);
|
||||
// this.templatesNames.subscribe(function (aList) {
|
||||
// if (this.templatesNames.skipFirst)
|
||||
// {
|
||||
// this.templatesNames.skipFirst = false;
|
||||
// }
|
||||
// else if (aList && 1 < aList.length)
|
||||
// {
|
||||
// Remote.templatesSortOrder(null, aList);
|
||||
// }
|
||||
// }, this);
|
||||
}
|
||||
|
||||
module.exports = new TemplateUserStore();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
.b-settings-identities {
|
||||
.b-settings-templates {
|
||||
|
||||
.process-place {
|
||||
text-align: center;
|
||||
|
|
|
@ -2,11 +2,15 @@
|
|||
.b-template-add-content {
|
||||
|
||||
&.modal {
|
||||
width: 700px;
|
||||
width: 750px;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.e-template-place {
|
||||
height: 300px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@
|
|||
this.bFromDraft = false;
|
||||
this.sReferences = '';
|
||||
|
||||
this.triggerForResize = _.bind(this.triggerForResize, this);
|
||||
this.resizerTrigger = _.bind(this.resizerTrigger, this);
|
||||
|
||||
this.allowContacts = !!AppStore.contactsIsAllowed();
|
||||
|
||||
|
@ -90,8 +90,6 @@
|
|||
|
||||
this.capaOpenPGP = PgpStore.capaOpenPGP;
|
||||
|
||||
this.resizer = ko.observable(false).extend({'throttle': 50});
|
||||
|
||||
this.identitiesDropdownTrigger = ko.observable(false);
|
||||
|
||||
this.to = ko.observable('');
|
||||
|
@ -241,11 +239,13 @@
|
|||
}
|
||||
}, this);
|
||||
|
||||
this.editorResizeThrottle = _.throttle(_.bind(this.editorResize, this), 100);
|
||||
this.resizer = ko.observable(false).extend({'throttle': 50});
|
||||
|
||||
this.resizer.subscribe(function () {
|
||||
this.editorResizeThrottle();
|
||||
}, this);
|
||||
this.resizer.subscribe(_.bind(function () {
|
||||
if (this.oEditor){
|
||||
this.oEditor.resize();
|
||||
}
|
||||
}, this));
|
||||
|
||||
this.canBeSendedOrSaved = ko.computed(function () {
|
||||
return !this.sending() && !this.saving();
|
||||
|
@ -429,9 +429,9 @@
|
|||
}
|
||||
}, this);
|
||||
|
||||
this.showCc.subscribe(this.triggerForResize);
|
||||
this.showBcc.subscribe(this.triggerForResize);
|
||||
this.showReplyTo.subscribe(this.triggerForResize);
|
||||
this.showCc.subscribe(this.resizerTrigger);
|
||||
this.showBcc.subscribe(this.resizerTrigger);
|
||||
this.showReplyTo.subscribe(this.resizerTrigger);
|
||||
|
||||
this.dropboxEnabled = SocialStore.dropbox.enabled;
|
||||
this.dropboxApiKey = SocialStore.dropbox.apiKey;
|
||||
|
@ -1230,7 +1230,7 @@
|
|||
this.currentIdentity(oIdentity);
|
||||
}
|
||||
|
||||
this.triggerForResize();
|
||||
this.resizerTrigger();
|
||||
};
|
||||
|
||||
ComposePopupView.prototype.onFocus = function ()
|
||||
|
@ -1244,15 +1244,7 @@
|
|||
this.oEditor.focus();
|
||||
}
|
||||
|
||||
this.triggerForResize();
|
||||
};
|
||||
|
||||
ComposePopupView.prototype.editorResize = function ()
|
||||
{
|
||||
if (this.oEditor)
|
||||
{
|
||||
this.oEditor.resize();
|
||||
}
|
||||
this.resizerTrigger();
|
||||
};
|
||||
|
||||
ComposePopupView.prototype.tryToClosePopup = function ()
|
||||
|
@ -1315,7 +1307,7 @@
|
|||
return false;
|
||||
});
|
||||
|
||||
Globals.$win.on('resize', self.triggerForResize);
|
||||
Events.sub('window.resize.real', this.resizerTrigger);
|
||||
|
||||
if (this.dropboxEnabled())
|
||||
{
|
||||
|
@ -2034,10 +2026,9 @@
|
|||
});
|
||||
};
|
||||
|
||||
ComposePopupView.prototype.triggerForResize = function ()
|
||||
ComposePopupView.prototype.resizerTrigger = function ()
|
||||
{
|
||||
this.resizer(!this.resizer());
|
||||
this.editorResizeThrottle();
|
||||
};
|
||||
|
||||
module.exports = ComposePopupView;
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
this.name.focus = ko.observable(false);
|
||||
|
||||
this.body = ko.observable('');
|
||||
this.body.loading = ko.observable(false);
|
||||
this.body.error = ko.observable(false);
|
||||
|
||||
this.name.subscribe(function () {
|
||||
|
@ -51,6 +52,8 @@
|
|||
|
||||
this.addTemplateCommand = Utils.createCommand(this, function () {
|
||||
|
||||
this.populateBodyFromEditor();
|
||||
|
||||
this.name.error('' === Utils.trim(this.name()));
|
||||
this.body.error('' === Utils.trim(this.body()) ||
|
||||
':HTML:' === Utils.trim(this.body()));
|
||||
|
@ -109,40 +112,52 @@
|
|||
|
||||
this.submitRequest(false);
|
||||
this.submitError('');
|
||||
|
||||
if (this.editor)
|
||||
{
|
||||
this.setBody('');
|
||||
}
|
||||
};
|
||||
|
||||
TemplatePopupView.prototype.setBody = function (sBody)
|
||||
{
|
||||
if (this.editor)
|
||||
{
|
||||
if (':HTML:' === sBody.substr(0, 6))
|
||||
{
|
||||
this.editor.setHtml(sBody.substr(6), false);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.editor.setPlain(sBody, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TemplatePopupView.prototype.populateBodyFromEditor = function ()
|
||||
{
|
||||
if (this.editor)
|
||||
{
|
||||
this.body(
|
||||
(this.editor.isHtml() ? ':HTML:' : '') + this.editor.getData()
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
TemplatePopupView.prototype.editorSetBody = function (sBody)
|
||||
{
|
||||
var
|
||||
self = this,
|
||||
fEditorSetData = function (sBody) {
|
||||
if (self.editor)
|
||||
{
|
||||
if (':HTML:' === sBody.substr(0, 6))
|
||||
{
|
||||
self.editor.setHtml(sBody.substr(6), false);
|
||||
}
|
||||
else
|
||||
{
|
||||
self.editor.setPlain(sBody, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
if (!this.editor && this.signatureDom())
|
||||
{
|
||||
var self = this;
|
||||
this.editor = new HtmlEditor(self.signatureDom(), function () {
|
||||
self.body(
|
||||
(self.editor.isHtml() ? ':HTML:' : '') + self.editor.getData()
|
||||
);
|
||||
self.populateBodyFromEditor();
|
||||
}, function () {
|
||||
fEditorSetData(sBody);
|
||||
self.setBody(sBody);
|
||||
});
|
||||
}
|
||||
else if (this.editor)
|
||||
else
|
||||
{
|
||||
fEditorSetData(sBody);
|
||||
this.setBody(sBody);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -156,16 +171,44 @@
|
|||
{
|
||||
this.id(oTemplate.id);
|
||||
this.name(oTemplate.name);
|
||||
this.body(oTemplate.body);
|
||||
|
||||
this.body.loading(true);
|
||||
if (oTemplate.populated)
|
||||
{
|
||||
self.editorSetBody(this.body());
|
||||
}
|
||||
else
|
||||
{
|
||||
this.body.loading(true);
|
||||
self.body.error(false);
|
||||
|
||||
Remote.templateGetById(function () {
|
||||
Remote.templateGetById(function (sResult, oData) {
|
||||
|
||||
self.body.loading(false);
|
||||
self.body.loading(false);
|
||||
|
||||
self.editorSetBody('');
|
||||
if (Enums.StorageResultType.Success === sResult && oData && oData.Result &&
|
||||
'Object/Template' === oData.Result['@Object'] && Utils.isNormal(oData.Result['Body']))
|
||||
{
|
||||
oTemplate.body = oData.Result['Body'];
|
||||
oTemplate.populated = true;
|
||||
|
||||
}, this.id());
|
||||
self.body(oTemplate.body);
|
||||
self.body.error(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
self.body('');
|
||||
self.body.error(true);
|
||||
}
|
||||
|
||||
self.editorSetBody(self.body());
|
||||
|
||||
}, this.id());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self.editorSetBody('');
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -423,11 +423,11 @@
|
|||
this.showFullInfo.subscribe(fCheckHeaderHeight);
|
||||
this.message.subscribe(fCheckHeaderHeight);
|
||||
|
||||
Globals.$win.on('resize', function () {
|
||||
Events.sub('window.resize', _.throttle(function () {
|
||||
_.delay(fCheckHeaderHeight, 1);
|
||||
_.delay(fCheckHeaderHeight, 200);
|
||||
_.delay(fCheckHeaderHeight, 500);
|
||||
});
|
||||
}, 50));
|
||||
|
||||
this.showFullInfo.subscribe(function () {
|
||||
Utils.windowResize();
|
||||
|
|
34
gulpfile.js
34
gulpfile.js
|
@ -7,6 +7,7 @@ var
|
|||
devVersion: '0.0.0',
|
||||
releasesPath: 'build/dist/releases',
|
||||
|
||||
rainloopBuilded: false,
|
||||
destPath: '',
|
||||
cleanPath: '',
|
||||
zipSrcPath: '',
|
||||
|
@ -459,6 +460,8 @@ gulp.task('rainloop:setup', ['rainloop:copy'], function() {
|
|||
cfg.zipSrcPath = dist;
|
||||
cfg.zipFile = 'rainloop-' + versionFull + '.zip';
|
||||
cfg.md5File = cfg.zipFile;
|
||||
|
||||
cfg.rainloopBuilded = true;
|
||||
});
|
||||
|
||||
gulp.task('rainloop:zip', ['rainloop:copy', 'rainloop:setup'], function() {
|
||||
|
@ -490,7 +493,28 @@ gulp.task('rainloop:owncloud:copy', function() {
|
|||
.pipe(gulp.dest(dist + 'rainloop'));
|
||||
});
|
||||
|
||||
gulp.task('rainloop:owncloud:setup', ['rainloop:owncloud:copy'], function() {
|
||||
gulp.task('rainloop:owncloud:copy-rainloop', ['rainloop:start', 'rainloop:owncloud:copy'], function() {
|
||||
|
||||
var
|
||||
versionFull = pkg.ownCloudPackageVersion,
|
||||
dist = cfg.releasesPath + '/owncloud/' + versionFull + '/src/rainloop/'
|
||||
;
|
||||
|
||||
if (cfg.rainloopBuilded && cfg.destPath)
|
||||
{
|
||||
return gulp.src(cfg.destPath + '/src/**/*', {base: cfg.destPath + '/src/'})
|
||||
.pipe(gulp.dest(dist + 'app/'));
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
gulp.task('rainloop:owncloud:copy-rainloop:clean', ['rainloop:owncloud:copy-rainloop'], function() {
|
||||
return (cfg.cleanPath) ? cleanDir(cfg.cleanPath) : false;
|
||||
});
|
||||
|
||||
gulp.task('rainloop:owncloud:setup', ['rainloop:owncloud:copy',
|
||||
'rainloop:owncloud:copy-rainloop'], function() {
|
||||
|
||||
var
|
||||
versionFull = pkg.ownCloudPackageVersion,
|
||||
|
@ -529,8 +553,12 @@ gulp.task('rainloop:owncloud:clean', ['rainloop:owncloud:copy', 'rainloop:ownclo
|
|||
gulp.task('default', ['js:libs', 'js:boot', 'js:openpgp', 'js:min', 'css:main:min', 'ckeditor', 'fontastic']);
|
||||
gulp.task('fast', ['js:app', 'js:admin', 'js:chunks', 'css:main']);
|
||||
|
||||
gulp.task('rainloop', ['js:lint', 'rainloop:copy', 'rainloop:setup', 'rainloop:zip', 'rainloop:md5', 'rainloop:clean']);
|
||||
gulp.task('owncloud', ['rainloop:owncloud:copy', 'rainloop:owncloud:setup', 'rainloop:owncloud:zip', 'rainloop:owncloud:md5', 'rainloop:owncloud:clean']);
|
||||
gulp.task('rainloop:start', ['js:lint', 'rainloop:copy', 'rainloop:setup']);
|
||||
gulp.task('rainloop', ['rainloop:start', 'rainloop:zip', 'rainloop:md5', 'rainloop:clean']);
|
||||
|
||||
gulp.task('owncloud', ['rainloop:owncloud:copy',
|
||||
'rainloop:owncloud:copy-rainloop',
|
||||
'rainloop:owncloud:setup', 'rainloop:owncloud:zip', 'rainloop:owncloud:md5', 'rainloop:owncloud:clean']);
|
||||
|
||||
//WATCH
|
||||
gulp.task('watch', ['fast'], function() {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"name": "RainLoop",
|
||||
"title": "RainLoop Webmail",
|
||||
"version": "1.8.0",
|
||||
"release": "251",
|
||||
"version": "1.8.1",
|
||||
"release": "255",
|
||||
"description": "Simple, modern & fast web-based email client",
|
||||
"homepage": "http://rainloop.net",
|
||||
"main": "gulpfile.js",
|
||||
|
@ -36,7 +36,7 @@
|
|||
"plugins"
|
||||
],
|
||||
"readmeFilename": "README.md",
|
||||
"ownCloudPackageVersion": "2.3",
|
||||
"ownCloudPackageVersion": "3.0",
|
||||
"engines": {
|
||||
"node": ">= 0.10.0"
|
||||
},
|
||||
|
|
|
@ -263,7 +263,6 @@ class Http
|
|||
*/
|
||||
public function GetHeader($sHeader)
|
||||
{
|
||||
$sResultHeader = '';
|
||||
$sServerKey = 'HTTP_'.\strtoupper(\str_replace('-', '_', $sHeader));
|
||||
$sResultHeader = $this->GetServer($sServerKey, '');
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ class SubStreams
|
|||
\stream_wrapper_register(self::STREAM_NAME, '\MailSo\Base\StreamWrappers\SubStreams');
|
||||
}
|
||||
|
||||
$sHashName = \md5(\microtime(true).\rand(1000, 9999));
|
||||
$sHashName = \MailSo\Base\Utils::Md5Rand();
|
||||
|
||||
self::$aStreams[$sHashName] = $aSubStreams;
|
||||
|
||||
|
@ -84,7 +84,7 @@ class SubStreams
|
|||
{
|
||||
return $this->aSubStreams[$this->iIndex];
|
||||
}
|
||||
|
||||
|
||||
return $nNull;
|
||||
}
|
||||
|
||||
|
|
|
@ -2147,6 +2147,28 @@ class Utils
|
|||
return \is_string($mResult) && 0 < \strlen($mResult) ? $mResult : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sAdditionalSalt = ''
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function Md5Rand($sAdditionalSalt = '')
|
||||
{
|
||||
return \md5(\microtime(true).\rand(10000, 99999).
|
||||
\md5($sAdditionalSalt).\rand(10000, 99999).\microtime(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sAdditionalSalt = ''
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function Sha1Rand($sAdditionalSalt = '')
|
||||
{
|
||||
return \sha1(\microtime(true).\rand(10000, 99999).
|
||||
\sha1($sAdditionalSalt).\rand(10000, 99999).\microtime(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sData
|
||||
* @param string $sKey
|
||||
|
|
|
@ -121,7 +121,7 @@ class Logger extends \MailSo\Base\Collection
|
|||
static $sCache = null;
|
||||
if (null === $sCache)
|
||||
{
|
||||
$sCache = \substr(\md5(\microtime(true).\rand(10000, 99999)), -8);
|
||||
$sCache = \substr(\MailSo\Base\Utils::Md5Rand(), -8);
|
||||
}
|
||||
|
||||
return $sCache;
|
||||
|
|
|
@ -990,7 +990,7 @@ class MailClient
|
|||
{
|
||||
do
|
||||
{
|
||||
$sKey = \md5(\rand(10000, 90000).\microtime(true));
|
||||
$sKey = \MailSo\Base\Utils::Md5Rand();
|
||||
}
|
||||
while (isset($aCache[$sKey]));
|
||||
|
||||
|
@ -1006,7 +1006,7 @@ class MailClient
|
|||
{
|
||||
do
|
||||
{
|
||||
$sKey = \md5(\rand(10000, 90000).\microtime(true));
|
||||
$sKey = \MailSo\Base\Utils::Md5Rand();
|
||||
}
|
||||
while (isset($aCache[$sKey]));
|
||||
|
||||
|
|
|
@ -535,8 +535,9 @@ class Message
|
|||
$sHostName = 'localhost';
|
||||
}
|
||||
|
||||
return '<'.\md5(\rand(100000, 999999).\time().$sHostName.
|
||||
(\MailSo\Base\Utils::FunctionExistsAndEnabled('getmypid') ? @\getmypid() : '')).'@'.$sHostName.'>';
|
||||
return '<'.
|
||||
\MailSo\Base\Utils::Md5Rand($sHostName.
|
||||
(\MailSo\Base\Utils::FunctionExistsAndEnabled('getmypid') ? @\getmypid() : '')).'@'.$sHostName.'>';
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1511,7 +1511,7 @@ class Actions
|
|||
$aResult['UseLocalProxyForExternalImages'] = (bool) $oConfig->Get('labs', 'use_local_proxy_for_external_images', false);
|
||||
|
||||
// user
|
||||
$aResult['ShowImages'] = (bool) $oConfig->Get('webmail', 'show_images', false);
|
||||
$aResult['ShowImages'] = (bool) $oConfig->Get('defaults', 'show_images', false);
|
||||
$aResult['MPP'] = (int) $oConfig->Get('webmail', 'messages_per_page', 25);
|
||||
$aResult['SoundNotification'] = false;
|
||||
$aResult['DesktopNotifications'] = false;
|
||||
|
@ -1982,7 +1982,7 @@ class Actions
|
|||
*/
|
||||
private function generateSignMeToken($sEmail)
|
||||
{
|
||||
return \md5(\microtime(true).APP_SALT.\rand(10000, 99999).$sEmail);
|
||||
return \MailSo\Base\Utils::Md5Rand(APP_SALT.$sEmail);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2122,6 +2122,85 @@ class Actions
|
|||
return $aAccounts;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Model\Account $oAccount
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function GetTemplates($oAccount)
|
||||
{
|
||||
$aTemplates = array();
|
||||
if ($oAccount)
|
||||
{
|
||||
$aData = array();
|
||||
|
||||
$sData = $this->StorageProvider(true)->Get($oAccount,
|
||||
\RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
|
||||
'templates'
|
||||
);
|
||||
|
||||
if ('' !== $sData && '[' === \substr($sData, 0, 1))
|
||||
{
|
||||
$aData = @\json_decode($sData, true);
|
||||
}
|
||||
|
||||
if (\is_array($aData) && 0 < \count($aData))
|
||||
{
|
||||
foreach ($aData as $aItem)
|
||||
{
|
||||
$oItem = \RainLoop\Model\Template::NewInstance();
|
||||
$oItem->FromJSON($aItem);
|
||||
|
||||
if ($oItem && $oItem->Validate())
|
||||
{
|
||||
\array_push($aTemplates, $oItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (1 < \count($aTemplates))
|
||||
{
|
||||
$sOrder = $this->StorageProvider()->Get($oAccount,
|
||||
\RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
|
||||
'templates_order'
|
||||
);
|
||||
|
||||
$aOrder = empty($sOrder) ? array() : @\json_decode($sOrder, true);
|
||||
if (\is_array($aOrder) && 1 < \count($aOrder))
|
||||
{
|
||||
\usort($aTemplates, function ($a, $b) use ($aOrder) {
|
||||
return \array_search($a->Id(), $aOrder) < \array_search($b->Id(), $aOrder) ? -1 : 1;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $aTemplates;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Model\Account $oAccount
|
||||
* @param string $sID
|
||||
*
|
||||
* @return \RainLoop\Model\Identity
|
||||
*/
|
||||
public function GetTemplateByID($oAccount, $sID)
|
||||
{
|
||||
$aTemplates = $this->GetTemplates($oAccount);
|
||||
if (\is_array($aTemplates))
|
||||
{
|
||||
foreach ($aTemplates as $oIdentity)
|
||||
{
|
||||
if ($oIdentity && $sID === $oIdentity->Id())
|
||||
{
|
||||
return $oIdentity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return isset($aTemplates[0]) ? $aTemplates[0] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Model\Account $oAccount
|
||||
*
|
||||
|
@ -2279,6 +2358,27 @@ class Actions
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Model\Account $oAccount
|
||||
* @param array $aTemplates = array()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function SetTemplates($oAccount, $aTemplates = array())
|
||||
{
|
||||
$aResult = array();
|
||||
foreach ($aTemplates as $oItem)
|
||||
{
|
||||
$aResult[] = $oItem->ToSimpleJSON(false);
|
||||
}
|
||||
|
||||
return $this->StorageProvider(true)->Put($oAccount,
|
||||
\RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
|
||||
'templates',
|
||||
@\json_encode($aResult)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*
|
||||
|
@ -2497,6 +2597,117 @@ class Actions
|
|||
return $this->DefaultResponse(__FUNCTION__, $this->SetIdentities($oAccount, $aNew));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*
|
||||
* @throws \MailSo\Base\Exceptions\Exception
|
||||
*/
|
||||
public function DoTemplateSetup()
|
||||
{
|
||||
$oAccount = $this->getAccountFromToken();
|
||||
|
||||
if (!$this->GetCapa(false, \RainLoop\Enumerations\Capa::TEMPLATES, $oAccount))
|
||||
{
|
||||
return $this->FalseResponse(__FUNCTION__);
|
||||
}
|
||||
|
||||
$oTemplate = \RainLoop\Model\Template::NewInstance();
|
||||
if (!$oTemplate->FromJSON($this->GetActionParams(), true))
|
||||
{
|
||||
throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::InvalidInputArgument);
|
||||
}
|
||||
|
||||
if ('' === $oTemplate->Id())
|
||||
{
|
||||
$oTemplate->GenerateID();
|
||||
}
|
||||
|
||||
$aTemplatesForSave = array();
|
||||
$aTemplates = $this->GetTemplates($oAccount);
|
||||
|
||||
|
||||
foreach ($aTemplates as $oItem)
|
||||
{
|
||||
if ($oItem && $oItem->Id() !== $oTemplate->Id())
|
||||
{
|
||||
$aTemplatesForSave[] = $oItem;
|
||||
}
|
||||
}
|
||||
|
||||
$aTemplatesForSave[] = $oTemplate;
|
||||
|
||||
return $this->DefaultResponse(__FUNCTION__, $this->SetTemplates($oAccount, $aTemplatesForSave));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*
|
||||
* @throws \MailSo\Base\Exceptions\Exception
|
||||
*/
|
||||
public function DoTemplateDelete()
|
||||
{
|
||||
$oAccount = $this->getAccountFromToken();
|
||||
|
||||
if (!$this->GetCapa(false, \RainLoop\Enumerations\Capa::TEMPLATES, $oAccount))
|
||||
{
|
||||
return $this->FalseResponse(__FUNCTION__);
|
||||
}
|
||||
|
||||
$sId = \trim($this->GetActionParam('IdToDelete', ''));
|
||||
if (empty($sId))
|
||||
{
|
||||
throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::UnknownError);
|
||||
}
|
||||
|
||||
$aNew = array();
|
||||
$aTemplates = $this->GetTemplates($oAccount);
|
||||
foreach ($aTemplates as $oItem)
|
||||
{
|
||||
if ($oItem && $sId !== $oItem->Id())
|
||||
{
|
||||
$aNew[] = $oItem;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->DefaultResponse(__FUNCTION__, $this->SetTemplates($oAccount, $aNew));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*
|
||||
* @throws \MailSo\Base\Exceptions\Exception
|
||||
*/
|
||||
public function DoTemplateGetByID()
|
||||
{
|
||||
$oAccount = $this->getAccountFromToken();
|
||||
|
||||
if (!$this->GetCapa(false, \RainLoop\Enumerations\Capa::TEMPLATES, $oAccount))
|
||||
{
|
||||
return $this->FalseResponse(__FUNCTION__);
|
||||
}
|
||||
|
||||
$sId = \trim($this->GetActionParam('ID', ''));
|
||||
if (empty($sId))
|
||||
{
|
||||
throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::UnknownError);
|
||||
}
|
||||
|
||||
$oTemplate = false;
|
||||
$aTemplates = $this->GetTemplates($oAccount);
|
||||
|
||||
foreach ($aTemplates as $oItem)
|
||||
{
|
||||
if ($oItem && $sId === $oItem->Id())
|
||||
{
|
||||
$oTemplate = $oItem;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$oTemplate->SetPopulateAlways(true);
|
||||
return $this->DefaultResponse(__FUNCTION__, $oTemplate);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*
|
||||
|
@ -2550,6 +2761,25 @@ class Actions
|
|||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*
|
||||
* @throws \MailSo\Base\Exceptions\Exception
|
||||
*/
|
||||
public function DoTemplates()
|
||||
{
|
||||
$oAccount = $this->getAccountFromToken();
|
||||
|
||||
if (!$this->GetCapa(false, \RainLoop\Enumerations\Capa::TEMPLATES, $oAccount))
|
||||
{
|
||||
return $this->FalseResponse(__FUNCTION__);
|
||||
}
|
||||
|
||||
return $this->DefaultResponse(__FUNCTION__, array(
|
||||
'Templates' => $this->GetTemplates($oAccount)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sHash
|
||||
*
|
||||
|
@ -2821,6 +3051,9 @@ class Actions
|
|||
case \RainLoop\Enumerations\Capa::ADDITIONAL_ACCOUNTS:
|
||||
$this->setConfigFromParams($oConfig, $sParamName, 'webmail', 'allow_additional_accounts', 'bool');
|
||||
break;
|
||||
case \RainLoop\Enumerations\Capa::TEMPLATES:
|
||||
$this->setConfigFromParams($oConfig, $sParamName, 'capa', 'templates', 'bool');
|
||||
break;
|
||||
case \RainLoop\Enumerations\Capa::TWO_FACTOR:
|
||||
$this->setConfigFromParams($oConfig, $sParamName, 'security', 'allow_two_factor_auth', 'bool');
|
||||
break;
|
||||
|
@ -2923,6 +3156,7 @@ class Actions
|
|||
});
|
||||
|
||||
$this->setCapaFromParams($oConfig, 'CapaAdditionalAccounts', \RainLoop\Enumerations\Capa::ADDITIONAL_ACCOUNTS);
|
||||
$this->setCapaFromParams($oConfig, 'CapaTemplates', \RainLoop\Enumerations\Capa::TEMPLATES);
|
||||
$this->setCapaFromParams($oConfig, 'CapaTwoFactorAuth', \RainLoop\Enumerations\Capa::TWO_FACTOR);
|
||||
$this->setCapaFromParams($oConfig, 'CapaOpenPGP', \RainLoop\Enumerations\Capa::OPEN_PGP);
|
||||
$this->setCapaFromParams($oConfig, 'CapaGravatar', \RainLoop\Enumerations\Capa::GRAVATAR);
|
||||
|
@ -5303,6 +5537,27 @@ class Actions
|
|||
return $oMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Model\Account $oAccount
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function deleteMessageAttachmnets($oAccount)
|
||||
{
|
||||
$aAttachments = $this->GetActionParam('Attachments', null);
|
||||
|
||||
if (\is_array($aAttachments))
|
||||
{
|
||||
foreach (\array_keys($aAttachments) as $sTempName)
|
||||
{
|
||||
if ($this->FilesProvider()->FileExists($oAccount, $sTempName))
|
||||
{
|
||||
$this->FilesProvider()->Clear($oAccount, $sTempName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Model\Account $oAccount
|
||||
*
|
||||
|
@ -5600,6 +5855,8 @@ class Actions
|
|||
{
|
||||
$this->smtpSendMessage($oAccount, $oMessage, $rMessageStream, $iMessageStreamSize);
|
||||
|
||||
$this->deleteMessageAttachmnets($oAccount);
|
||||
|
||||
if (is_array($aDraftInfo) && 3 === count($aDraftInfo))
|
||||
{
|
||||
$sDraftInfoType = $aDraftInfo[0];
|
||||
|
@ -6967,7 +7224,7 @@ class Actions
|
|||
$oSettings = $this->SettingsProvider()->Load($oAccount);
|
||||
if ($oSettings)
|
||||
{
|
||||
$sHash = \md5($sName.APP_VERSION.APP_SALT.\rand(1000, 9999).\microtime(true));
|
||||
$sHash = \MailSo\Base\Utils::Md5Rand($sName.APP_VERSION.APP_SALT);
|
||||
|
||||
$oSettings->SetConf('UserBackgroundName', $sName);
|
||||
$oSettings->SetConf('UserBackgroundHash', $sHash);
|
||||
|
@ -7225,7 +7482,7 @@ class Actions
|
|||
$sLast = \array_pop($aParams);
|
||||
|
||||
$sUrl = $this->Http()->GetFullUrl().'?/Raw/&s=/'.implode('/', $aParams).'/&ss=/'.$sLast;
|
||||
$sFullUrl = 'http://docs.google.com/viewer?embedded=true&url='.urlencode($sUrl);
|
||||
$sFullUrl = 'https://docs.google.com/viewer?embedded=true&url='.urlencode($sUrl);
|
||||
|
||||
@\header('Content-Type: text/html; charset=utf-8');
|
||||
echo '<html style="height: 100%; width: 100%; margin: 0; padding: 0"><head></head>'.
|
||||
|
@ -7272,6 +7529,8 @@ class Actions
|
|||
$rMessageStream = $this->FilesProvider()->GetFile($oAccount, $sSavedName);
|
||||
|
||||
$this->MailClient()->MessageAppendStream($rMessageStream, $iMessageStreamSize, $sFolderFullNameRaw);
|
||||
|
||||
$this->FilesProvider()->Clear($oAccount, $sSavedName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7301,6 +7560,11 @@ class Actions
|
|||
}
|
||||
}
|
||||
|
||||
// if ($oConfig->Get('capa', 'templates', true))
|
||||
// {
|
||||
// $aResult[] = \RainLoop\Enumerations\Capa::TEMPLATES;
|
||||
// }
|
||||
|
||||
if ($oConfig->Get('webmail', 'allow_additional_accounts', false))
|
||||
{
|
||||
$aResult[] = \RainLoop\Enumerations\Capa::ADDITIONAL_ACCOUNTS;
|
||||
|
@ -7455,7 +7719,7 @@ class Actions
|
|||
{
|
||||
\MailSo\Base\StreamWrappers\TempFile::Reg();
|
||||
|
||||
$sFileName = 'mailsotempfile://'.\md5($sFileNameOut.\rand(1000, 9999));
|
||||
$sFileName = 'mailsotempfile://'.\MailSo\Base\Utils::Md5Rand($sFileNameOut);
|
||||
|
||||
$rTempResource = \fopen($sFileName, 'r+b');
|
||||
if (@\is_resource($rTempResource))
|
||||
|
@ -8256,25 +8520,6 @@ class Actions
|
|||
@\header('Location: '.$sUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sTitle
|
||||
* @param string $sDesc
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function ErrorTemplates($sTitle, $sDesc, $bShowBackLink = true)
|
||||
{
|
||||
return strtr(file_get_contents(APP_VERSION_ROOT_PATH.'app/templates/Error.html'), array(
|
||||
'{{BaseWebStaticPath}}' => APP_WEB_STATIC_PATH,
|
||||
'{{ErrorTitle}}' => $sTitle,
|
||||
'{{ErrorHeader}}' => $sTitle,
|
||||
'{{ErrorDesc}}' => $sDesc,
|
||||
'{{BackLinkVisibilityStyle}}' => $bShowBackLink ? 'display:inline-block' : 'display:none',
|
||||
'{{BackLink}}' => $this->StaticI18N('STATIC/BACK_LINK'),
|
||||
'{{BackHref}}' => './'
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object $oData
|
||||
* @param string $sParent
|
||||
|
|
|
@ -136,7 +136,7 @@ class Api
|
|||
*/
|
||||
public static function GetUserSsoHash($sEmail, $sPassword, $bUseTimeout = true)
|
||||
{
|
||||
$sSsoHash = \sha1(\rand(10000, 99999).$sEmail.$sPassword.\microtime(true));
|
||||
$sSsoHash = \MailSo\Base\Utils::Sha1Rand($sEmail.$sPassword);
|
||||
|
||||
return \RainLoop\Api::Actions()->Cacher()->Set(\RainLoop\KeyPathHelper::SsoCacherKey($sSsoHash), \RainLoop\Utils::EncodeKeyValues(array(
|
||||
'Email' => $sEmail,
|
||||
|
|
|
@ -129,7 +129,8 @@ class Application extends \RainLoop\Config\AbstractConfig
|
|||
),
|
||||
|
||||
'capa' => array(
|
||||
'filters' => array(true)
|
||||
'filters' => array(true),
|
||||
'templates' => array(true)
|
||||
),
|
||||
|
||||
'login' => array(
|
||||
|
@ -164,6 +165,7 @@ Values:
|
|||
'view_editor_type' => array('Html', 'Editor mode used by default (Plain, Html, HtmlForced or PlainForced)'),
|
||||
'view_layout' => array(1, 'layout: 0 - no preview, 1 - side preview, 3 - bottom preview'),
|
||||
'view_use_checkboxes' => array(true),
|
||||
'show_images' => array(false),
|
||||
'contacts_autosave' => array(true),
|
||||
'mail_use_threads' => array(false),
|
||||
'mail_reply_same_folder' => array(false)
|
||||
|
|
|
@ -15,4 +15,5 @@ class Capa
|
|||
const FILTERS = 'FILTERS';
|
||||
const ATTACHMENT_THUMBNAILS = 'ATTACHMENT_THUMBNAILS';
|
||||
const ADDITIONAL_ACCOUNTS = 'ADDITIONAL_ACCOUNTS';
|
||||
const TEMPLATES = 'TEMPLATES';
|
||||
}
|
||||
|
|
149
rainloop/v/0.0.0/app/libraries/RainLoop/Model/Template.php
Normal file
149
rainloop/v/0.0.0/app/libraries/RainLoop/Model/Template.php
Normal file
|
@ -0,0 +1,149 @@
|
|||
<?php
|
||||
|
||||
namespace RainLoop\Model;
|
||||
|
||||
class Template
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sId;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sName;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $sBody;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $bPopulateAlways;
|
||||
|
||||
/**
|
||||
* @param string $sId = ''
|
||||
* @param string $sName = ''
|
||||
* @param string $sBody = ''
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function __construct($sId = '', $sName = '', $sBody = '')
|
||||
{
|
||||
$this->sId = $sId;
|
||||
$this->sName = $sName;
|
||||
$this->sBody = $sBody;
|
||||
$this->bPopulateAlways = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sId = ''
|
||||
* @param string $sName = ''
|
||||
* @param string $sBody = ''
|
||||
*
|
||||
* @return \RainLoop\Model\Template
|
||||
*/
|
||||
public static function NewInstance($sId = '', $sName = '', $sBody = '')
|
||||
{
|
||||
return new self($sId, $sBody);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function Id()
|
||||
{
|
||||
return $this->sId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function Name()
|
||||
{
|
||||
return $this->sName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function Body()
|
||||
{
|
||||
return $this->sBody;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $bPopulateAlways
|
||||
*/
|
||||
public function SetPopulateAlways($bPopulateAlways)
|
||||
{
|
||||
$this->bPopulateAlways = !!$bPopulateAlways;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $aData
|
||||
* @param bool $bAjax = false
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function FromJSON($aData, $bAjax = false)
|
||||
{
|
||||
if (isset($aData['ID'], $aData['Name'], $aData['Body']))
|
||||
{
|
||||
$this->sId = $aData['ID'];
|
||||
$this->sName = $aData['Name'];
|
||||
$this->sBody = $aData['Body'];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $bAjax = false
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function ToSimpleJSON($bAjax = false)
|
||||
{
|
||||
$sBody = $this->Body();
|
||||
$bPopulated = true;
|
||||
|
||||
if ($bAjax && $bPopulated && !$this->bPopulateAlways)
|
||||
{
|
||||
if (1024 * 5 < \strlen($sBody) || true)
|
||||
{
|
||||
$bPopulated = false;
|
||||
$sBody = '';
|
||||
}
|
||||
}
|
||||
|
||||
return array(
|
||||
'ID' => $this->Id(),
|
||||
'Name' => $this->Name(),
|
||||
'Populated' => $bPopulated,
|
||||
'Body' => $sBody
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function GenerateID()
|
||||
{
|
||||
return $this->sId = \MailSo\Base\Utils::Md5Rand();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function Validate()
|
||||
{
|
||||
return 0 < \strlen($this->sBody);
|
||||
}
|
||||
}
|
|
@ -151,7 +151,7 @@ class Contact
|
|||
public function RegenerateContactStr()
|
||||
{
|
||||
$this->IdContactStr = \class_exists('Sabre\DAV\Client') ?
|
||||
\Sabre\DAV\UUIDUtil::getUUID() : \md5(\microtime(true).'-'.\rand(10000, 99999));
|
||||
\Sabre\DAV\UUIDUtil::getUUID() : \MailSo\Base\Utils::Md5Rand();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -107,6 +107,15 @@ class Files extends \RainLoop\Providers\AbstractProvider
|
|||
return $this->oDriver ? $this->oDriver->GC($iTimeToClearInHours) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function CloseAllOpenedFiles()
|
||||
{
|
||||
return $this->oDriver && \method_exists($this->oDriver, 'CloseAllOpenedFiles') ?
|
||||
$this->oDriver->CloseAllOpenedFiles() : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
|
|
|
@ -4,6 +4,11 @@ namespace RainLoop\Providers\Files;
|
|||
|
||||
class DefaultStorage implements \RainLoop\Providers\Files\FilesInterface
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $aResources;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
|
@ -16,6 +21,7 @@ class DefaultStorage implements \RainLoop\Providers\Files\FilesInterface
|
|||
*/
|
||||
public function __construct($sStoragePath)
|
||||
{
|
||||
$this->aResources = array();
|
||||
$this->sDataPath = \rtrim(\trim($sStoragePath), '\\/');
|
||||
}
|
||||
|
||||
|
@ -70,6 +76,11 @@ class DefaultStorage implements \RainLoop\Providers\Files\FilesInterface
|
|||
if ($bCreate || \file_exists($sFileName))
|
||||
{
|
||||
$mResult = @\fopen($sFileName, $sOpenMode);
|
||||
|
||||
if (\is_resource($mResult))
|
||||
{
|
||||
$this->aResources[$sFileName] = $mResult;
|
||||
}
|
||||
}
|
||||
|
||||
return $mResult;
|
||||
|
@ -105,6 +116,11 @@ class DefaultStorage implements \RainLoop\Providers\Files\FilesInterface
|
|||
$sFileName = $this->generateFileName($oAccount, $sKey);
|
||||
if (\file_exists($sFileName))
|
||||
{
|
||||
if (isset($this->aResources[$sFileName]) && \is_resource($this->aResources[$sFileName]))
|
||||
{
|
||||
@\fclose($this->aResources[$sFileName]);
|
||||
}
|
||||
|
||||
$mResult = @\unlink($sFileName);
|
||||
}
|
||||
|
||||
|
@ -156,6 +172,25 @@ class DefaultStorage implements \RainLoop\Providers\Files\FilesInterface
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function CloseAllOpenedFiles()
|
||||
{
|
||||
if (\is_array($this->aResources) && 0 < \count($this->aResources))
|
||||
{
|
||||
foreach ($this->aResources as $sFileName => $rFile)
|
||||
{
|
||||
if (!empty($sFileName) && \is_resource($rFile))
|
||||
{
|
||||
@\fclose($rFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Model\Account $oAccount
|
||||
* @param string $sKey
|
||||
|
|
|
@ -125,7 +125,7 @@ class Service
|
|||
|
||||
if ($bAdmin && !$this->oActions->Config()->Get('security', 'allow_admin_panel', true))
|
||||
{
|
||||
echo $this->oActions->ErrorTemplates('Access Denied.',
|
||||
echo $this->oServiceActions->ErrorTemplates('Access Denied.',
|
||||
'Access to the RainLoop Webmail Admin Panel is not allowed!', true);
|
||||
|
||||
return $this;
|
||||
|
@ -150,6 +150,9 @@ class Service
|
|||
|
||||
if ($bIndex)
|
||||
{
|
||||
@\header('Content-Security-Policy:');
|
||||
@\header_remove('Content-Security-Policy');
|
||||
|
||||
@header('Content-Type: text/html; charset=utf-8');
|
||||
$this->oHttp->ServerNoCache();
|
||||
|
||||
|
@ -216,7 +219,7 @@ class Service
|
|||
$bAppJsDebug = !!$this->oActions->Config()->Get('labs', 'use_app_debug_js', false);
|
||||
$bAppCssDebug = !!$this->oActions->Config()->Get('labs', 'use_app_debug_css', false);
|
||||
|
||||
$sStaticPrefix = APP_WEB_STATIC_PATH;
|
||||
$sStaticPrefix = $this->oServiceActions->WebStaticPath();
|
||||
|
||||
$aData = array(
|
||||
'Language' => $sLanguage,
|
||||
|
@ -254,7 +257,7 @@ class Service
|
|||
\implode('~', array(
|
||||
\md5($this->oActions->Config()->Get('cache', 'index', '')),
|
||||
$this->oActions->Plugins()->Hash(),
|
||||
APP_WEB_PATH, APP_VERSION
|
||||
$this->oServiceActions->WebVersionPath(), APP_VERSION
|
||||
)).
|
||||
\implode('~', $aTemplateParameters)
|
||||
);
|
||||
|
|
|
@ -675,7 +675,7 @@ class ServiceActions
|
|||
|
||||
if (\file_exists($sThemeFile) && \file_exists($sThemeTemplateFile) && \file_exists($sThemeValuesFile))
|
||||
{
|
||||
$aResult[] = '@base: "'.($bCustomTheme ? '' : APP_WEB_PATH).'themes/'.$sRealTheme.'/";';
|
||||
$aResult[] = '@base: "'.($bCustomTheme ? $this->WebPath() : $this->WebVersionPath()).'themes/'.$sRealTheme.'/";';
|
||||
$aResult[] = \file_get_contents($sThemeValuesFile);
|
||||
$aResult[] = \file_get_contents($sThemeFile);
|
||||
$aResult[] = \file_get_contents($sThemeTemplateFile);
|
||||
|
@ -779,7 +779,7 @@ class ServiceActions
|
|||
|
||||
@\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,
|
||||
'{{BaseWebStaticPath}}' => $this->WebStaticPath(),
|
||||
'{{ErrorTitle}}' => $sTitle,
|
||||
'{{ErrorHeader}}' => $sTitle,
|
||||
'{{ErrorDesc}}' => $sDesc
|
||||
|
@ -1051,6 +1051,58 @@ class ServiceActions
|
|||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sTitle
|
||||
* @param string $sDesc
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function ErrorTemplates($sTitle, $sDesc, $bShowBackLink = true)
|
||||
{
|
||||
return strtr(file_get_contents(APP_VERSION_ROOT_PATH.'app/templates/Error.html'), array(
|
||||
'{{BaseWebStaticPath}}' => $this->WebStaticPath(),
|
||||
'{{ErrorTitle}}' => $sTitle,
|
||||
'{{ErrorHeader}}' => $sTitle,
|
||||
'{{ErrorDesc}}' => $sDesc,
|
||||
'{{BackLinkVisibilityStyle}}' => $bShowBackLink ? 'display:inline-block' : 'display:none',
|
||||
'{{BackLink}}' => $this->oActions->StaticI18N('STATIC/BACK_LINK'),
|
||||
'{{BackHref}}' => './'
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function WebPath()
|
||||
{
|
||||
if (isset($_ENV['RAINLOOP_OWNCLOUD']) && $_ENV['RAINLOOP_OWNCLOUD'])
|
||||
{
|
||||
$sUrl = $this->oHttp->GetUrl();
|
||||
if ($sUrl && \preg_match('/\/index\.php\/apps\/rainloop/', $sUrl))
|
||||
{
|
||||
$sUrl = \preg_replace('/\/index\.php\/apps\/rainloop.+$/', '/', $sUrl);
|
||||
return \rtrim(\trim($sUrl), '\//').'/apps/rainloop/app/';
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function WebVersionPath()
|
||||
{
|
||||
return $this->WebPath().'rainloop/v/'.APP_VERSION.'/';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function WebStaticPath()
|
||||
{
|
||||
return $this->WebVersionPath().'static/';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sTitle
|
||||
* @param string $sDesc
|
||||
|
|
|
@ -72,7 +72,7 @@ class Utils
|
|||
$sToken = \RainLoop\Utils::GetCookie($sKey, null);
|
||||
if (null === $sToken)
|
||||
{
|
||||
$sToken = \md5(\rand(10000, 99999).\microtime(true).APP_SALT);
|
||||
$sToken = \MailSo\Base\Utils::Md5Rand(APP_SALT);
|
||||
\RainLoop\Utils::SetCookie($sKey, $sToken, \time() + 60 * 60 * 24 * 30, '/', null, null, true);
|
||||
}
|
||||
|
||||
|
@ -97,7 +97,7 @@ class Utils
|
|||
$sToken = \RainLoop\Utils::GetCookie($sKey, null);
|
||||
if (null === $sToken)
|
||||
{
|
||||
$sToken = \md5(\rand(10000, 99999).\microtime(true).APP_SALT);
|
||||
$sToken = \MailSo\Base\Utils::Md5Rand(APP_SALT);
|
||||
\RainLoop\Utils::SetCookie($sKey, $sToken, 0, '/', null, null, true);
|
||||
}
|
||||
|
||||
|
|
|
@ -138,5 +138,18 @@
|
|||
}"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!--
|
||||
<div class="control-group">
|
||||
<div class="controls">
|
||||
<div data-bind="component: {
|
||||
name: 'Checkbox',
|
||||
params: {
|
||||
label: 'Allow templates',
|
||||
value: capaTemplates
|
||||
}
|
||||
}"></div>
|
||||
</div>
|
||||
</div>
|
||||
-->
|
||||
</div>
|
||||
</div>
|
|
@ -16,13 +16,15 @@
|
|||
</div>
|
||||
<br />
|
||||
<div class="control-group" data-bind="css: {'error': name.error}">
|
||||
<label class="i18n" data-i18n-text="POPUPS_ADD_TEMPLATE/LABEL_NAME"></label>
|
||||
<input type="text" class="inputName span6" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
|
||||
data-bind="textInput: name, onEnter: addTemplateCommand, hasfocus: name.focus" />
|
||||
<label class="i18n control-label" data-i18n-text="POPUPS_ADD_TEMPLATE/LABEL_NAME"></label>
|
||||
<div class="controls">
|
||||
<input type="text" class="inputName input-xlarge" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
|
||||
data-bind="textInput: name, onEnter: addTemplateCommand, hasfocus: name.focus" />
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<div class="control-group" data-bind="css: {'error': body.error}">
|
||||
<label class="i18n" data-i18n-text="POPUPS_ADD_TEMPLATE/LABEL_TEXT"></label>
|
||||
<div class="e-body-place" data-bind="initDom: signatureDom"></div>
|
||||
<div class="e-template-place" data-bind="initDom: signatureDom"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -26,9 +26,9 @@ Options -Indexes
|
|||
if (file_exists(APP_INDEX_ROOT_PATH.'include.php'))
|
||||
{
|
||||
include_once APP_INDEX_ROOT_PATH.'include.php';
|
||||
$sCustomDataPath = function_exists('__get_custom_data_full_path') ? rtrim(trim(__get_custom_data_full_path()), '\\/') : '';
|
||||
}
|
||||
|
||||
$sCustomDataPath = function_exists('__get_custom_data_full_path') ? rtrim(trim(__get_custom_data_full_path()), '\\/') : '';
|
||||
define('APP_DATA_FOLDER_PATH', 0 === strlen($sCustomDataPath) ? APP_INDEX_ROOT_PATH.'data/' : $sCustomDataPath.'/');
|
||||
unset($sCustomDataPath);
|
||||
|
||||
|
@ -58,8 +58,6 @@ Options -Indexes
|
|||
define('APP_REP_PATH', 'http://repository.rainloop.net/v1/');
|
||||
define('APP_REPO_CORE_FILE', 'http://repository.rainloop.net/v2/core.{{channel}}.json');
|
||||
define('APP_STATUS_PATH', 'http://status.rainloop.net/');
|
||||
define('APP_WEB_PATH', 'rainloop/v/'.APP_VERSION.'/');
|
||||
define('APP_WEB_STATIC_PATH', APP_WEB_PATH.'static/');
|
||||
define('APP_DATA_FOLDER_PATH_UNIX', str_replace('\\', '/', APP_DATA_FOLDER_PATH));
|
||||
|
||||
$sSalt = @file_get_contents(APP_DATA_FOLDER_PATH.'SALT.php');
|
||||
|
|
Loading…
Reference in a new issue