public
nobgit
read
NobMail
Based on mailcow: dockerized
Languages
Repository composition by tracked source files.
PHP
49%
JavaScript
35%
HTML
9%
CSS
4%
Shell
2%
Python
1%
Lua
0%
Perl
0%
Ruby
0%
SCSS
0%
Create file
Wiki Documentation
Clone
https://nobgit.com/orgs/nobgit/nobmail.git
ssh://[email protected]:2222/orgs/nobgit/nobmail.git
Commit
Various...
adc23d86
.gitignore | 1 -
data/web/admin.php | 237 ++---
data/web/css/breakpoint.min.css | 1 +
data/web/css/debug.css | 37 +
data/web/css/quarantaine.css | 37 +
data/web/debug.php | 328 +++++++
data/web/img/rspamd_logo.png | Bin 0 -> 4613 bytes
data/web/inc/ajax/container_ctrl.php | 53 +
data/web/inc/ajax/log_driver.php | 12 +
data/web/inc/ajax/qitem_details.php | 83 ++
data/web/inc/ajax/sogo_ctrl.php | 39 -
data/web/inc/footer.inc.php | 70 +-
data/web/inc/functions.customize.inc.php | 54 +-
data/web/inc/functions.docker.inc.php | 49 +-
data/web/inc/functions.fail2ban.inc.php | 2 -
data/web/inc/functions.inc.php | 203 +++-
data/web/inc/functions.mailbox.inc.php | 26 +-
data/web/inc/functions.quarantaine.inc.php | 282 ++++++
data/web/inc/header.inc.php | 14 +-
data/web/inc/init_db.inc.php | 108 +-
data/web/inc/lib/composer.json | 3 +-
data/web/inc/lib/composer.lock | 102 +-
data/web/inc/lib/vendor/composer/autoload_psr4.php | 1 +
.../inc/lib/vendor/composer/autoload_static.php | 8 +
data/web/inc/lib/vendor/composer/installed.json | 180 +++-
.../php-mime-mail-parser/LICENSE | 21 +
.../php-mime-mail-parser/README.md | 167 ++++
.../php-mime-mail-parser/composer.json | 61 ++
.../php-mime-mail-parser/mailparse-stubs.php | 303 ++++++
.../php-mime-mail-parser/phpunit.xml.dist | 6 +
.../php-mime-mail-parser/src/Attachment.php | 183 ++++
.../php-mime-mail-parser/src/Charset.php | 338 +++++++
.../src/Contracts/CharsetManager.php | 24 +
.../php-mime-mail-parser/src/Exception.php | 8 +
.../php-mime-mail-parser/src/Parser.php | 893 +++++++++++++++++
.../web/inc/lib/vendor/phpmailer/phpmailer/VERSION | 2 +-
.../vendor/phpmailer/phpmailer/class.phpmailer.php | 4 +-
.../lib/vendor/phpmailer/phpmailer/class.pop3.php | 2 +-
.../lib/vendor/phpmailer/phpmailer/class.smtp.php | 4 +-
.../lib/vendor/robthree/twofactorauth/.gitignore | 5 +-
.../lib/vendor/robthree/twofactorauth/.travis.yml | 13 +-
.../.vs/config/applicationhost.config | 1031 ++++++++++++++++++++
.../lib/vendor/robthree/twofactorauth/README.md | 2 +-
.../vendor/robthree/twofactorauth/composer.json | 2 +-
.../Time/ConvertUnixTimeDotComTimeProvider.php | 2 +-
.../lib/Providers/Time/HttpTimeProvider.php | 3 +-
.../u2flib-server/src/u2flib_server/U2F.php.1 | 507 ----------
data/web/inc/prerequisites.inc.php | 20 +-
data/web/inc/sessions.inc.php | 18 +
data/web/inc/triggers.inc.php | 12 +
data/web/inc/vars.inc.php | 19 +-
data/web/index.php | 14 +-
data/web/js/admin.js | 350 +------
data/web/js/api.js | 28 +-
data/web/js/debug.js | 503 ++++++++++
data/web/js/formcache.min.js | 10 +
data/web/js/mailbox.js | 6 +-
data/web/js/quarantaine.js | 82 ++
data/web/json_api.php | 362 +++++--
data/web/lang/lang.de.php | 93 +-
data/web/lang/lang.en.php | 70 +-
data/web/mailbox.php | 13 +-
data/web/modals/admin.php | 4 +-
data/web/modals/debug.php | 6 +
data/web/modals/footer.php | 14 +-
data/web/modals/mailbox.php | 37 +-
data/web/modals/quarantaine.php | 32 +
data/web/modals/user.php | 4 +-
data/web/quarantaine.php | 56 ++
data/web/user.php | 17 +-
70 files changed, 5954 insertions(+), 1327 deletions(-)
create mode 100644 data/web/css/breakpoint.min.css
create mode 100644 data/web/css/debug.css
create mode 100644 data/web/css/quarantaine.css
create mode 100644 data/web/debug.php
create mode 100644 data/web/img/rspamd_logo.png
create mode 100644 data/web/inc/ajax/container_ctrl.php
create mode 100644 data/web/inc/ajax/log_driver.php
create mode 100644 data/web/inc/ajax/qitem_details.php
delete mode 100644 data/web/inc/ajax/sogo_ctrl.php
create mode 100644 data/web/inc/functions.quarantaine.inc.php
create mode 100644 data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/LICENSE
create mode 100644 data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/README.md
create mode 100644 data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/composer.json
create mode 100644 data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/mailparse-stubs.php
create mode 100644 data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/phpunit.xml.dist
create mode 100644 data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/src/Attachment.php
create mode 100644 data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/src/Charset.php
create mode 100644 data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/src/Contracts/CharsetManager.php
create mode 100644 data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/src/Exception.php
create mode 100644 data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/src/Parser.php
create mode 100644 data/web/inc/lib/vendor/robthree/twofactorauth/.vs/config/applicationhost.config
delete mode 100644 data/web/inc/lib/vendor/yubico/u2flib-server/src/u2flib_server/U2F.php.1
create mode 100644 data/web/js/debug.js
create mode 100644 data/web/js/formcache.min.js
create mode 100644 data/web/js/quarantaine.js
create mode 100644 data/web/modals/debug.php
create mode 100644 data/web/modals/quarantaine.php
create mode 100644 data/web/quarantaine.php
Diff
diff --git a/.gitignore b/.gitignore
index 0d081fc4..b945f8cf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,4 +21,3 @@ data/conf/nginx/*.conf
data/conf/nginx/*.custom
data/conf/nginx/*.bak
data/conf/dovecot/extra.conf
-data/conf/rspamd/custom/*
diff --git a/data/web/admin.php b/data/web/admin.php
index 0d7c6466..e1fe74be 100644
--- a/data/web/admin.php
+++ b/data/web/admin.php
@@ -8,26 +8,8 @@ $tfa_data = get_tfa();
?>
<div class="container">
<ul class="nav nav-tabs" role="tablist">
- <li role="presentation" class="active">
- <a href="#tab-access" aria-controls="tab-access" role="tab" data-toggle="tab"><?=$lang['admin']['access'];?></a>
- </li>
- <li role="presentation">
- <a href="#tab-config" aria-controls="tab-config" role="tab" data-toggle="tab"><?=$lang['admin']['configuration'];?></a>
- </li>
- <li class="dropdown">
- <a class="dropdown-toggle" data-toggle="dropdown" href="#">Logs
- <span class="caret"></span></a>
- <ul class="dropdown-menu">
- <li role="presentation"><a href="#tab-postfix-logs" aria-controls="tab-postfix-logs" role="tab" data-toggle="tab">Postfix</a></li>
- <li role="presentation"><a href="#tab-dovecot-logs" aria-controls="tab-dovecot-logs" role="tab" data-toggle="tab">Dovecot</a></li>
- <li role="presentation"><a href="#tab-sogo-logs" aria-controls="tab-sogo-logs" role="tab" data-toggle="tab">SOGo</a></li>
- <?php if (F2B == 1): ?>
- <li role="presentation"><a href="#tab-fail2ban-logs" aria-controls="tab-fail2ban-logs" role="tab" data-toggle="tab">Fail2ban</a></li>
- <?php endif; ?>
- <li role="presentation"><a href="#tab-rspamd-history" aria-controls="tab-rspamd-history" role="tab" data-toggle="tab">Rspamd</a></li>
- <li role="presentation"><a href="#tab-autodiscover-logs" aria-controls="tab-autodiscover-logs" role="tab" data-toggle="tab">Autodiscover</a></li>
- </ul>
- </li>
+ <li role="presentation" class="active"><a href="#tab-access" aria-controls="tab-access" role="tab" data-toggle="tab"><?=$lang['admin']['access'];?></a></li>
+ <li role="presentation"><a href="#tab-config" aria-controls="tab-config" role="tab" data-toggle="tab"><?=$lang['admin']['configuration'];?></a></li>
</ul>
<div class="tab-content" style="padding-top:20px">
@@ -58,7 +40,7 @@ $tfa_data = get_tfa();
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
- <button class="btn btn-default" id="edit_selected" data-id="admin" data-item="null" data-api-url='edit/self' data-api-attr='{}' href="#"><?=$lang['admin']['save'];?></button>
+ <button class="btn btn-default" id="edit_selected" data-id="admin" data-item="null" data-api-url='edit/self' data-api-attr='{}' href="#"><span class="glyphicon glyphicon-check"></span> <?=$lang['admin']['save'];?></button>
</div>
</div>
</form>
@@ -96,6 +78,42 @@ $tfa_data = get_tfa();
</div>
</div>
</div>
+
+ <div class="panel panel-primary">
+ <div class="panel-heading">API</div>
+ <div class="panel-body">
+ <form class="form-horizontal" autocapitalize="none" autocorrect="off" role="form" method="post">
+ <div class="form-group">
+ <label class="control-label col-sm-3" for="allow_from"><?=$lang['admin']['api_allow_from'];?>:</label>
+ <div class="col-sm-9">
+ <textarea class="form-control" rows="5" name="allow_from" id="allow_from" required><?=htmlspecialchars($admindetails['allow_from']);?></textarea>
+ </div>
+ </div>
+ <div class="form-group">
+ <label class="control-label col-sm-3" for="admin_api_key"><?=$lang['admin']['api_key'];?>:</label>
+ <div class="col-sm-9">
+ <input type="text" class="form-control" placeholder="-" value="<?=htmlspecialchars($admindetails['api_key']);?>" readonly>
+ </div>
+ </div>
+ <div class="form-group">
+ <div class="col-sm-offset-3 col-sm-9">
+ <label>
+ <input type="checkbox" name="active" <?=($admindetails['api_active'] == 1) ? 'checked' : null;?>> <?=$lang['admin']['activate_api'];?>
+ </label>
+ </div>
+ </div>
+ <div class="form-group">
+ <div class="col-sm-offset-3 col-sm-9">
+ <div class="btn-group">
+ <button class="btn btn-default" name="admin_api" type="submit" href="#"><span class="glyphicon glyphicon-check"></span> <?=$lang['admin']['save'];?></button>
+ <button class="btn btn-info" name="admin_api_regen_key" type="submit" href="#"><?=$lang['admin']['regen_api_key'];?></button>
+ </div>
+ </div>
+ </div>
+ </form>
+ </div>
+ </div>
+
<div class="panel panel-default">
<div class="panel-heading"><?=$lang['admin']['domain_admins'];?></div>
<div class="panel-body">
@@ -121,17 +139,15 @@ $tfa_data = get_tfa();
</div>
</div>
-
<div role="tabpanel" class="tab-pane" id="tab-config">
<div class="row">
<div id="sidebar-admin" class="col-sm-2 hidden-xs">
<div id="scrollbox" class="list-group">
<a href="#dkim" class="list-group-item"><?=$lang['admin']['dkim_keys'];?></a>
<a href="#fwdhosts" class="list-group-item"><?=$lang['admin']['forwarding_hosts'];?></a>
- <?php if (F2B == 1): ?>
<a href="#f2bparams" class="list-group-item"><?=$lang['admin']['f2b_parameters'];?></a>
- <?php endif; ?>
<a href="#relayhosts" class="list-group-item">Relayhosts</a>
+ <a href="#quarantaine" class="list-group-item">Quarantaine</a>
<a href="#customize" class="list-group-item"><?=$lang['admin']['customize'];?></a>
<a href="#top" class="list-group-item" style="border-top:1px dashed #dadada">↸ <?=$lang['admin']['to_top'];?></a>
</div>
@@ -310,7 +326,6 @@ $tfa_data = get_tfa();
</div>
</div>
- <?php if (F2B == 1): ?>
<span class="anchor" id="f2bparams"></span>
<div class="panel panel-default">
<div class="panel-heading"><?=$lang['admin']['f2b_parameters'];?></div>
@@ -332,14 +347,13 @@ $tfa_data = get_tfa();
<input type="number" class="form-control" id="retry_window" name="retry_window" value="<?=$f2b_data['retry_window'];?>" required>
</div>
<div class="form-group">
- <label for="retry_window"><?=$lang['admin']['f2b_whitelist'];?>:</label>
+ <label for="whitelist"><?=$lang['admin']['f2b_whitelist'];?>:</label>
<textarea class="form-control" id="whitelist" name="whitelist" rows="5"><?=$f2b_data['whitelist'];?></textarea>
</div>
<button class="btn btn-default" id="add_item" data-id="f2b" data-api-url='edit/fail2ban' data-api-attr='{}' href="#"><span class="glyphicon glyphicon-check"></span> <?=$lang['admin']['save'];?></button>
</form>
</div>
</div>
- <?php endif; ?>
<span class="anchor" id="relayhosts"></span>
<div class="panel panel-default">
@@ -381,6 +395,43 @@ $tfa_data = get_tfa();
</div>
</div>
+ <span class="anchor" id="quarantaine"></span>
+ <div class="panel panel-default">
+ <div class="panel-heading">Quarantäne</div>
+ <div class="panel-body">
+ <?php $q_data = quarantaine('settings'); ?>
+ <form class="form" data-id="quarantaine" role="form" method="post">
+ <div class="row">
+ <div class="col-sm-6">
+ <div class="form-group">
+ <label for="retention_size">Rückhaltungen pro Mailbox:</label>
+ <input type="number" class="form-control" id="retention_size" name="retention_size" value="<?=$q_data['retention_size'];?>" required>
+ </div>
+ </div>
+ <div class="col-sm-6">
+ <div class="form-group">
+ <label for="max_size">Maximale Größe in MiB (größere Elemente werden verworfen):</label>
+ <input type="number" class="form-control" id="max_size" name="max_size" value="<?=$q_data['max_size'];?>" required>
+ </div>
+ </div>
+ </div>
+ <div class="form-group">
+ <label for="exclude_domains">Domains und Alias-Domains ausschließen:</label><br />
+ <select data-width="100%" id="exclude_domains" name="exclude_domains" class="selectpicker" title="<?=$lang['tfa']['select'];?>" multiple>
+ <?php
+ foreach (array_merge(mailbox('get', 'domains'), mailbox('get', 'alias_domains')) as $domain):
+ ?>
+ <option <?=(in_array($domain, $q_data['exclude_domains'])) ? 'selected' : null;?>><?=htmlspecialchars($domain);?></option>
+ <?php
+ endforeach;
+ ?>
+ </select>
+ </div>
+ <button class="btn btn-success" id="edit_selected" data-item="self" data-id="quarantaine" data-api-url='edit/quarantaine' data-api-attr='{"action":"settings"}' href="#"><span class="glyphicon glyphicon-check"></span> <?=$lang['admin']['save'];?></button>
+ </form>
+ </div>
+ </div>
+
<span class="anchor" id="customize"></span>
<div class="panel panel-default">
<div class="panel-heading"><?=$lang['admin']['customize'];?></div>
@@ -449,10 +500,29 @@ $tfa_data = get_tfa();
endforeach;
?>
</table>
- <div class="btn-group">
- <button class="btn btn-success" id="edit_selected" data-item="admin" data-id="app_links" data-reload="no" data-api-url='edit/app_links' data-api-attr='{}' href="#"><?=$lang['admin']['save'];?></button>
- <button class="btn btn-default" type="button" id="add_app_link_row"><?=$lang['admin']['add_row'];?></button>
- </div>
+ <p><div class="btn-group">
+ <button class="btn btn-sm btn-success" id="edit_selected" data-item="admin" data-id="app_links" data-reload="no" data-api-url='edit/app_links' data-api-attr='{}' href="#"><span class="glyphicon glyphicon-check"></span> <?=$lang['admin']['save'];?></button>
+ <button class="btn btn-sm btn-default" type="button" id="add_app_link_row"><?=$lang['admin']['add_row'];?></button>
+ </div></p>
+ </form>
+ <legend><?=$lang['admin']['ui_texts'];?></legend>
+ <?php
+ $ui_texts = customize('get', 'ui_texts');
+ ?>
+ <form class="form" data-id="uitexts" role="form" method="post">
+ <div class="form-group">
+ <label for="main_name"><?=$lang['admin']['main_name'];?>:</label>
+ <input type="text" class="form-control" id="main_name" name="main_name" placeholder="mailcow UI" value="<?=$ui_texts['main_name'];?>">
+ </div>
+ <div class="form-group">
+ <label for="apps_name"><?=$lang['admin']['apps_name'];?>:</label>
+ <input type="text" class="form-control" id="apps_name" name="apps_name" placeholder="mailcow Apps" value="<?=$ui_texts['apps_name'];?>">
+ </div>
+ <div class="form-group">
+ <label for="help_text"><?=$lang['admin']['help_text'];?>:</label>
+ <textarea class="form-control" id="help_text" name="help_text" rows="7"><?=$ui_texts['help_text'];?></textarea>
+ </div>
+ <button class="btn btn-success" id="edit_selected" data-item="null" data-id="uitexts" data-api-url='edit/ui_texts' data-api-attr='{}' href="#"><span class="glyphicon glyphicon-check"></span> <?=$lang['admin']['save'];?></button>
</form>
</div>
</div>
@@ -460,111 +530,6 @@ $tfa_data = get_tfa();
</div>
</div>
- <div role="tabpanel" class="tab-pane" id="tab-postfix-logs">
- <div class="panel panel-default">
- <div class="panel-heading">Postfix <span class="badge badge-info log-lines"></span>
- <div class="btn-group pull-right">
- <button class="btn btn-xs btn-default add_log_lines" data-post-process="general_syslog" data-table="postfix_log" data-log-url="postfix" data-nrows="100">+ 100</button>
- <button class="btn btn-xs btn-default add_log_lines" data-post-process="general_syslog" data-table="postfix_log" data-log-url="postfix" data-nrows="1000">+ 1000</button>
- <button class="btn btn-xs btn-default" id="refresh_postfix_log"><?=$lang['admin']['refresh'];?></button>
- </div>
- </div>
- <div class="panel-body">
- <div class="table-responsive">
- <table class="table table-striped table-condensed" id="postfix_log"></table>
- </div>
- </div>
- </div>
- </div>
-
- <div role="tabpanel" class="tab-pane" id="tab-dovecot-logs">
- <div class="panel panel-default">
- <div class="panel-heading">Dovecot <span class="badge badge-info log-lines"></span>
- <div class="btn-group pull-right">
- <button class="btn btn-xs btn-default add_log_lines" data-post-process="general_syslog" data-table="dovecot_log" data-log-url="dovecot" data-nrows="100">+ 100</button>
- <button class="btn btn-xs btn-default add_log_lines" data-post-process="general_syslog" data-table="dovecot_log" data-log-url="dovecot" data-nrows="1000">+ 1000</button>
- <button class="btn btn-xs btn-default" id="refresh_dovecot_log"><?=$lang['admin']['refresh'];?></button>
- </div>
- </div>
- <div class="panel-body">
- <div class="table-responsive">
- <table class="table table-striped table-condensed" id="dovecot_log"></table>
- </div>
- </div>
- </div>
- </div>
-
- <div role="tabpanel" class="tab-pane" id="tab-sogo-logs">
- <div class="panel panel-default">
- <div class="panel-heading">SOGo <span class="badge badge-info log-lines"></span>
- <div class="btn-group pull-right">
- <button class="btn btn-xs btn-default add_log_lines" data-post-process="general_syslog" data-table="sogo_log" data-log-url="sogo" data-nrows="100">+ 100</button>
- <button class="btn btn-xs btn-default add_log_lines" data-post-process="general_syslog" data-table="sogo_log" data-log-url="sogo" data-nrows="1000">+ 1000</button>
- <button class="btn btn-xs btn-default" id="refresh_sogo_log"><?=$lang['admin']['refresh'];?></button>
- </div>
- </div>
- <div class="panel-body">
- <div class="table-responsive">
- <table class="table table-striped table-condensed" id="sogo_log"></table>
- </div>
- </div>
- </div>
- </div>
-
-
- <?php if (F2B == 1): ?>
- <div role="tabpanel" class="tab-pane" id="tab-fail2ban-logs">
- <div class="panel panel-default">
- <div class="panel-heading">Fail2ban <span class="badge badge-info log-lines"></span>
- <div class="btn-group pull-right">
- <button class="btn btn-xs btn-default add_log_lines" data-post-process="general_syslog" data-table="fail2ban_log" data-log-url="fail2ban" data-nrows="100">+ 100</button>
- <button class="btn btn-xs btn-default add_log_lines" data-post-process="general_syslog" data-table="fail2ban_log" data-log-url="fail2ban" data-nrows="1000">+ 1000</button>
- <button class="btn btn-xs btn-default" id="refresh_fail2ban_log"><?=$lang['admin']['refresh'];?></button>
- </div>
- </div>
- <div class="panel-body">
- <div class="table-responsive">
- <table class="table table-striped table-condensed" id="fail2ban_log"></table>
- </div>
- </div>
- </div>
- </div>
- <?php endif; ?>
-
- <div role="tabpanel" class="tab-pane" id="tab-rspamd-history">
- <div class="panel panel-default">
- <div class="panel-heading">Rspamd history <span class="badge badge-info log-lines"></span>
- <div class="btn-group pull-right">
- <button class="btn btn-xs btn-default add_log_lines" data-post-process="rspamd_history" data-table="rspamd_history" data-log-url="rspamd-history" data-nrows="100">+ 100</button>
- <button class="btn btn-xs btn-default add_log_lines" data-post-process="rspamd_history" data-table="rspamd_history" data-log-url="rspamd-history" data-nrows="1000">+ 1000</button>
- <button class="btn btn-xs btn-default" id="refresh_rspamd_history"><?=$lang['admin']['refresh'];?></button>
- </div>
- </div>
- <div class="panel-body">
- <div class="table-responsive">
- <table class="table table-striped table-condensed log-table" id="rspamd_history"></table>
- </div>
- </div>
- </div>
- </div>
-
- <div role="tabpanel" class="tab-pane" id="tab-autodiscover-logs">
- <div class="panel panel-default">
- <div class="panel-heading">Autodiscover <span class="badge badge-info log-lines"></span>
- <div class="btn-group pull-right">
- <button class="btn btn-xs btn-default add_log_lines" data-post-process="autodiscover_log" data-table="autodiscover_log" data-log-url="autodiscover" data-nrows="100">+ 100</button>
- <button class="btn btn-xs btn-default add_log_lines" data-post-process="autodiscover_log" data-table="autodiscover_log" data-log-url="autodiscover" data-nrows="1000">+ 1000</button>
- <button class="btn btn-xs btn-default" id="refresh_autodiscover_log"><?=$lang['admin']['refresh'];?></button>
- </div>
- </div>
- <div class="panel-body">
- <div class="table-responsive">
- <table class="table table-striped table-condensed" id="autodiscover_log"></table>
- </div>
- </div>
- </div>
- </div>
-
</div>
</div> <!-- /container -->
<?php
diff --git a/data/web/css/breakpoint.min.css b/data/web/css/breakpoint.min.css
new file mode 100644
index 00000000..8d84757c
--- /dev/null
+++ b/data/web/css/breakpoint.min.css
@@ -0,0 +1 @@
+@media (max-width:1050px){.navbar-header{float:none}.navbar-left,.navbar-nav,.navbar-right{float:none!important}.navbar-toggle{display:block}.navbar-collapse{border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-collapse.collapse{display:none!important}.navbar-nav{margin-top:7.5px}.navbar-nav>li{float:none}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px}.collapse.in{display:block!important}.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}}
\ No newline at end of file
diff --git a/data/web/css/debug.css b/data/web/css/debug.css
new file mode 100644
index 00000000..585d1905
--- /dev/null
+++ b/data/web/css/debug.css
@@ -0,0 +1,37 @@
+table.footable>tbody>tr.footable-empty>td {
+ font-size:15px !important;
+ font-style:italic;
+}
+.pagination a {
+ text-decoration: none !important;
+}
+.panel panel-default {
+ overflow: visible !important;
+}
+.table-responsive {
+ overflow: visible !important;
+}
+@media screen and (max-width: 767px) {
+ .table-responsive {
+ overflow-x: scroll !important;
+ }
+}
+.footer-add-item {
+ display:block;
+ text-align: center;
+ font-style: italic;
+ padding: 10px;
+ background: #F5F5F5;
+}
+@media (min-width: 992px) {
+ .container {
+ width: 80%;
+ }
+}
+.mass-actions-debug {
+ user-select: none;
+ padding:10px 0 10px 10px;
+}
+.inputMissingAttr {
+ border-color: #FF4136;
+}
\ No newline at end of file
diff --git a/data/web/css/quarantaine.css b/data/web/css/quarantaine.css
new file mode 100644
index 00000000..7a5ee761
--- /dev/null
+++ b/data/web/css/quarantaine.css
@@ -0,0 +1,37 @@
+table.footable>tbody>tr.footable-empty>td {
+ font-size:15px !important;
+ font-style:italic;
+}
+.pagination a {
+ text-decoration: none !important;
+}
+.panel panel-default {
+ overflow: visible !important;
+}
+.table-responsive {
+ overflow: visible !important;
+}
+@media screen and (max-width: 767px) {
+ .table-responsive {
+ overflow-x: scroll !important;
+ }
+}
+.footer-add-item {
+ display:block;
+ text-align: center;
+ font-style: italic;
+ padding: 10px;
+ background: #F5F5F5;
+}
+@media (min-width: 992px) {
+ .container {
+ width: 80%;
+ }
+}
+.mass-actions-quarantaine {
+ user-select: none;
+ padding:10px 0 10px 10px;
+}
+.inputMissingAttr {
+ border-color: #FF4136;
+}
\ No newline at end of file
diff --git a/data/web/debug.php b/data/web/debug.php
new file mode 100644
index 00000000..289aa84a
--- /dev/null
+++ b/data/web/debug.php
@@ -0,0 +1,328 @@
+<?php
+require_once "inc/prerequisites.inc.php";
+
+if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == "admin") {
+require_once "inc/header.inc.php";
+$_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
+
+?>
+<div class="container">
+
+ <ul class="nav nav-tabs" role="tablist">
+ <li class="dropdown active"><a class="dropdown-toggle" data-toggle="dropdown" href="#">Rspamd
+ <span class="caret"></span></a>
+ <ul class="dropdown-menu">
+ <li role="presentation" class="active"><a href="#tab-rspamd-ui" aria-controls="tab-rspamd-ui" role="tab" data-toggle="tab">Rspamd UI</a></li>
+ <li role="presentation"><a href="#tab-rspamd-settings" aria-controls="tab-rspamd-settings" role="tab" data-toggle="tab">Rspamd settings map</a></li>
+ </ul>
+ </li>
+ <li role="presentation"><a href="#tab-containers" aria-controls="tab-containers" role="tab" data-toggle="tab">Containers</a></li>
+ <li class="dropdown"><a class="dropdown-toggle" data-toggle="dropdown" href="#">Logs
+ <span class="caret"></span></a>
+ <ul class="dropdown-menu">
+ <li role="presentation"><a href="#tab-postfix-logs" aria-controls="tab-postfix-logs" role="tab" data-toggle="tab">Postfix</a></li>
+ <li role="presentation"><a href="#tab-dovecot-logs" aria-controls="tab-dovecot-logs" role="tab" data-toggle="tab">Dovecot</a></li>
+ <li role="presentation"><a href="#tab-sogo-logs" aria-controls="tab-sogo-logs" role="tab" data-toggle="tab">SOGo</a></li>
+ <li role="presentation"><a href="#tab-fail2ban-logs" aria-controls="tab-fail2ban-logs" role="tab" data-toggle="tab">Fail2ban</a></li>
+ <li role="presentation"><a href="#tab-rspamd-history" aria-controls="tab-rspamd-history" role="tab" data-toggle="tab">Rspamd</a></li>
+ <li role="presentation"><a href="#tab-autodiscover-logs" aria-controls="tab-autodiscover-logs" role="tab" data-toggle="tab">Autodiscover</a></li>
+ <li role="presentation"><a href="#tab-watchdog-logs" aria-controls="tab-watchdog-logs" role="tab" data-toggle="tab">Watchdog</a></li>
+ <li role="presentation"><a href="#tab-acme-logs" aria-controls="tab-acme-logs" role="tab" data-toggle="tab">ACME</a></li>
+ <li role="presentation"><a href="#tab-api-logs" aria-controls="tab-api-logs" role="tab" data-toggle="tab">API</a></li>
+ </ul>
+ </li>
+ </ul>
+
+ <div class="row">
+ <div class="col-md-12">
+ <div class="tab-content" style="padding-top:20px">
+
+ <div role="tabpanel" class="tab-pane active" id="tab-rspamd-ui">
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <h3 class="panel-title">Rspamd UI</h3>
+ </div>
+ <div class="panel-body">
+ <div class="row">
+ <div class="col-sm-9">
+ <form class="form-horizontal" autocapitalize="none" data-id="admin" autocorrect="off" role="form" method="post">
+ <div class="form-group">
+ <div class="col-sm-offset-3 col-sm-9">
+ <label>
+ <a href="/rspamd/" target="_blank"><span class="glyphicon glyphicon-new-window" aria-hidden="true"></span> Rspamd UI</a>
+ </label>
+ </div>
+ </div>
+ <div class="form-group">
+ <label class="control-label col-sm-3" for="rspamd_ui_pass"><?=$lang['admin']['password'];?>:</label>
+ <div class="col-sm-9">
+ <input type="password" class="form-control" name="rspamd_ui_pass" id="rspamd_ui_pass">
+ </div>
+ </div>
+ <div class="form-group">
+ <label class="control-label col-sm-3" for="rspamd_ui_pass2"><?=$lang['admin']['password_repeat'];?>:</label>
+ <div class="col-sm-9">
+ <input type="password" class="form-control" name="rspamd_ui_pass2" id="rspamd_ui_pass2">
+ </div>
+ </div>
+ <div class="form-group">
+ <div class="col-sm-offset-3 col-sm-9">
+ <button type="submit" class="btn btn-default" id="rspamd_ui" name="rspamd_ui" href="#"><span class="glyphicon glyphicon-check"></span> <?=$lang['admin']['save'];?></button>
+ </div>
+ </div>
+ </form>
+ </div>
+ <div class="col-sm-3">
+ <img class="img-responsive" src="/img/rspamd_logo.png" alt="Rspamd UI" />
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div role="tabpanel" class="tab-pane" id="tab-rspamd-settings">
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <h3 class="panel-title">Rspamd settings map</h3>
+ </div>
+ <div class="panel-body">
+ <textarea autocorrect="off" spellcheck="false" autocapitalize="none" class="form-control" rows="20" id="settings_map" name="settings_map" readonly><?=file_get_contents('http://nginx:8081/settings.php');?></textarea>
+ </div>
+ </div>
+ </div>
+
+ <div role="tabpanel" class="tab-pane" id="tab-containers">
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <h3 class="panel-title">Container information</h3>
+ </div>
+ <div class="panel-body">
+ <ul class="list-group">
+ <?php
+ $container_array = array(
+ 'nginx-mailcow',
+ 'rspamd-mailcow',
+ 'postfix-mailcow',
+ 'dovecot-mailcow',
+ 'sogo-mailcow',
+ 'acme-mailcow',
+ 'memcached-mailcow',
+ 'watchdog-mailcow',
+ 'unbound-mailcow',
+ 'redis-mailcow',
+ 'php-fpm-mailcow',
+ 'mysql-mailcow',
+ 'fail2ban-mailcow',
+ 'clamd-mailcow'
+ );
+ }
+ foreach ($container_array as $container) {
+ $container_stats = docker($container, 'info');
+ ?>
+ <li class="list-group-item">
+ <?=$container;?>
+ <?php
+ date_default_timezone_set('UTC');
+ $StartedAt = date_parse($container_stats['State']['StartedAt']);
+ $date = new \DateTime();
+ $date->setTimestamp(mktime(
+ $StartedAt['hour'],
+ $StartedAt['minute'],
+ $StartedAt['second'],
+ $StartedAt['month'],
+ $StartedAt['day'],
+ $StartedAt['year']));
+ $user_tz = new DateTimeZone(getenv('TZ'));
+ $date->setTimezone($user_tz);
+ $started = $date->format('r');
+ ?>
+ <small>(Started on <?=$started;?>),
+ <a href data-toggle="modal" data-container="<?=$container;?>" data-target="#RestartContainer">Restart</a></small>
+ <span class="pull-right label label-<?=($container_stats['State']['Running'] == 1) ? 'success' : 'danger';?>"> </span>
+ </li>
+ <?php
+ }
+ ?>
+ </ul>
+ </div>
+ </div>
+ </div>
+
+ <div role="tabpanel" class="tab-pane" id="tab-postfix-logs">
+ <div class="panel panel-default">
+ <div class="panel-heading">Postfix <span class="badge badge-info log-lines"></span>
+ <div class="btn-group pull-right">
+ <button class="btn btn-xs btn-default add_log_lines" data-post-process="general_syslog" data-table="postfix_log" data-log-url="postfix" data-nrows="100">+ 100</button>
+ <button class="btn btn-xs btn-default add_log_lines" data-post-process="general_syslog" data-table="postfix_log" data-log-url="postfix" data-nrows="1000">+ 1000</button>
+ <button class="btn btn-xs btn-default" id="refresh_postfix_log"><?=$lang['admin']['refresh'];?></button>
+ </div>
+ </div>
+ <div class="panel-body">
+ <div class="table-responsive">
+ <table class="table table-striped table-condensed" id="postfix_log"></table>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div role="tabpanel" class="tab-pane" id="tab-dovecot-logs">
+ <div class="panel panel-default">
+ <div class="panel-heading">Dovecot <span class="badge badge-info log-lines"></span>
+ <div class="btn-group pull-right">
+ <button class="btn btn-xs btn-default add_log_lines" data-post-process="general_syslog" data-table="dovecot_log" data-log-url="dovecot" data-nrows="100">+ 100</button>
+ <button class="btn btn-xs btn-default add_log_lines" data-post-process="general_syslog" data-table="dovecot_log" data-log-url="dovecot" data-nrows="1000">+ 1000</button>
+ <button class="btn btn-xs btn-default" id="refresh_dovecot_log"><?=$lang['admin']['refresh'];?></button>
+ </div>
+ </div>
+ <div class="panel-body">
+ <div class="table-responsive">
+ <table class="table table-striped table-condensed" id="dovecot_log"></table>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div role="tabpanel" class="tab-pane" id="tab-sogo-logs">
+ <div class="panel panel-default">
+ <div class="panel-heading">SOGo <span class="badge badge-info log-lines"></span>
+ <div class="btn-group pull-right">
+ <button class="btn btn-xs btn-default add_log_lines" data-post-process="general_syslog" data-table="sogo_log" data-log-url="sogo" data-nrows="100">+ 100</button>
+ <button class="btn btn-xs btn-default add_log_lines" data-post-process="general_syslog" data-table="sogo_log" data-log-url="sogo" data-nrows="1000">+ 1000</button>
+ <button class="btn btn-xs btn-default" id="refresh_sogo_log"><?=$lang['admin']['refresh'];?></button>
+ </div>
+ </div>
+ <div class="panel-body">
+ <div class="table-responsive">
+ <table class="table table-striped table-condensed" id="sogo_log"></table>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div role="tabpanel" class="tab-pane" id="tab-fail2ban-logs">
+ <div class="panel panel-default">
+ <div class="panel-heading">Fail2ban <span class="badge badge-info log-lines"></span>
+ <div class="btn-group pull-right">
+ <button class="btn btn-xs btn-default add_log_lines" data-post-process="general_syslog" data-table="fail2ban_log" data-log-url="fail2ban" data-nrows="100">+ 100</button>
+ <button class="btn btn-xs btn-default add_log_lines" data-post-process="general_syslog" data-table="fail2ban_log" data-log-url="fail2ban" data-nrows="1000">+ 1000</button>
+ <button class="btn btn-xs btn-default" id="refresh_fail2ban_log"><?=$lang['admin']['refresh'];?></button>
+ </div>
+ </div>
+ <div class="panel-body">
+ <div class="table-responsive">
+ <table class="table table-striped table-condensed" id="fail2ban_log"></table>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div role="tabpanel" class="tab-pane" id="tab-rspamd-history">
+ <div class="panel panel-default">
+ <div class="panel-heading">Rspamd history <span class="badge badge-info log-lines"></span>
+ <div class="btn-group pull-right">
+ <button class="btn btn-xs btn-default add_log_lines" data-post-process="rspamd_history" data-table="rspamd_history" data-log-url="rspamd-history" data-nrows="100">+ 100</button>
+ <button class="btn btn-xs btn-default add_log_lines" data-post-process="rspamd_history" data-table="rspamd_history" data-log-url="rspamd-history" data-nrows="1000">+ 1000</button>
+ <button class="btn btn-xs btn-default" id="refresh_rspamd_history"><?=$lang['admin']['refresh'];?></button>
+ </div>
+ </div>
+ <div class="panel-body">
+ <div class="table-responsive">
+ <table class="table table-striped table-condensed log-table" id="rspamd_history"></table>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div role="tabpanel" class="tab-pane" id="tab-autodiscover-logs">
+ <div class="panel panel-default">
+ <div class="panel-heading">Autodiscover <span class="badge badge-info log-lines"></span>
+ <div class="btn-group pull-right">
+ <button class="btn btn-xs btn-default add_log_lines" data-post-process="autodiscover_log" data-table="autodiscover_log" data-log-url="autodiscover" data-nrows="100">+ 100</button>
+ <button class="btn btn-xs btn-default add_log_lines" data-post-process="autodiscover_log" data-table="autodiscover_log" data-log-url="autodiscover" data-nrows="1000">+ 1000</button>
+ <button class="btn btn-xs btn-default" id="refresh_autodiscover_log"><?=$lang['admin']['refresh'];?></button>
+ </div>
+ </div>
+ <div class="panel-body">
+ <div class="table-responsive">
+ <table class="table table-striped table-condensed" id="autodiscover_log"></table>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div role="tabpanel" class="tab-pane" id="tab-watchdog-logs">
+ <div class="panel panel-default">
+ <div class="panel-heading">Watchdog <span class="badge badge-info log-lines"></span>
+ <div class="btn-group pull-right">
+ <button class="btn btn-xs btn-default add_log_lines" data-post-process="watchdog" data-table="watchdog_log" data-log-url="watchdog" data-nrows="100">+ 100</button>
+ <button class="btn btn-xs btn-default add_log_lines" data-post-process="watchdog" data-table="watchdog_log" data-log-url="watchdog" data-nrows="1000">+ 1000</button>
+ <button class="btn btn-xs btn-default" id="refresh_watchdog_log"><?=$lang['admin']['refresh'];?></button>
+ </div>
+ </div>
+ <div class="panel-body">
+ <div class="table-responsive">
+ <table class="table table-striped table-condensed" id="watchdog_log"></table>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div role="tabpanel" class="tab-pane" id="tab-acme-logs">
+ <div class="panel panel-default">
+ <div class="panel-heading">ACME <span class="badge badge-info log-lines"></span>
+ <div class="btn-group pull-right">
+ <button class="btn btn-xs btn-default add_log_lines" data-post-process="general_syslog" data-table="acme_log" data-log-url="acme" data-nrows="100">+ 100</button>
+ <button class="btn btn-xs btn-default add_log_lines" data-post-process="general_syslog" data-table="acme_log" data-log-url="acme" data-nrows="1000">+ 1000</button>
+ <button class="btn btn-xs btn-default" id="refresh_acme_log"><?=$lang['admin']['refresh'];?></button>
+ </div>
+ </div>
+ <div class="panel-body">
+ <div class="table-responsive">
+ <table class="table table-striped table-condensed" id="acme_log"></table>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div role="tabpanel" class="tab-pane" id="tab-api-logs">
+ <div class="panel panel-default">
+ <div class="panel-heading">API <span class="badge badge-info log-lines"></span>
+ <div class="btn-group pull-right">
+ <button class="btn btn-xs btn-default add_log_lines" data-post-process="apilog" data-table="api_log" data-log-url="api" data-nrows="100">+ 100</button>
+ <button class="btn btn-xs btn-default add_log_lines" data-post-process="apilog" data-table="api_log" data-log-url="api" data-nrows="1000">+ 1000</button>
+ <button class="btn btn-xs btn-default" id="refresh_api_log"><?=$lang['admin']['refresh'];?></button>
+ </div>
+ </div>
+ <div class="panel-body">
+ <div class="table-responsive">
+ <table class="table table-striped table-condensed" id="api_log"></table>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ </div> <!-- /tab-content -->
+ </div> <!-- /col-md-12 -->
+ </div> <!-- /row -->
+</div> <!-- /container -->
+<?php
+require_once $_SERVER['DOCUMENT_ROOT'] . '/modals/debug.php';
+?>
+<script type='text/javascript'>
+<?php
+$lang_admin = json_encode($lang['admin']);
+echo "var lang = ". $lang_admin . ";\n";
+echo "var csrf_token = '". $_SESSION['CSRF']['TOKEN'] . "';\n";
+echo "var log_pagination_size = '". $LOG_PAGINATION_SIZE . "';\n";
+
+?>
+</script>
+<script src="js/footable.min.js"></script>
+<script src="js/debug.js"></script>
+<?php
+require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/footer.inc.php';
+} else {
+ header('Location: /');
+ exit();
+}
+?>
diff --git a/data/web/img/rspamd_logo.png b/data/web/img/rspamd_logo.png
new file mode 100644
index 00000000..0e97426d
Binary files /dev/null and b/data/web/img/rspamd_logo.png differ
diff --git a/data/web/inc/ajax/container_ctrl.php b/data/web/inc/ajax/container_ctrl.php
new file mode 100644
index 00000000..d12f5767
--- /dev/null
+++ b/data/web/inc/ajax/container_ctrl.php
@@ -0,0 +1,53 @@
+<?php
+session_start();
+require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/prerequisites.inc.php';
+if (!isset($_SESSION['mailcow_cc_role']) || $_SESSION['mailcow_cc_role'] != 'admin') {
+ exit();
+}
+
+if (preg_match('/^[a-z\-]{0,}-mailcow/', $_GET['service'])) {
+ if ($_GET['action'] == "start") {
+ header('Content-Type: text/html; charset=utf-8');
+ $retry = 0;
+ while (docker($_GET['service'], 'info')['State']['Running'] != 1 && $retry <= 3) {
+ $response = docker($_GET['service'], 'post', 'start');
+ $response = json_decode($response, true);
+ $last_response = ($response['type'] == "success") ? '<b><span class="pull-right text-success">OK</span></b>' : '<b><span class="pull-right text-danger">Error: ' . $response['msg'] . '</span></b>';
+ if ($response['type'] == "success") {
+ break;
+ }
+ usleep(1500000);
+ $retry++;
+ }
+ echo (!isset($last_response)) ? '<b><span class="pull-right text-warning">Already running</span></b>' : $last_response;
+ }
+ if ($_GET['action'] == "stop") {
+ header('Content-Type: text/html; charset=utf-8');
+ $retry = 0;
+ while (docker($_GET['service'], 'info')['State']['Running'] == 1 && $retry <= 3) {
+ $response = docker($_GET['service'], 'post', 'stop');
+ $response = json_decode($response, true);
+ $last_response = ($response['type'] == "success") ? '<b><span class="pull-right text-success">OK</span></b>' : '<b><span class="pull-right text-danger">Error: ' . $response['msg'] . '</span></b>';
+ if ($response['type'] == "success") {
+ break;
+ }
+ usleep(1500000);
+ $retry++;
+ }
+ echo (!isset($last_response)) ? '<b><span class="pull-right text-warning">Not running</span></b>' : $last_response;
+ }
+ if ($_GET['action'] == "restart") {
+ header('Content-Type: text/html; charset=utf-8');
+ $response = docker($_GET['service'], 'post', 'restart');
+ $response = json_decode($response, true);
+ $last_response = ($response['type'] == "success") ? '<b><span class="pull-right text-success">OK</span></b>' : '<b><span class="pull-right text-danger">Error: ' . $response['msg'] . '</span></b>';
+ echo (!isset($last_response)) ? '<b><span class="pull-right text-warning">Cannot restart container</span></b>' : $last_response;
+ }
+ if ($_GET['action'] == "logs") {
+ $lines = (empty($_GET['lines']) || !is_numeric($_GET['lines'])) ? 1000 : $_GET['lines'];
+ header('Content-Type: text/plain; charset=utf-8');
+ print_r(preg_split('/\n/', docker($_GET['service'], 'logs', $lines)));
+ }
+}
+
+?>
diff --git a/data/web/inc/ajax/log_driver.php b/data/web/inc/ajax/log_driver.php
new file mode 100644
index 00000000..319f672d
--- /dev/null
+++ b/data/web/inc/ajax/log_driver.php
@@ -0,0 +1,12 @@
+<?php
+session_start();
+require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/prerequisites.inc.php';
+header('Content-Type: text/plain');
+if (!isset($_SESSION['mailcow_cc_role'])) {
+ exit();
+}
+if (isset($_GET['type']) && isset($_GET['msg'])) {
+ global $mailcow_hostname;
+ //empty
+}
+?>
diff --git a/data/web/inc/ajax/qitem_details.php b/data/web/inc/ajax/qitem_details.php
new file mode 100644
index 00000000..a4b80be1
--- /dev/null
+++ b/data/web/inc/ajax/qitem_details.php
@@ -0,0 +1,83 @@
+<?php
+session_start();
+header("Content-Type: application/json");
+require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/prerequisites.inc.php';
+if (!isset($_SESSION['mailcow_cc_role'])) {
+ exit();
+}
+function rrmdir($src) {
+ $dir = opendir($src);
+ while(false !== ( $file = readdir($dir)) ) {
+ if (( $file != '.' ) && ( $file != '..' )) {
+ $full = $src . '/' . $file;
+ if ( is_dir($full) ) {
+ rrmdir($full);
+ }
+ else {
+ unlink($full);
+ }
+ }
+ }
+ closedir($dir);
+ rmdir($src);
+}
+if (!empty($_GET['id']) && ctype_alnum($_GET['id'])) {
+ $tmpdir = '/tmp/' . $_GET['id'] . '/';
+ $mailc = quarantaine('details', $_GET['id']);
+ if (strlen($mailc['msg']) > 10485760) {
+ echo json_encode(array('error' => 'Message size exceeds 10 MiB.'));
+ exit;
+ }
+ if (!empty($mailc['msg'])) {
+ // Init message array
+ $data = array();
+ // Init parser
+ $mail_parser = new PhpMimeMailParser\Parser();
+ // Load msg to parser
+ $mail_parser->setText($mailc['msg']);
+ // Get text/plain content
+ $data['text_plain'] = $mail_parser->getMessageBody('text');
+ // Get subject
+ $data['subject'] = $mail_parser->getHeader('subject');
+ // Get attachments
+ if (is_dir($tmpdir)) {
+ rrmdir($tmpdir);
+ }
+ mkdir('/tmp/' . $_GET['id']);
+ $mail_parser->saveAttachments($tmpdir, true);
+ $atts = $mail_parser->getAttachments(true);
+ if (count($atts) > 0) {
+ foreach ($atts as $key => $val) {
+ $data['attachments'][$key] = array(
+ // Index
+ // 0 => file name
+ // 1 => mime type
+ // 2 => file size
+ // 3 => vt link by sha256
+ $val->getFilename(),
+ $val->getContentType(),
+ filesize($tmpdir . $val->getFilename()),
+ 'https://www.virustotal.com/file/' . hash_file('SHA256', $tmpdir . $val->getFilename()) . '/analysis/'
+ );
+ }
+ }
+ if (isset($_GET['att'])) {
+ $dl_id = intval($_GET['att']);
+ $dl_filename = $data['attachments'][$dl_id][0];
+ if (!is_dir($tmpdir . $dl_filename) && file_exists($tmpdir . $dl_filename)) {
+ header('Pragma: public');
+ header('Expires: 0');
+ header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
+ header('Cache-Control: private', false);
+ header('Content-Type: ' . $data['attachments'][$dl_id][1]);
+ header('Content-Disposition: attachment; filename="'. $dl_filename . '";');
+ header('Content-Transfer-Encoding: binary');
+ header('Content-Length: ' . $data['attachments'][$dl_id][2]);
+ readfile($tmpdir . $dl_filename);
+ exit;
+ }
+ }
+ echo json_encode($data);
+ }
+}
+?>
diff --git a/data/web/inc/ajax/sogo_ctrl.php b/data/web/inc/ajax/sogo_ctrl.php
deleted file mode 100644
index e238d9c0..00000000
--- a/data/web/inc/ajax/sogo_ctrl.php
+++ /dev/null
@@ -1,39 +0,0 @@
-<?php
-session_start();
-require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/prerequisites.inc.php';
-header('Content-Type: text/html; charset=utf-8');
-if (!isset($_SESSION['mailcow_cc_role']) || $_SESSION['mailcow_cc_role'] != 'admin') {
- exit();
-}
-
-if ($_GET['ACTION'] == "start") {
- $retry = 0;
- while (docker('sogo-mailcow', 'info')['State']['Running'] != 1 && $retry <= 3) {
- $response = docker('sogo-mailcow', 'post', 'start');
- $response = json_decode($response, true);
- $last_response = ($response['type'] == "success") ? '<b><span class="pull-right text-success">OK</span></b>' : '<b><span class="pull-right text-danger">Error: ' . $response['msg'] . '</span></b>';
- if ($response['type'] == "success") {
- break;
- }
- usleep(1500000);
- $retry++;
- }
- echo (!isset($last_response)) ? '<b><span class="pull-right text-warning">Already running</span></b>' : $last_response;
-}
-
-if ($_GET['ACTION'] == "stop") {
- $retry = 0;
- while (docker('sogo-mailcow', 'info')['State']['Running'] == 1 && $retry <= 3) {
- $response = docker('sogo-mailcow', 'post', 'stop');
- $response = json_decode($response, true);
- $last_response = ($response['type'] == "success") ? '<b><span class="pull-right text-success">OK</span></b>' : '<b><span class="pull-right text-danger">Error: ' . $response['msg'] . '</span></b>';
- if ($response['type'] == "success") {
- break;
- }
- usleep(1500000);
- $retry++;
- }
- echo (!isset($last_response)) ? '<b><span class="pull-right text-warning">Not running</span></b>' : $last_response;
-}
-
-?>
diff --git a/data/web/inc/footer.inc.php b/data/web/inc/footer.inc.php
index 3ba758be..a082211b 100644
--- a/data/web/inc/footer.inc.php
+++ b/data/web/inc/footer.inc.php
@@ -8,6 +8,7 @@ require_once $_SERVER['DOCUMENT_ROOT'] . '/modals/footer.php';
<script src="/js/bootstrap-select.min.js"></script>
<script src="/js/bootstrap-filestyle.min.js"></script>
<script src="/js/notifications.min.js"></script>
+<script src="/js/formcache.min.js"></script>
<script src="/js/numberedtextarea.min.js"></script>
<script src="/js/u2f-api.js"></script>
<script src="/js/api.js"></script>
@@ -26,11 +27,19 @@ $(document).ready(function() {
msg = $('<span/>').html(message).text();
if (type == 'danger') {
auto_hide = 0;
+ $('#' + localStorage.getItem("add_modal")).modal('show');
+ localStorage.removeItem("add_modal");
} else {
auto_hide = 5000;
}
+ $.ajax({
+ url: '/inc/ajax/log_driver.php',
+ data: {"type": type,"msg": msg},
+ type: "GET"
+ });
$.notify({message: msg},{z_index: 20000, delay: auto_hide, type: type,placement: {from: "bottom",align: "right"},animate: {enter: 'animated fadeInUp',exit: 'animated fadeOutDown'}});
}
+ $('[data-cached-form="true"]').formcache({key: $(this).data('id')});
<?php if (isset($_SESSION['return'])): ?>
mailcow_alert_box(<?=json_encode($_SESSION['return']['msg']); ?>, "<?= $_SESSION['return']['type']; ?>");
<?php endif; unset($_SESSION['return']); ?>
@@ -118,13 +127,8 @@ $(document).ready(function() {
}
});
- // Activate tooltips
$(function () {
$('[data-toggle="tooltip"]').tooltip()
- })
- // Hide alerts after n seconds
- $("#alert-fade").fadeTo(7000, 500).slideUp(500, function(){
- $("#alert-fade").alert('close');
});
// Remember last navigation pill
@@ -173,36 +177,32 @@ $(document).ready(function() {
// Init Bootstrap Selectpicker
$('select').selectpicker();
- // Trigger SOGo restart
- $('#triggerRestartSogo').click(function(){
- $(this).prop("disabled",true);
- $(this).html('<span class="glyphicon glyphicon-refresh glyphicon-spin"></span> ');
- $('#statusTriggerRestartSogo').text('Stopping SOGo workers, this may take a while... ');
- $.ajax({
- method: 'get',
- url: '/inc/ajax/sogo_ctrl.php',
- data: {
- 'ajax': true,
- 'ACTION': 'stop'
- },
- success: function(data) {
- $('#statusTriggerRestartSogo').append(data);
- $('#statusTriggerRestartSogo').append('<br>Starting SOGo...');
- $.ajax({
- method: 'get',
- url: '/inc/ajax/sogo_ctrl.php',
- data: {
- 'ajax': true,
- 'ACTION': 'start'
- },
- success: function(data) {
- $('#statusTriggerRestartSogo').append(data);
- $('#triggerRestartSogo').html('<span class="glyphicon glyphicon-ok"></span> ');
- }
- });
- }
+ // Trigger container restart
+ $('#RestartContainer').on('show.bs.modal', function(e) {
+ var container = $(e.relatedTarget).data('container');
+ $('#containerName').text(container);
+ $('#triggerRestartContainer').click(function(){
+ $(this).prop("disabled",true);
+ $(this).html('<span class="glyphicon glyphicon-refresh glyphicon-spin"></span> ');
+ $('#statusTriggerRestartContainer').text('Restarting container, this may take a while... ');
+ $.ajax({
+ method: 'get',
+ url: '/inc/ajax/container_ctrl.php',
+ timeout: 3000,
+ data: {
+ 'service': container,
+ 'action': 'restart'
+ },
+ error: function() {
+ window.location = window.location.href.split("#")[0];
+ },
+ success: function(data) {
+ $('#statusTriggerRestartContainer').append(data);
+ $('#triggerRestartContainer').html('<span class="glyphicon glyphicon-ok"></span> ');
+ }
+ });
});
- });
+ })
// CSRF
$('<input type="hidden" value="<?= $_SESSION['CSRF']['TOKEN']; ?>">').attr('id', 'csrf_token').attr('name', 'csrf_token').appendTo('form');
@@ -216,4 +216,4 @@ $(document).ready(function() {
</html>
<?php
$stmt = null;
-$pdo = null;
\ No newline at end of file
+$pdo = null;
diff --git a/data/web/inc/functions.customize.inc.php b/data/web/inc/functions.customize.inc.php
index 7e8f7b03..e3d8c64d 100644
--- a/data/web/inc/functions.customize.inc.php
+++ b/data/web/inc/functions.customize.inc.php
@@ -18,7 +18,7 @@ function customize($_action, $_item, $_data = null) {
if (file_exists($_data['main_logo']['tmp_name']) !== true) {
$_SESSION['return'] = array(
'type' => 'danger',
- 'msg' => 'Cannot validate image file: Temporary file not found'
+ 'msg' => $lang['danger']['img_tmp_missing']
);
return false;
}
@@ -26,7 +26,7 @@ function customize($_action, $_item, $_data = null) {
if ($image->valid() !== true) {
$_SESSION['return'] = array(
'type' => 'danger',
- 'msg' => 'Cannot validate image file'
+ 'msg' => $lang['danger']['img_invalid']
);
return false;
}
@@ -35,7 +35,7 @@ function customize($_action, $_item, $_data = null) {
catch (ImagickException $e) {
$_SESSION['return'] = array(
'type' => 'danger',
- 'msg' => 'Cannot validate image file'
+ 'msg' => $lang['danger']['img_invalid']
);
return false;
}
@@ -43,7 +43,7 @@ function customize($_action, $_item, $_data = null) {
else {
$_SESSION['return'] = array(
'type' => 'danger',
- 'msg' => 'Invalid mime type'
+ 'msg' => $lang['danger']['invalid_mime_type']
);
return false;
}
@@ -59,7 +59,7 @@ function customize($_action, $_item, $_data = null) {
}
$_SESSION['return'] = array(
'type' => 'success',
- 'msg' => 'File uploaded successfully'
+ 'msg' => $lang['success']['upload_success']
);
break;
}
@@ -77,7 +77,7 @@ function customize($_action, $_item, $_data = null) {
$apps = (array)$_data['app'];
$links = (array)$_data['href'];
$out = array();
- if (count($apps) == count($links)) {;
+ if (count($apps) == count($links)) {
for ($i = 0; $i < count($apps); $i++) {
$out[] = array($apps[$i] => $links[$i]);
}
@@ -94,7 +94,28 @@ function customize($_action, $_item, $_data = null) {
}
$_SESSION['return'] = array(
'type' => 'success',
- 'msg' => 'Saved changes to app links'
+ 'msg' => $lang['success']['app_links']
+ );
+ break;
+ case 'ui_texts':
+ $main_name = $_data['main_name'];
+ $apps_name = $_data['apps_name'];
+ $help_text = $_data['help_text'];
+ try {
+ $redis->set('MAIN_NAME', htmlspecialchars($main_name));
+ $redis->set('APPS_NAME', htmlspecialchars($apps_name));
+ $redis->set('HELP_TEXT', $help_text);
+ }
+ catch (RedisException $e) {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => 'Redis: '.$e
+ );
+ return false;
+ }
+ $_SESSION['return'] = array(
+ 'type' => 'success',
+ 'msg' => $lang['success']['ui_texts']
);
break;
}
@@ -113,7 +134,7 @@ function customize($_action, $_item, $_data = null) {
if ($redis->del('MAIN_LOGO')) {
$_SESSION['return'] = array(
'type' => 'success',
- 'msg' => 'Reset default logo'
+ 'msg' => $lang['success']['reset_main_logo']
);
return true;
}
@@ -155,6 +176,21 @@ function customize($_action, $_item, $_data = null) {
return false;
}
break;
+ case 'ui_texts':
+ try {
+ $data['main_name'] = ($main_name = $redis->get('MAIN_NAME')) ? $main_name : 'mailcow UI';
+ $data['apps_name'] = ($apps_name = $redis->get('APPS_NAME')) ? $apps_name : 'mailcow Apps';
+ $data['help_text'] = ($help_text = $redis->get('HELP_TEXT')) ? $help_text : false;
+ return $data;
+ }
+ catch (RedisException $e) {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => 'Redis: '.$e
+ );
+ return false;
+ }
+ break;
case 'main_logo_specs':
try {
$image = new Imagick();
@@ -167,7 +203,7 @@ function customize($_action, $_item, $_data = null) {
catch (ImagickException $e) {
$_SESSION['return'] = array(
'type' => 'danger',
- 'msg' => 'Error: Imagick exception while reading image'
+ 'msg' => $lang['danger']['imagick_exception']
);
return false;
}
diff --git a/data/web/inc/functions.docker.inc.php b/data/web/inc/functions.docker.inc.php
index a5f2581c..7cd5ed4e 100644
--- a/data/web/inc/functions.docker.inc.php
+++ b/data/web/inc/functions.docker.inc.php
@@ -1,5 +1,12 @@
<?php
-function docker($service_name, $action, $post_action = null, $post_fields = null) {
+function docker($service_name, $action, $attr1 = null, $attr2 = null, $extra_headers = null) {
+ if ($_SESSION['mailcow_cc_role'] != "admin") {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => sprintf($lang['danger']['access_denied'])
+ );
+ return false;
+ }
$curl = curl_init();
curl_setopt($curl, CURLOPT_HTTPHEADER,array( 'Content-Type: application/json' ));
switch($action) {
@@ -52,14 +59,44 @@ function docker($service_name, $action, $post_action = null, $post_fields = null
return false;
}
break;
+ case 'logs':
+ $container_id = docker($service_name, 'get_id');
+ if (ctype_xdigit($container_id)) {
+ $lines = (empty($attr1) || !is_numeric($attr1)) ? 100 : $attr1;
+ curl_setopt($curl, CURLOPT_URL, 'http://dockerapi:8080/containers/' . $container_id . '/logs/' . $lines);
+ curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
+ curl_setopt($curl, CURLOPT_POST, 0);
+ $response = curl_exec($curl);
+ if ($response === false) {
+ $err = curl_error($curl);
+ curl_close($curl);
+ return $err;
+ }
+ else {
+ curl_close($curl);
+ if (empty($response)) {
+ return true;
+ }
+ else {
+ return json_decode($response, true);
+ }
+ }
+ }
+ else {
+ return false;
+ }
+ break;
case 'post':
- if (!empty($post_action)) {
+ if (!empty($attr1)) {
$container_id = docker($service_name, 'get_id');
- if (ctype_xdigit($container_id) && ctype_alnum($post_action)) {
- curl_setopt($curl, CURLOPT_URL, 'http://dockerapi:8080/containers/' . $container_id . '/' . $post_action);
+ if (ctype_xdigit($container_id) && ctype_alnum($attr1)) {
+ curl_setopt($curl, CURLOPT_URL, 'http://dockerapi:8080/containers/' . $container_id . '/' . $attr1);
curl_setopt($curl, CURLOPT_POST, 1);
- if (!empty($post_fields)) {
- curl_setopt( $curl, CURLOPT_POSTFIELDS, json_encode($post_fields));
+ if (!empty($attr2)) {
+ curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($attr2));
+ }
+ if (!empty($extra_headers) && is_array($extra_headers)) {
+ curl_setopt($curl, CURLOPT_HTTPHEADER, $extra_headers);
}
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec($curl);
diff --git a/data/web/inc/functions.fail2ban.inc.php b/data/web/inc/functions.fail2ban.inc.php
index 6c9e1692..e1801be7 100644
--- a/data/web/inc/functions.fail2ban.inc.php
+++ b/data/web/inc/functions.fail2ban.inc.php
@@ -1,5 +1,4 @@
<?php
-if (F2B == 1) {
function fail2ban($_action, $_data = null) {
global $redis;
global $lang;
@@ -97,4 +96,3 @@ function fail2ban($_action, $_data = null) {
break;
}
}
-}
diff --git a/data/web/inc/functions.inc.php b/data/web/inc/functions.inc.php
index 1ba9e644..34e24028 100644
--- a/data/web/inc/functions.inc.php
+++ b/data/web/inc/functions.inc.php
@@ -443,14 +443,31 @@ function user_get_alias_details($username) {
}
try {
$data['address'] = $username;
- $stmt = $pdo->prepare("SELECT IFNULL(GROUP_CONCAT(`address` SEPARATOR ', '), '✘') AS `aliases` FROM `alias`
+ $stmt = $pdo->prepare("SELECT IFNULL(GROUP_CONCAT(`address` SEPARATOR ', '), '✘') AS `shared_aliases` FROM `alias`
WHERE `goto` REGEXP :username_goto
AND `address` NOT LIKE '@%'
+ AND `goto` != :username_goto2
AND `address` != :username_address");
- $stmt->execute(array(':username_goto' => '(^|,)'.$username.'($|,)', ':username_address' => $username));
+ $stmt->execute(array(
+ ':username_goto' => '(^|,)'.$username.'($|,)',
+ ':username_goto2' => $username,
+ ':username_address' => $username
+ ));
$run = $stmt->fetchAll(PDO::FETCH_ASSOC);
while ($row = array_shift($run)) {
- $data['aliases'] = $row['aliases'];
+ $data['shared_aliases'] = $row['shared_aliases'];
+ }
+ $stmt = $pdo->prepare("SELECT IFNULL(GROUP_CONCAT(`address` SEPARATOR ', '), '✘') AS `direct_aliases` FROM `alias`
+ WHERE `goto` = :username_goto
+ AND `address` != :username_address");
+ $stmt->execute(
+ array(
+ ':username_goto' => $username,
+ ':username_address' => $username
+ ));
+ $run = $stmt->fetchAll(PDO::FETCH_ASSOC);
+ while ($row = array_shift($run)) {
+ $data['direct_aliases'] = $row['direct_aliases'];
}
$stmt = $pdo->prepare("SELECT IFNULL(GROUP_CONCAT(local_part, '@', alias_domain SEPARATOR ', '), '✘') AS `ad_alias` FROM `mailbox`
LEFT OUTER JOIN `alias_domain` on `target_domain` = `domain`
@@ -851,6 +868,135 @@ function verify_tfa_login($username, $token) {
}
return false;
}
+function admin_api($action, $data = null) {
+ global $pdo;
+ global $lang;
+ if ($_SESSION['mailcow_cc_role'] != "admin") {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => sprintf($lang['danger']['access_denied'])
+ );
+ return false;
+ }
+ switch ($action) {
+ case "edit":
+ $regen_key = $data['admin_api_regen_key'];
+ $active = (isset($data['active'])) ? 1 : 0;
+ $allow_from = array_map('trim', preg_split( "/( |,|;|\n)/", $data['allow_from']));
+ foreach ($allow_from as $key => $val) {
+ if (!filter_var($val, FILTER_VALIDATE_IP)) {
+ unset($allow_from[$key]);
+ continue;
+ }
+ }
+ $allow_from = implode(',', array_unique(array_filter($allow_from)));
+ if (empty($allow_from)) {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => 'List of allowed IPs cannot be empty'
+ );
+ return false;
+ }
+ $api_key = implode('-', array(
+ strtoupper(bin2hex(random_bytes(3))),
+ strtoupper(bin2hex(random_bytes(3))),
+ strtoupper(bin2hex(random_bytes(3))),
+ strtoupper(bin2hex(random_bytes(3))),
+ strtoupper(bin2hex(random_bytes(3)))
+ ));
+ $stmt = $pdo->prepare("INSERT INTO `api` (`username`, `api_key`, `active`, `allow_from`)
+ SELECT `username`, :api_key, :active, :allow_from FROM `admin` WHERE `superadmin`='1' AND `active`='1'
+ ON DUPLICATE KEY UPDATE `active` = :active_u, `allow_from` = :allow_from_u ;");
+ $stmt->execute(array(
+ ':api_key' => $api_key,
+ ':active' => $active,
+ ':active_u' => $active,
+ ':allow_from' => $allow_from,
+ ':allow_from_u' => $allow_from
+ ));
+ break;
+ case "regen_key":
+ $api_key = implode('-', array(
+ strtoupper(bin2hex(random_bytes(3))),
+ strtoupper(bin2hex(random_bytes(3))),
+ strtoupper(bin2hex(random_bytes(3))),
+ strtoupper(bin2hex(random_bytes(3))),
+ strtoupper(bin2hex(random_bytes(3)))
+ ));
+ $stmt = $pdo->prepare("UPDATE `api` SET `api_key` = :api_key WHERE `username` IN
+ (SELECT `username` FROM `admin` WHERE `superadmin`='1' AND `active`='1')");
+ $stmt->execute(array(
+ ':api_key' => $api_key
+ ));
+ break;
+ }
+ $_SESSION['return'] = array(
+ 'type' => 'success',
+ 'msg' => sprintf($lang['success']['admin_modified'])
+ );
+}
+function rspamd_ui($action, $data = null) {
+ global $lang;
+ if ($_SESSION['mailcow_cc_role'] != "admin") {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => sprintf($lang['danger']['access_denied'])
+ );
+ return false;
+ }
+ switch ($action) {
+ case "edit":
+ $rspamd_ui_pass = $data['rspamd_ui_pass'];
+ $rspamd_ui_pass2 = $data['rspamd_ui_pass2'];
+ if (empty($rspamd_ui_pass) || empty($rspamd_ui_pass2)) {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => 'Password cannot be empty'
+ );
+ return false;
+ }
+ if ($rspamd_ui_pass != $rspamd_ui_pass2) {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => 'Passwords do not match'
+ );
+ return false;
+ }
+ if (strlen($rspamd_ui_pass) < 6) {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => 'Please use at least 6 characters for your password'
+ );
+ return false;
+ }
+ $docker_return = docker('rspamd-mailcow', 'post', 'exec', array('cmd' => 'worker_password', 'raw' => $rspamd_ui_pass), array('Content-Type: application/json'));
+ if ($docker_return_array = json_decode($docker_return, true)) {
+ if ($docker_return_array['type'] == 'success') {
+ $_SESSION['return'] = array(
+ 'type' => 'success',
+ 'msg' => 'Rspamd UI password set successfully'
+ );
+ return true;
+ }
+ else {
+ $_SESSION['return'] = array(
+ 'type' => $docker_return_array['type'],
+ 'msg' => $docker_return_array['msg']
+ );
+ return false;
+ }
+ }
+ else {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => 'Unknown error'
+ );
+ return false;
+ }
+ break;
+ }
+
+}
function get_admin_details() {
// No parameter to be given, only one admin should exist
global $pdo;
@@ -860,8 +1006,10 @@ function get_admin_details() {
return false;
}
try {
- $stmt = $pdo->prepare("SELECT `username`, `modified`, `created` FROM `admin` WHERE `superadmin`='1' AND active='1'");
- $stmt->execute();
+ $stmt = $pdo->query("SELECT `admin`.`username`, `api`.`active` AS `api_active`, `api`.`api_key`, `api`.`allow_from` FROM `admin`
+ INNER JOIN `api` ON `admin`.`username` = `api`.`username`
+ WHERE `admin`.`superadmin`='1'
+ AND `admin`.`active`='1'");
$data = $stmt->fetch(PDO::FETCH_ASSOC);
}
catch(PDOException $e) {
@@ -932,6 +1080,51 @@ function get_logs($container, $lines = false) {
return $data_array;
}
}
+ if ($container == "watchdog-mailcow") {
+ if (!is_numeric($lines)) {
+ list ($from, $to) = explode('-', $lines);
+ $data = $redis->lRange('WATCHDOG_LOG', intval($from), intval($to));
+ }
+ else {
+ $data = $redis->lRange('WATCHDOG_LOG', 0, intval($lines));
+ }
+ if ($data) {
+ foreach ($data as $json_line) {
+ $data_array[] = json_decode($json_line, true);
+ }
+ return $data_array;
+ }
+ }
+ if ($container == "acme-mailcow") {
+ if (!is_numeric($lines)) {
+ list ($from, $to) = explode('-', $lines);
+ $data = $redis->lRange('ACME_LOG', intval($from), intval($to));
+ }
+ else {
+ $data = $redis->lRange('ACME_LOG', 0, intval($lines));
+ }
+ if ($data) {
+ foreach ($data as $json_line) {
+ $data_array[] = json_decode($json_line, true);
+ }
+ return $data_array;
+ }
+ }
+ if ($container == "api-mailcow") {
+ if (!is_numeric($lines)) {
+ list ($from, $to) = explode('-', $lines);
+ $data = $redis->lRange('API_LOG', intval($from), intval($to));
+ }
+ else {
+ $data = $redis->lRange('API_LOG', 0, intval($lines));
+ }
+ if ($data) {
+ foreach ($data as $json_line) {
+ $data_array[] = json_decode($json_line, true);
+ }
+ return $data_array;
+ }
+ }
if ($container == "fail2ban-mailcow") {
if (!is_numeric($lines)) {
list ($from, $to) = explode('-', $lines);
diff --git a/data/web/inc/functions.mailbox.inc.php b/data/web/inc/functions.mailbox.inc.php
index d1410f97..054a9499 100644
--- a/data/web/inc/functions.mailbox.inc.php
+++ b/data/web/inc/functions.mailbox.inc.php
@@ -490,9 +490,20 @@ function mailbox($_action, $_type, $_data = null, $attr = null) {
if (in_array($address, $gotos)) {
continue;
}
+ $domain = idn_to_ascii(substr(strstr($address, '@'), 1));
+ $local_part = strstr($address, '@', true);
+ $address = $local_part.'@'.$domain;
$stmt = $pdo->prepare("SELECT `address` FROM `alias`
- WHERE `address`= :address");
- $stmt->execute(array(':address' => $address));
+ WHERE `address`= :address OR `address` IN (
+ SELECT `username` FROM `mailbox`, `alias_domain`
+ WHERE (
+ `alias_domain`.`alias_domain` = :address_d
+ AND `mailbox`.`username` = CONCAT(:address_l, '@', alias_domain.target_domain)))");
+ $stmt->execute(array(
+ ':address' => $address,
+ ':address_l' => $local_part,
+ ':address_d' => $domain
+ ));
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
if ($num_results != 0) {
$_SESSION['return'] = array(
@@ -501,9 +512,6 @@ function mailbox($_action, $_type, $_data = null, $attr = null) {
);
return false;
}
- $domain = idn_to_ascii(substr(strstr($address, '@'), 1));
- $local_part = strstr($address, '@', true);
- $address = $local_part.'@'.$domain;
$domaindata = mailbox('get', 'domain_details', $domain);
if (is_array($domaindata) && $domaindata['aliases_left'] == "0") {
$_SESSION['return'] = array(
@@ -722,7 +730,7 @@ function mailbox($_action, $_type, $_data = null, $attr = null) {
}
$active = intval($_data['active']);
$quota_b = ($quota_m * 1048576);
- $maildir = $domain . "/" . $local_part . "/mail-" . time() . "/";
+ $maildir = $domain . "/" . $local_part . "/mails/";
if (!is_valid_domain_name($domain)) {
$_SESSION['return'] = array(
'type' => 'danger',
@@ -2302,7 +2310,7 @@ function mailbox($_action, $_type, $_data = null, $attr = null) {
}
else {
try {
- $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `kind` NOT REGEXP 'location|thing|group' AND `domain` IN (SELECT `domain` FROM `domain_admins` WHERE `active` = '1' AND `username` = :username) OR 'admin' = :role");
+ $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `kind` NOT REGEXP 'location|thing|group' AND (`domain` IN (SELECT `domain` FROM `domain_admins` WHERE `active` = '1' AND `username` = :username) OR 'admin' = :role)");
$stmt->execute(array(
':username' => $_SESSION['mailcow_cc_username'],
':role' => $_SESSION['mailcow_cc_role'],
@@ -3360,7 +3368,7 @@ function mailbox($_action, $_type, $_data = null, $attr = null) {
));
$stmt = $pdo->prepare("DELETE FROM `bcc_maps` WHERE `local_dest` = :domain");
$stmt->execute(array(
- ':domain' => '%@'.$domain,
+ ':domain' => $domain,
));
}
catch (PDOException $e) {
@@ -3484,7 +3492,7 @@ function mailbox($_action, $_type, $_data = null, $attr = null) {
));
$stmt = $pdo->prepare("DELETE FROM `bcc_maps` WHERE `local_dest` = :alias_domain");
$stmt->execute(array(
- ':domain' => '%@'.$alias_domain,
+ ':domain' => $alias_domain,
));
}
catch (PDOException $e) {
diff --git a/data/web/inc/functions.quarantaine.inc.php b/data/web/inc/functions.quarantaine.inc.php
new file mode 100644
index 00000000..4b9e6b00
--- /dev/null
+++ b/data/web/inc/functions.quarantaine.inc.php
@@ -0,0 +1,282 @@
+<?php
+function quarantaine($_action, $_data = null) {
+ global $pdo;
+ global $redis;
+ global $lang;
+ switch ($_action) {
+ case 'delete':
+ if (!is_array($_data['id'])) {
+ $ids = array();
+ $ids[] = $_data['id'];
+ }
+ else {
+ $ids = $_data['id'];
+ }
+ if (!isset($_SESSION['acl']['quarantaine']) || $_SESSION['acl']['quarantaine'] != "1" ) {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => sprintf($lang['danger']['access_denied'])
+ );
+ return false;
+ }
+ foreach ($ids as $id) {
+ if (!is_numeric($id)) {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => sprintf($lang['danger']['access_denied'])
+ );
+ return false;
+ }
+ try {
+ $stmt = $pdo->prepare('SELECT `rcpt` FROM `quarantaine` WHERE `id` = :id');
+ $stmt->execute(array(':id' => $id));
+ $row = $stmt->fetch(PDO::FETCH_ASSOC);
+ if (hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $row['rcpt'])) {
+ try {
+ $stmt = $pdo->prepare("DELETE FROM `quarantaine` WHERE `id` = :id");
+ $stmt->execute(array(
+ ':id' => $id
+ ));
+ }
+ catch (PDOException $e) {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => 'MySQL: '.$e
+ );
+ return false;
+ }
+ }
+ else {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => sprintf($lang['danger']['access_denied'])
+ );
+ return false;
+ }
+ }
+ catch(PDOException $e) {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => 'MySQL: '.$e
+ );
+ }
+ }
+ $_SESSION['return'] = array(
+ 'type' => 'success',
+ 'msg' => sprintf($lang['success']['items_deleted'], implode(', ', $ids))
+ );
+ break;
+ case 'edit':
+ if (!isset($_SESSION['acl']['quarantaine']) || $_SESSION['acl']['quarantaine'] != "1" ) {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => sprintf($lang['danger']['access_denied'])
+ );
+ return false;
+ }
+ // Edit settings
+ if ($_data['action'] == 'settings') {
+ if ($_SESSION['mailcow_cc_role'] != "admin") {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => sprintf($lang['danger']['access_denied'])
+ );
+ return false;
+ }
+ $retention_size = $_data['retention_size'];
+ $max_size = $_data['max_size'];
+ $exclude_domains = (array)$_data['exclude_domains'];
+ try {
+ $redis->Set('Q_RETENTION_SIZE', intval($retention_size));
+ $redis->Set('Q_MAX_SIZE', intval($max_size));
+ $redis->Set('Q_EXCLUDE_DOMAINS', json_encode($exclude_domains));
+ }
+ catch (RedisException $e) {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => 'Redis: '.$e
+ );
+ return false;
+ }
+ $_SESSION['return'] = array(
+ 'type' => 'success',
+ 'msg' => 'Saved settings'
+ );
+ }
+ // Release item
+ elseif ($_data['action'] == 'release') {
+ if (!is_array($_data['id'])) {
+ $ids = array();
+ $ids[] = $_data['id'];
+ }
+ else {
+ $ids = $_data['id'];
+ }
+ foreach ($ids as $id) {
+ if (!is_numeric($id)) {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => sprintf($lang['danger']['access_denied'])
+ );
+ return false;
+ }
+ try {
+ $stmt = $pdo->prepare('SELECT `msg`, `qid`, `sender`, `rcpt` FROM `quarantaine` WHERE `id` = :id');
+ $stmt->execute(array(':id' => $id));
+ $row = $stmt->fetch(PDO::FETCH_ASSOC);
+ if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $row['rcpt'])) {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => sprintf($lang['danger']['access_denied'])
+ );
+ return false;
+ }
+ }
+ catch(PDOException $e) {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => 'MySQL: '.$e
+ );
+ }
+ $sender = (isset($row['sender'])) ? $row['sender'] : 'sender-unknown@rspamd';
+ try {
+ $mail = new PHPMailer(true);
+ $mail->isSMTP();
+ $mail->SMTPDebug = 0;
+ $mail->SMTPOptions = array(
+ 'ssl' => array(
+ 'verify_peer' => false,
+ 'verify_peer_name' => false,
+ 'allow_self_signed' => true
+ )
+ );
+ if (!empty(gethostbynamel('postfix-mailcow'))) {
+ $postfix = 'apostfix-mailcow';
+ }
+ if (!empty(gethostbynamel('postfix'))) {
+ $postfix = 'postfix';
+ }
+ else {
+ $_SESSION['return'] = array(
+ 'type' => 'warning',
+ 'msg' => sprintf($lang['danger']['release_send_failed'], 'Cannot determine Postfix host')
+ );
+ return false;
+ }
+ $mail->Host = $postfix;
+ $mail->Port = 590;
+ $mail->setFrom($sender);
+ $mail->CharSet = 'UTF-8';
+ $mail->Subject = sprintf($lang['quarantaine']['release_subject'], $row['qid']);
+ $mail->addAddress($row['rcpt']);
+ $mail->IsHTML(false);
+ $msg_tmpf = tempnam("/tmp", $row['qid']);
+ file_put_contents($msg_tmpf, $row['msg']);
+ $mail->addAttachment($msg_tmpf, $row['qid'] . '.eml');
+ $mail->Body = sprintf($lang['quarantaine']['release_body']);
+ $mail->send();
+ unlink($msg_tmpf);
+ }
+ catch (phpmailerException $e) {
+ unlink($msg_tmpf);
+ $_SESSION['return'] = array(
+ 'type' => 'warning',
+ 'msg' => sprintf($lang['danger']['release_send_failed'], $e->errorMessage())
+ );
+ return false;
+ }
+ try {
+ $stmt = $pdo->prepare("DELETE FROM `quarantaine` WHERE `id` = :id");
+ $stmt->execute(array(
+ ':id' => $id
+ ));
+ }
+ catch (PDOException $e) {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => 'MySQL: '.$e
+ );
+ return false;
+ }
+ }
+ $_SESSION['return'] = array(
+ 'type' => 'success',
+ 'msg' => $lang['success']['items_released']
+ );
+ }
+ return true;
+ break;
+ case 'get':
+ try {
+ if ($_SESSION['mailcow_cc_role'] == "user") {
+ $stmt = $pdo->prepare('SELECT `id`, `qid`, `rcpt`, `sender`, UNIX_TIMESTAMP(`created`) AS `created` FROM `quarantaine` WHERE `rcpt` = :mbox');
+ $stmt->execute(array(':mbox' => $_SESSION['mailcow_cc_username']));
+ $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
+ while($row = array_shift($rows)) {
+ $q_meta[] = $row;
+ }
+ }
+ else {
+ foreach (mailbox('get', 'mailboxes') as $mbox) {
+ $stmt = $pdo->prepare('SELECT `id`, `qid`, `rcpt`, `sender`, UNIX_TIMESTAMP(`created`) AS `created` FROM `quarantaine` WHERE `rcpt` = :mbox');
+ $stmt->execute(array(':mbox' => $mbox));
+ $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
+ while($row = array_shift($rows)) {
+ $q_meta[] = $row;
+ }
+ }
+ }
+ }
+ catch(PDOException $e) {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => 'MySQL: '.$e
+ );
+ }
+ return $q_meta;
+ break;
+ case 'settings':
+ if ($_SESSION['mailcow_cc_role'] != "admin") {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => sprintf($lang['danger']['access_denied'])
+ );
+ return false;
+ }
+ try {
+ $settings['exclude_domains'] = json_decode($redis->Get('Q_EXCLUDE_DOMAINS'), true);
+ $settings['max_size'] = $redis->Get('Q_MAX_SIZE');
+ $settings['retention_size'] = $redis->Get('Q_RETENTION_SIZE');
+ }
+ catch (RedisException $e) {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => 'Redis: '.$e
+ );
+ return false;
+ }
+ return $settings;
+ break;
+ case 'details':
+ if (!is_numeric($_data) || empty($_data)) {
+ return false;
+ }
+ try {
+ $stmt = $pdo->prepare('SELECT `rcpt`, `symbols`, `msg`, `domain` FROM `quarantaine` WHERE `id`= :id');
+ $stmt->execute(array(':id' => $_data));
+ $row = $stmt->fetch(PDO::FETCH_ASSOC);
+ if (hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $row['rcpt'])) {
+ return $row;
+ }
+ return false;
+ }
+ catch(PDOException $e) {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => 'MySQL: '.$e
+ );
+ }
+ return false;
+ break;
+ }
+}
\ No newline at end of file
diff --git a/data/web/inc/header.inc.php b/data/web/inc/header.inc.php
index cedd07ca..c8dbe4b1 100644
--- a/data/web/inc/header.inc.php
+++ b/data/web/inc/header.inc.php
@@ -15,6 +15,7 @@
<?php else: ?>
<link rel="stylesheet" href="/css/bootstrap.min.css">
<?php endif; ?>
+<link rel="stylesheet" href="/css/breakpoint.min.css">
<link rel="stylesheet" href="/css/bootstrap-select.min.css">
<link rel="stylesheet" href="/css/bootstrap-slider.min.css">
<link rel="stylesheet" href="/css/bootstrap-switch.min.css">
@@ -27,6 +28,8 @@
<?= (preg_match("/admin.php/i", $_SERVER['REQUEST_URI'])) ? '<link rel="stylesheet" href="/css/admin.css">' : null; ?>
<?= (preg_match("/user.php/i", $_SERVER['REQUEST_URI'])) ? '<link rel="stylesheet" href="/css/user.css">' : null; ?>
<?= (preg_match("/edit.php/i", $_SERVER['REQUEST_URI'])) ? '<link rel="stylesheet" href="/css/edit.css">' : null; ?>
+<?= (preg_match("/quarantaine.php/i", $_SERVER['REQUEST_URI'])) ? '<link rel="stylesheet" href="/css/quarantaine.css">' : null; ?>
+<?= (preg_match("/debug.php/i", $_SERVER['REQUEST_URI'])) ? '<link rel="stylesheet" href="/css/debug.css">' : null; ?>
<link rel="shortcut icon" href="/favicon.png" type="image/png">
<link rel="icon" href="/favicon.png" type="image/png">
</head>
@@ -35,7 +38,6 @@
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
- <span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
@@ -70,6 +72,7 @@
if (isset($_SESSION['mailcow_cc_role'])) {
if ($_SESSION['mailcow_cc_role'] == 'admin') {
?>
+ <li<?= (preg_match("/debug/i", $_SERVER['REQUEST_URI'])) ? ' class="active"' : ''; ?>><a href="/debug.php"><?= $lang['header']['debug']; ?></a></li>
<li<?= (preg_match("/admin/i", $_SERVER['REQUEST_URI'])) ? ' class="active"' : ''; ?>><a href="/admin.php"><?= $lang['header']['administration']; ?></a></li>
<?php
}
@@ -88,14 +91,19 @@
</ul>
</li>
<?php
+ if (isset($_SESSION['mailcow_cc_role'])) {
+ ?>
+ <li<?= (preg_match("/quarantaine/i", $_SERVER['REQUEST_URI'])) ? ' class="active"' : ''; ?>><a href="/quarantaine.php"><span style="font-size: 12px;" class="glyphicon glyphicon-briefcase"></span> <?= $lang['header']['quarantaine']; ?></a></li>
+ <?php
+ }
if ($_SESSION['mailcow_cc_role'] == 'admin') {
?>
- <li><a href data-toggle="modal" data-target="#RestartSOGo"><span style="font-size: 12px;" class="glyphicon glyphicon-refresh" aria-hidden="true"></span> <?= $lang['header']['restart_sogo']; ?></a></li>
+ <li><a href data-toggle="modal" data-container="sogo-mailcow" data-target="#RestartContainer"><span style="font-size: 12px;" class="glyphicon glyphicon-refresh"></span> <?= $lang['header']['restart_sogo']; ?></a></li>
<?php
}
?>
<li class="dropdown">
- <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><span class="glyphicon glyphicon-link" aria-hidden="true"></span> Apps <span class="caret"></span></a>
+ <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><span class="glyphicon glyphicon-link"></span> Apps <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
<?php
foreach ($MAILCOW_APPS as $app):
diff --git a/data/web/inc/init_db.inc.php b/data/web/inc/init_db.inc.php
index 24a7e072..db3f2f38 100644
--- a/data/web/inc/init_db.inc.php
+++ b/data/web/inc/init_db.inc.php
@@ -3,7 +3,7 @@ function init_db_schema() {
try {
global $pdo;
- $db_version = "16112017_2259";
+ $db_version = "29112017_1515";
$stmt = $pdo->query("SHOW TABLES LIKE 'versions'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
@@ -103,6 +103,30 @@ function init_db_schema() {
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
+ "api" => array(
+ "cols" => array(
+ "username" => "VARCHAR(255) NOT NULL",
+ "api_key" => "VARCHAR(255) NOT NULL",
+ "allow_from" => "VARCHAR(512) NOT NULL",
+ "created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
+ "modified" => "DATETIME ON UPDATE NOW(0)",
+ "active" => "TINYINT(1) NOT NULL DEFAULT '1'"
+ ),
+ "keys" => array(
+ "primary" => array(
+ "" => array("username")
+ ),
+ "fkey" => array(
+ "fk_username_api" => array(
+ "col" => "username",
+ "ref" => "admin.username",
+ "delete" => "CASCADE",
+ "update" => "NO ACTION"
+ )
+ )
+ ),
+ "attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
+ ),
"sender_acl" => array(
"cols" => array(
"logged_in_as" => "VARCHAR(255) NOT NULL",
@@ -133,6 +157,28 @@ function init_db_schema() {
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
+ "quarantaine" => array(
+ "cols" => array(
+ "id" => "INT NOT NULL AUTO_INCREMENT",
+ "qid" => "VARCHAR(30) NOT NULL",
+ "score" => "FLOAT(8,2)",
+ "ip" => "VARBINARY(16)",
+ "action" => "CHAR(20) NOT NULL DEFAULT 'unknown'",
+ "symbols" => "JSON",
+ "sender" => "VARCHAR(255) NOT NULL DEFAULT 'unknown'",
+ "rcpt" => "VARCHAR(255)",
+ "msg" => "LONGTEXT",
+ "domain" => "VARCHAR(255)",
+ "created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
+ "user" => "VARCHAR(255) NOT NULL DEFAULT 'unknown'",
+ ),
+ "keys" => array(
+ "primary" => array(
+ "" => array("id")
+ )
+ ),
+ "attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
+ ),
"mailbox" => array(
"cols" => array(
"username" => "VARCHAR(255) NOT NULL",
@@ -191,6 +237,51 @@ function init_db_schema() {
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
+ "imap_user_shares" => array(
+ "cols" => array(
+ "from_user" => "VARCHAR(255) NOT NULL",
+ "to_user" => "VARCHAR(255) NOT NULL",
+ "dummy" => "CHAR(1) DEFAULT '1'",
+ "created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
+ "modified" => "DATETIME ON UPDATE CURRENT_TIMESTAMP"
+ ),
+ "keys" => array(
+ "primary" => array(
+ "" => array("from_user", "to_user")
+ ),
+ "fkey" => array(
+ "fk_from_user_user_shares" => array(
+ "col" => "from_user",
+ "ref" => "mailbox.username",
+ "delete" => "CASCADE",
+ "update" => "NO ACTION"
+ )
+ )
+ ),
+ "attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
+ ),
+ "imap_anyone_shares" => array(
+ "cols" => array(
+ "from_user" => "VARCHAR(255) NOT NULL",
+ "dummy" => "CHAR(1) DEFAULT '1'",
+ "created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
+ "modified" => "DATETIME ON UPDATE CURRENT_TIMESTAMP"
+ ),
+ "keys" => array(
+ "primary" => array(
+ "" => array("from_user")
+ ),
+ "fkey" => array(
+ "fk_from_anyone_user_shares" => array(
+ "col" => "from_user",
+ "ref" => "mailbox.username",
+ "delete" => "CASCADE",
+ "update" => "NO ACTION"
+ )
+ )
+ ),
+ "attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
+ ),
"user_acl" => array(
"cols" => array(
"username" => "VARCHAR(255) NOT NULL",
@@ -202,6 +293,7 @@ function init_db_schema() {
"syncjobs" => "TINYINT(1) NOT NULL DEFAULT '1'",
"eas_reset" => "TINYINT(1) NOT NULL DEFAULT '1'",
"filters" => "TINYINT(1) NOT NULL DEFAULT '1'",
+ "quarantaine" => "TINYINT(1) NOT NULL DEFAULT '1'",
"bcc_maps" => "TINYINT(1) NOT NULL DEFAULT '1'",
),
"keys" => array(
@@ -708,6 +800,20 @@ function init_db_schema() {
$pdo->query($create);
}
+ // Create events to clean database
+ $events[] = 'DROP EVENT IF EXISTS clean_spamalias;
+DELIMITER //
+CREATE EVENT clean_spamalias
+ON SCHEDULE EVERY 1 DAY DO
+BEGIN
+ DELETE FROM spamalias WHERE validity < UNIX_TIMESTAMP();
+END;
+//
+DELIMITER ;';
+ foreach ($events as $event) {
+ $pdo->exec($event);
+ }
+
// Inject admin if not exists
$stmt = $pdo->query("SELECT NULL FROM `admin`");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
diff --git a/data/web/inc/lib/composer.json b/data/web/inc/lib/composer.json
index 9ac68875..fd8b845e 100644
--- a/data/web/inc/lib/composer.json
+++ b/data/web/inc/lib/composer.json
@@ -2,6 +2,7 @@
"require": {
"robthree/twofactorauth": "^1.6",
"yubico/u2flib-server": "^1.0",
- "phpmailer/phpmailer": "^5.2"
+ "phpmailer/phpmailer": "^5.2",
+ "php-mime-mail-parser/php-mime-mail-parser": "^2.9"
}
}
diff --git a/data/web/inc/lib/composer.lock b/data/web/inc/lib/composer.lock
index cca7113e..384ff585 100644
--- a/data/web/inc/lib/composer.lock
+++ b/data/web/inc/lib/composer.lock
@@ -4,20 +4,100 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
- "content-hash": "d51ef1712a74b0dfed729f2bdd85d1e3",
+ "content-hash": "ee4c9e269c29282221ce88bc23f1bda9",
"packages": [
+ {
+ "name": "php-mime-mail-parser/php-mime-mail-parser",
+ "version": "2.9.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-mime-mail-parser/php-mime-mail-parser.git",
+ "reference": "c6884c7bc77adbf55979db99841195b232fd30f1"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-mime-mail-parser/php-mime-mail-parser/zipball/c6884c7bc77adbf55979db99841195b232fd30f1",
+ "reference": "c6884c7bc77adbf55979db99841195b232fd30f1",
+ "shasum": ""
+ },
+ "require": {
+ "ext-mailparse": "*",
+ "php": "^5.4.0 || ^7.0"
+ },
+ "replace": {
+ "exorus/php-mime-mail-parser": "*",
+ "messaged/php-mime-mail-parser": "*"
+ },
+ "require-dev": {
+ "phpunit/php-token-stream": "^1.3.0",
+ "phpunit/phpunit": "^4.0 || ^5.0",
+ "satooshi/php-coveralls": "0.*",
+ "squizlabs/php_codesniffer": "2.*"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "PhpMimeMailParser\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "bucabay",
+ "email": "[email protected]",
+ "homepage": "http://www.fijiwebdesign.com",
+ "role": "Developer"
+ },
+ {
+ "name": "eXorus",
+ "email": "[email protected]",
+ "homepage": "https://github.com/eXorus/",
+ "role": "Developer"
+ },
+ {
+ "name": "M.Valinskis",
+ "email": "[email protected]",
+ "homepage": "https://code.google.com/p/php-mime-mail-parser",
+ "role": "Developer"
+ },
+ {
+ "name": "eugene.emmett.wood",
+ "email": "[email protected]",
+ "homepage": "https://code.google.com/p/php-mime-mail-parser",
+ "role": "Developer"
+ },
+ {
+ "name": "alknetso",
+ "email": "[email protected]",
+ "homepage": "https://code.google.com/p/php-mime-mail-parser",
+ "role": "Developer"
+ }
+ ],
+ "description": "Fully Tested Mailparse Extension Wrapper for PHP 5.4+",
+ "homepage": "https://github.com/php-mime-mail-parser/php-mime-mail-parser",
+ "keywords": [
+ "MimeMailParser",
+ "mail",
+ "mailparse",
+ "mime"
+ ],
+ "time": "2017-11-02T05:49:00+00:00"
+ },
{
"name": "phpmailer/phpmailer",
- "version": "v5.2.26",
+ "version": "v5.2.25",
"source": {
"type": "git",
"url": "https://github.com/PHPMailer/PHPMailer.git",
- "reference": "70362997bda4376378be7d92d81e2200550923f7"
+ "reference": "2baf20b01690fba8cf720c1ebcf9b988eda50915"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/70362997bda4376378be7d92d81e2200550923f7",
- "reference": "70362997bda4376378be7d92d81e2200550923f7",
+ "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/2baf20b01690fba8cf720c1ebcf9b988eda50915",
+ "reference": "2baf20b01690fba8cf720c1ebcf9b988eda50915",
"shasum": ""
},
"require": {
@@ -81,20 +161,20 @@
}
],
"description": "PHPMailer is a full-featured email creation and transfer class for PHP",
- "time": "2017-11-04T09:26:05+00:00"
+ "time": "2017-08-28T11:12:07+00:00"
},
{
"name": "robthree/twofactorauth",
- "version": "1.6.1",
+ "version": "1.6",
"source": {
"type": "git",
"url": "https://github.com/RobThree/TwoFactorAuth.git",
- "reference": "a77e7d822343bb88112baef808839cfae7bc5abb"
+ "reference": "5093ab230cd8f1296d792afb6a49545f37e7fd5a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/RobThree/TwoFactorAuth/zipball/a77e7d822343bb88112baef808839cfae7bc5abb",
- "reference": "a77e7d822343bb88112baef808839cfae7bc5abb",
+ "url": "https://api.github.com/repos/RobThree/TwoFactorAuth/zipball/5093ab230cd8f1296d792afb6a49545f37e7fd5a",
+ "reference": "5093ab230cd8f1296d792afb6a49545f37e7fd5a",
"shasum": ""
},
"require": {
@@ -132,7 +212,7 @@
"php",
"tfa"
],
- "time": "2017-11-06T17:55:56+00:00"
+ "time": "2017-02-17T15:24:54+00:00"
},
{
"name": "yubico/u2flib-server",
diff --git a/data/web/inc/lib/vendor/composer/autoload_psr4.php b/data/web/inc/lib/vendor/composer/autoload_psr4.php
index 55ee8027..8abeac4b 100644
--- a/data/web/inc/lib/vendor/composer/autoload_psr4.php
+++ b/data/web/inc/lib/vendor/composer/autoload_psr4.php
@@ -7,4 +7,5 @@ $baseDir = dirname($vendorDir);
return array(
'RobThree\\Auth\\' => array($vendorDir . '/robthree/twofactorauth/lib'),
+ 'PhpMimeMailParser\\' => array($vendorDir . '/php-mime-mail-parser/php-mime-mail-parser/src'),
);
diff --git a/data/web/inc/lib/vendor/composer/autoload_static.php b/data/web/inc/lib/vendor/composer/autoload_static.php
index ad3b924f..24f862c6 100644
--- a/data/web/inc/lib/vendor/composer/autoload_static.php
+++ b/data/web/inc/lib/vendor/composer/autoload_static.php
@@ -11,6 +11,10 @@ class ComposerStaticInit873464e4bd965a3168f133248b1b218b
array (
'RobThree\\Auth\\' => 14,
),
+ 'P' =>
+ array (
+ 'PhpMimeMailParser\\' => 18,
+ ),
);
public static $prefixDirsPsr4 = array (
@@ -18,6 +22,10 @@ class ComposerStaticInit873464e4bd965a3168f133248b1b218b
array (
0 => __DIR__ . '/..' . '/robthree/twofactorauth/lib',
),
+ 'PhpMimeMailParser\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/php-mime-mail-parser/php-mime-mail-parser/src',
+ ),
);
public static $classMap = array (
diff --git a/data/web/inc/lib/vendor/composer/installed.json b/data/web/inc/lib/vendor/composer/installed.json
index 22cd3e15..ba0c1451 100644
--- a/data/web/inc/lib/vendor/composer/installed.json
+++ b/data/web/inc/lib/vendor/composer/installed.json
@@ -1,54 +1,17 @@
[
- {
- "name": "yubico/u2flib-server",
- "version": "1.0.1",
- "version_normalized": "1.0.1.0",
- "source": {
- "type": "git",
- "url": "https://github.com/Yubico/php-u2flib-server.git",
- "reference": "dc318c80b59e62921c210f31b014def26ceebbab"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/Yubico/php-u2flib-server/zipball/dc318c80b59e62921c210f31b014def26ceebbab",
- "reference": "dc318c80b59e62921c210f31b014def26ceebbab",
- "shasum": ""
- },
- "require": {
- "ext-openssl": "*",
- "php": ">=5.6"
- },
- "require-dev": {
- "phpunit/phpunit": "~5.7"
- },
- "time": "2017-05-09T07:33:58+00:00",
- "type": "library",
- "installation-source": "dist",
- "autoload": {
- "classmap": [
- "src/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-2-Clause"
- ],
- "description": "Library for U2F implementation",
- "homepage": "https://developers.yubico.com/php-u2flib-server"
- },
{
"name": "robthree/twofactorauth",
- "version": "1.6.1",
- "version_normalized": "1.6.1.0",
+ "version": "1.6",
+ "version_normalized": "1.6.0.0",
"source": {
"type": "git",
"url": "https://github.com/RobThree/TwoFactorAuth.git",
- "reference": "a77e7d822343bb88112baef808839cfae7bc5abb"
+ "reference": "5093ab230cd8f1296d792afb6a49545f37e7fd5a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/RobThree/TwoFactorAuth/zipball/a77e7d822343bb88112baef808839cfae7bc5abb",
- "reference": "a77e7d822343bb88112baef808839cfae7bc5abb",
+ "url": "https://api.github.com/repos/RobThree/TwoFactorAuth/zipball/5093ab230cd8f1296d792afb6a49545f37e7fd5a",
+ "reference": "5093ab230cd8f1296d792afb6a49545f37e7fd5a",
"shasum": ""
},
"require": {
@@ -57,7 +20,7 @@
"require-dev": {
"phpunit/phpunit": "@stable"
},
- "time": "2017-11-06T17:55:56+00:00",
+ "time": "2017-02-17T15:24:54+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@@ -89,19 +52,56 @@
"tfa"
]
},
+ {
+ "name": "yubico/u2flib-server",
+ "version": "1.0.1",
+ "version_normalized": "1.0.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Yubico/php-u2flib-server.git",
+ "reference": "dc318c80b59e62921c210f31b014def26ceebbab"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Yubico/php-u2flib-server/zipball/dc318c80b59e62921c210f31b014def26ceebbab",
+ "reference": "dc318c80b59e62921c210f31b014def26ceebbab",
+ "shasum": ""
+ },
+ "require": {
+ "ext-openssl": "*",
+ "php": ">=5.6"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~5.7"
+ },
+ "time": "2017-05-09T07:33:58+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-2-Clause"
+ ],
+ "description": "Library for U2F implementation",
+ "homepage": "https://developers.yubico.com/php-u2flib-server"
+ },
{
"name": "phpmailer/phpmailer",
- "version": "v5.2.26",
- "version_normalized": "5.2.26.0",
+ "version": "v5.2.25",
+ "version_normalized": "5.2.25.0",
"source": {
"type": "git",
"url": "https://github.com/PHPMailer/PHPMailer.git",
- "reference": "70362997bda4376378be7d92d81e2200550923f7"
+ "reference": "2baf20b01690fba8cf720c1ebcf9b988eda50915"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/70362997bda4376378be7d92d81e2200550923f7",
- "reference": "70362997bda4376378be7d92d81e2200550923f7",
+ "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/2baf20b01690fba8cf720c1ebcf9b988eda50915",
+ "reference": "2baf20b01690fba8cf720c1ebcf9b988eda50915",
"shasum": ""
},
"require": {
@@ -131,7 +131,7 @@
"suggest": {
"league/oauth2-google": "Needed for Google XOAUTH2 authentication"
},
- "time": "2017-11-04T09:26:05+00:00",
+ "time": "2017-08-28T11:12:07+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@@ -167,5 +167,87 @@
}
],
"description": "PHPMailer is a full-featured email creation and transfer class for PHP"
+ },
+ {
+ "name": "php-mime-mail-parser/php-mime-mail-parser",
+ "version": "2.9.3",
+ "version_normalized": "2.9.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-mime-mail-parser/php-mime-mail-parser.git",
+ "reference": "c6884c7bc77adbf55979db99841195b232fd30f1"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-mime-mail-parser/php-mime-mail-parser/zipball/c6884c7bc77adbf55979db99841195b232fd30f1",
+ "reference": "c6884c7bc77adbf55979db99841195b232fd30f1",
+ "shasum": ""
+ },
+ "require": {
+ "ext-mailparse": "*",
+ "php": "^5.4.0 || ^7.0"
+ },
+ "replace": {
+ "exorus/php-mime-mail-parser": "*",
+ "messaged/php-mime-mail-parser": "*"
+ },
+ "require-dev": {
+ "phpunit/php-token-stream": "^1.3.0",
+ "phpunit/phpunit": "^4.0 || ^5.0",
+ "satooshi/php-coveralls": "0.*",
+ "squizlabs/php_codesniffer": "2.*"
+ },
+ "time": "2017-11-02T05:49:00+00:00",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "PhpMimeMailParser\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "bucabay",
+ "email": "[email protected]",
+ "homepage": "http://www.fijiwebdesign.com",
+ "role": "Developer"
+ },
+ {
+ "name": "eXorus",
+ "email": "[email protected]",
+ "homepage": "https://github.com/eXorus/",
+ "role": "Developer"
+ },
+ {
+ "name": "M.Valinskis",
+ "email": "[email protected]",
+ "homepage": "https://code.google.com/p/php-mime-mail-parser",
+ "role": "Developer"
+ },
+ {
+ "name": "eugene.emmett.wood",
+ "email": "[email protected]",
+ "homepage": "https://code.google.com/p/php-mime-mail-parser",
+ "role": "Developer"
+ },
+ {
+ "name": "alknetso",
+ "email": "[email protected]",
+ "homepage": "https://code.google.com/p/php-mime-mail-parser",
+ "role": "Developer"
+ }
+ ],
+ "description": "Fully Tested Mailparse Extension Wrapper for PHP 5.4+",
+ "homepage": "https://github.com/php-mime-mail-parser/php-mime-mail-parser",
+ "keywords": [
+ "MimeMailParser",
+ "mail",
+ "mailparse",
+ "mime"
+ ]
}
]
diff --git a/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/LICENSE b/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/LICENSE
new file mode 100644
index 00000000..ab85686e
--- /dev/null
+++ b/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Vincent Dauce
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/README.md b/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/README.md
new file mode 100644
index 00000000..7f996284
--- /dev/null
+++ b/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/README.md
@@ -0,0 +1,167 @@
+# php-mime-mail-parser
+
+A fully tested mailparse extension wrapper for PHP 5.4+
+
+[](https://github.com/php-mime-mail-parser/php-mime-mail-parser/releases)
+[](https://packagist.org/packages/php-mime-mail-parser/php-mime-mail-parser)
+[](LICENSE)
+
+## Why?
+
+This extension can be used to...
+ * Parse and read email from Postfix
+ * Create webmail
+ * Store email information such a subject, HTML body, attachments, and etc. into a database
+
+## Is it reliable?
+
+Yes. All known issues have been reproduced, fixed and tested.
+
+We use Travis CI to help ensure code quality. You can see real-time statistics below:
+
+[](https://travis-ci.org/php-mime-mail-parser/php-mime-mail-parser)
+[](https://coveralls.io/r/php-mime-mail-parser/php-mime-mail-parser)
+[](https://scrutinizer-ci.com/g/php-mime-mail-parser/php-mime-mail-parser)
+
+## How do I install it?
+
+The easiest way is via [Composer](https://getcomposer.org/).
+
+To install the latest version of PHP MIME Mail Parser, run the command below:
+
+ composer require php-mime-mail-parser/php-mime-mail-parser
+
+## Requirements
+
+The following versions of PHP are supported:
+
+* PHP 5.4
+* PHP 5.5
+* PHP 5.6
+* PHP 7
+* HHVM
+
+```
+sudo apt install php-cli php-pear php-dev php-mbstring
+```
+
+Make sure you have the mailparse extension (http://php.net/manual/en/book.mailparse.php) properly installed. The command line `php -m | grep mailparse` need to return "mailparse" else install it:
+* PHP version > 7.0: mailparse
+* PHP version < 7.0: mailparse 2.1.6
+
+Follow this steps to install mailparse:
+
+* Compile in the temp folder the extension mailparse or mailparse-2.1.6 (workaround because pecl install doesn't work yet)
+```
+cd
+pecl download mailparse
+tar -xvf mailparse-3.0.2.tgz
+cd mailparse-3.0.2/
+phpize
+./configure
+sed -i 's/#if\s!HAVE_MBSTRING/#ifndef MBFL_MBFILTER_H/' ./mailparse.c
+make
+sudo mv modules/mailparse.so /usr/lib/php/20160303/
+```
+* Add the extension mailparse and activate it
+```
+echo "extension=mailparse.so" | sudo tee /etc/php/7.1/mods-available/mailparse.ini
+sudo phpenmod mailparse
+```
+
+On Windows, you need to download mailparse DLL from http://pecl.php.net/package/mailparse and add the line "extension=php_mailparse.dll" to php.ini accordingly.
+
+## How do I use it?
+
+```php
+<?php
+// Include the library first
+require_once __DIR__.'/vendor/autoload.php';
+
+$path = 'path/to/mail.txt';
+$Parser = new PhpMimeMailParser\Parser();
+
+// There are four methods available to indicate which mime mail to parse.
+// You only need to use one of the following four:
+
+// 1. Specify a file path to the mime mail.
+$Parser->setPath($path);
+
+// 2. Specify a php file resource (stream) to the mime mail.
+$Parser->setStream(fopen($path, "r"));
+
+// 3. Specify the raw mime mail text.
+$Parser->setText(file_get_contents($path));
+
+// 4. Specify a stream to work with mail server
+$Parser->setStream(fopen("php://stdin", "r"));
+
+// Once we've indicated where to find the mail, we can parse out the data
+$to = $Parser->getHeader('to'); // "test" <[email protected]>, "test2" <[email protected]>
+$addressesTo = $Parser->getAddresses('to'); //Return an array : [[test, [email protected], false],[test2, [email protected], false]]
+
+$from = $Parser->getHeader('from'); // "test" <[email protected]>
+$addressesFrom = $Parser->getAddresses('from'); //Return an array : test, [email protected], false
+
+$subject = $Parser->getHeader('subject');
+
+$text = $Parser->getMessageBody('text');
+
+$html = $Parser->getMessageBody('html');
+$htmlEmbedded = $Parser->getMessageBody('htmlEmbedded'); //HTML Body included data
+
+$stringHeaders = $Parser->getHeadersRaw(); // Get all headers as a string, no charset conversion
+$arrayHeaders = $Parser->getHeaders(); // Get all headers as an array, with charset conversion
+
+// Pass in a writeable path to save attachments
+$attach_dir = '/path/to/save/attachments/'; // Be sure to include the trailing slash
+$include_inline = true; // Optional argument to include inline attachments (default: true)
+$Parser->saveAttachments($attach_dir [,$include_inline]);
+
+// Get an array of Attachment items from $Parser
+$attachments = $Parser->getAttachments([$include_inline]);
+
+// Loop through all the Attachments
+if (count($attachments) > 0) {
+ foreach ($attachments as $attachment) {
+ echo 'Filename : '.$attachment->getFilename().'<br />'; // logo.jpg
+ echo 'Filesize : '.filesize($attach_dir.$attachment->getFilename()).'<br />'; // 1000
+ echo 'Filetype : '.$attachment->getContentType().'<br />'; // image/jpeg
+ echo 'MIME part string : '.$attachment->getMimePartStr().'<br />'; // (the whole MIME part of the attachment)
+ }
+}
+
+?>
+```
+
+Next you need to forward emails to this script above. For that I'm using [Postfix](http://www.postfix.org/) like a mail server, you need to configure /etc/postfix/master.cf
+
+Add this line at the end of the file (specify myhook to send all emails to the script test.php)
+```
+myhook unix - n n - - pipe
+ flags=F user=www-data argv=php -c /etc/php5/apache2/php.ini -f /var/www/test.php ${sender} ${size} ${recipient}
+```
+
+Edit this line (register myhook)
+```
+smtp inet n - - - - smtpd
+ -o content_filter=myhook:dummy
+```
+
+The php script must use the fourth method to work with this configuration.
+
+
+## Can I contribute?
+
+Feel free to contribute!
+
+ git clone https://github.com/php-mime-mail-parser/php-mime-mail-parser
+ cd php-mime-mail-parser
+ composer install
+ ./vendor/bin/phpunit
+
+If you report an issue, please provide the raw email that triggered it. This helps us reproduce the issue and fix it more quickly.
+
+### License
+
+The php-mime-mail-parser/php-mime-mail-parser is open-sourced software licensed under the [MIT license](http://opensource.org/licenses/MIT)
diff --git a/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/composer.json b/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/composer.json
new file mode 100644
index 00000000..320d08d2
--- /dev/null
+++ b/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/composer.json
@@ -0,0 +1,61 @@
+{
+ "name": "php-mime-mail-parser/php-mime-mail-parser",
+ "type": "library",
+ "description": "Fully Tested Mailparse Extension Wrapper for PHP 5.4+",
+ "keywords": ["mime", "mail", "mailparse", "MimeMailParser"],
+ "homepage": "https://github.com/php-mime-mail-parser/php-mime-mail-parser",
+ "license": "MIT",
+ "authors": [
+ {
+ "name":"eXorus",
+ "email":"[email protected]",
+ "homepage":"https://github.com/eXorus/",
+ "role":"Developer"
+ },
+ {
+ "name":"M.Valinskis",
+ "email":"[email protected]",
+ "homepage":"https://code.google.com/p/php-mime-mail-parser",
+ "role":"Developer"
+ },
+ {
+ "name":"eugene.emmett.wood",
+ "email":"[email protected]",
+ "homepage":"https://code.google.com/p/php-mime-mail-parser",
+ "role":"Developer"
+ },
+ {
+ "name":"alknetso",
+ "email":"[email protected]",
+ "homepage":"https://code.google.com/p/php-mime-mail-parser",
+ "role":"Developer"
+ },
+ {
+ "name":"bucabay",
+ "email":"[email protected]",
+ "homepage":"http://www.fijiwebdesign.com",
+ "role":"Developer"
+ }
+ ],
+ "repository":{
+ "type":"git",
+ "url":"https://github.com/php-mime-mail-parser/php-mime-mail-parser.git"
+ },
+ "require": {
+ "php": "^5.4.0 || ^7.0",
+ "ext-mailparse": "*"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^4.0 || ^5.0",
+ "phpunit/php-token-stream": "^1.3.0",
+ "satooshi/php-coveralls": "0.*",
+ "squizlabs/PHP_CodeSniffer": "2.*"
+ },
+ "replace": {
+ "exorus/php-mime-mail-parser": "*",
+ "messaged/php-mime-mail-parser": "*"
+ },
+ "autoload": {
+ "psr-4": { "PhpMimeMailParser\\": "src/" }
+ }
+}
diff --git a/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/mailparse-stubs.php b/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/mailparse-stubs.php
new file mode 100644
index 00000000..743033ef
--- /dev/null
+++ b/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/mailparse-stubs.php
@@ -0,0 +1,303 @@
+<?php
+/**
+ * @link http://php.net/manual/en/mailparse.constants.php
+ */
+define('MAILPARSE_EXTRACT_OUTPUT', 0);
+
+/**
+ * @link http://php.net/manual/en/mailparse.constants.php
+ */
+define('MAILPARSE_EXTRACT_STREAM', 1);
+
+/**
+ * @link http://php.net/manual/en/mailparse.constants.php
+ */
+define('MAILPARSE_EXTRACT_RETURN', 2);
+
+/**
+ * Parses a file. This is the optimal way of parsing a mail file that you have on
+ * disk.
+ *
+ * @link http://php.net/manual/en/functions.mailparse-msg-parse-file.php
+ *
+ * @param string $filename Path to the file holding the message. The file is opened
+ * and streamed through the parser
+ *
+ * @return resource Returns a MIME resource representing the structure, or false on error
+ */
+function mailparse_msg_parse_file($filename)
+{
+}
+
+/**
+ * .
+ *
+ * @link http://php.net/manual/en/functions.mailparse-msg-get-part.php
+ *
+ * @param resource $mimemail A valid MIME resource
+ * @param string $mimesection
+ *
+ * @return resource
+ */
+function mailparse_msg_get_part($mimemail, $mimesection)
+{
+}
+
+/**
+ * .
+ *
+ * @link http://php.net/manual/en/functions.mailparse-msg-get-structure.php
+ *
+ * @param resource $mimemail A valid MIME resource
+ *
+ * @return array
+ */
+function mailparse_msg_get_structure($mimemail)
+{
+}
+
+/**
+ * .
+ *
+ * @link http://php.net/manual/en/functions.mailparse-msg-get-part-data.php
+ *
+ * @param resource $mimemail A valid MIME resource
+ *
+ * @return array
+ */
+function mailparse_msg_get_part_data($mimemail)
+{
+}
+
+/**
+ * .
+ *
+ * @link http://php.net/manual/en/functions.mailparse-msg-extract-part.php
+ *
+ * @param resource $mimemail A valid MIME resource
+ * @param string $msgbody
+ * @param callable $callbackfunc
+ *
+ * @return void
+ */
+function mailparse_msg_extract_part($mimemail, $msgbody, $callbackfunc)
+{
+}
+
+/**
+ * Extracts/decodes a message section from the supplied filename.
+ *
+ * @link http://php.net/manual/en/functions.mailparse-msg-extract-part-file.php
+ *
+ * @param resource $mimemail A valid MIME resource, created with
+ * mailparse_msg_create
+ * @param mixed $filename Can be a file name or a valid stream resource
+ * @param callable $callbackfunc If set, this must be either a valid callback that
+ * will be passed the extracted section, or null to make this function return the
+ * extracted section
+ *
+ * @return string If $callbackfunc is not null returns true on success
+ */
+function mailparse_msg_extract_part_file($mimemail, $filename, $callbackfunc = false)
+{
+}
+
+/**
+ * .
+ *
+ * @link http://php.net/manual/en/functions.mailparse-msg-extract-whole-part-file.php
+ *
+ * @param resource $mimemail A valid MIME resource
+ * @param string $filename
+ * @param callable $callbackfunc
+ *
+ * @return string
+ */
+function mailparse_msg_extract_whole_part_file($mimemail, $filename, $callbackfunc)
+{
+}
+
+/**
+ * Create a MIME mail resource.
+ *
+ * @link http://php.net/manual/en/functions.mailparse-msg-create.php
+ * @return resource Returns a handle that can be used to parse a message
+ */
+function mailparse_msg_create()
+{
+}
+
+/**
+ * Frees a MIME resource.
+ *
+ * @link http://php.net/manual/en/functions.mailparse-msg-free.php
+ *
+ * @param resource $mimemail A valid MIME resource allocated by
+ * mailparse_msg_create or mailparse_msg_parse_file
+ *
+ * @return bool
+ */
+function mailparse_msg_free($mimemail)
+{
+}
+
+/**
+ * Incrementally parse data into the supplied mime mail resource.
+ *
+ * @link http://php.net/manual/en/functions.mailparse-msg-parse.php
+ *
+ * @param resource $mimemail A valid MIME resource
+ * @param string $data
+ *
+ * @return bool
+ */
+function mailparse_msg_parse($mimemail, $data)
+{
+}
+
+/**
+ * Parses a RFC 822 compliant recipient list, such as that found in the To: header.
+ *
+ * @link http://php.net/manual/en/functions.mailparse-rfc822-parse-addresses.php
+ *
+ * @param string $addresses A string containing addresses, like in: Wez Furlong
+ * [email protected], [email protected]
+ *
+ * @return array Returns an array of associative arrays with the following keys for each
+ * recipient: display The recipient name, for display purpose. If this part is not
+ * set for a recipient, this key will hold the same value as address. address The
+ * email address is_group true if the recipient is a newsgroup, false otherwise
+ */
+function mailparse_rfc822_parse_addresses($addresses)
+{
+}
+
+/**
+ * Figures out the best way of encoding the content read from the given file
+ * pointer.
+ *
+ * @link http://php.net/manual/en/functions.mailparse-determine-best-xfer-encoding.php
+ *
+ * @param resource $fp A valid file pointer, which must be seek-able
+ *
+ * @return string Returns one of the character encodings supported by the mbstring module
+ */
+function mailparse_determine_best_xfer_encoding($fp)
+{
+}
+
+/**
+ * Streams data from the source file pointer, apply $encoding and write to the
+ * destination file pointer.
+ *
+ * @link http://php.net/manual/en/functions.mailparse-stream-encode.php
+ *
+ * @param resource $sourcefp A valid file handle. The file is streamed through the
+ * parser
+ * @param resource $destfp The destination file handle in which the encoded data
+ * will be written
+ * @param string $encoding One of the character encodings supported by the mbstring
+ * module
+ *
+ * @return bool
+ */
+function mailparse_stream_encode($sourcefp, $destfp, $encoding)
+{
+}
+
+/**
+ * Scans the data from the given file pointer and extract each embedded uuencoded
+ * file into a temporary file.
+ *
+ * @link http://php.net/manual/en/functions.mailparse-uudecode-all.php
+ *
+ * @param resource $fp A valid file pointer
+ *
+ * @return array Returns an array of associative arrays listing filename information.
+ * filename Path to the temporary file name created origfilename The original
+ * filename, for uuencoded parts only The first filename entry is the message body.
+ * The next entries are the decoded uuencoded files
+ */
+function mailparse_uudecode_all($fp)
+{
+}
+
+/**
+ * @return
+ */
+function mailparse_test()
+{
+}
+
+class mimemessage
+{
+ /**
+ * @return
+ */
+ public function mimemessage()
+ {
+ }
+
+ /**
+ * @return
+ */
+ public function get_child()
+ {
+ }
+
+ /**
+ * @return
+ */
+ public function get_child_count()
+ {
+ }
+
+ /**
+ * @return
+ */
+ public function get_parent()
+ {
+ }
+
+ /**
+ * @return
+ */
+ public function extract_headers()
+ {
+ }
+
+ /**
+ * @return
+ */
+ public function extract_body()
+ {
+ }
+
+ /**
+ * @return
+ */
+ public function enum_uue()
+ {
+ }
+
+ /**
+ * @return
+ */
+ public function extract_uue()
+ {
+ }
+
+ /**
+ * @return
+ */
+ public function remove()
+ {
+ }
+
+ /**
+ * @return
+ */
+ public function add_child()
+ {
+ }
+}
diff --git a/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/phpunit.xml.dist b/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/phpunit.xml.dist
new file mode 100644
index 00000000..32b1dbbf
--- /dev/null
+++ b/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/phpunit.xml.dist
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<phpunit colors="true" bootstrap="vendor/autoload.php">
+ <testsuite name="eXorus PhpMimeMailParser Test Suite">
+ <directory suffix="Test.php">tests</directory>
+ </testsuite>
+</phpunit>
diff --git a/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/src/Attachment.php b/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/src/Attachment.php
new file mode 100644
index 00000000..52012622
--- /dev/null
+++ b/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/src/Attachment.php
@@ -0,0 +1,183 @@
+<?php
+
+namespace PhpMimeMailParser;
+
+/**
+ * Attachment of php-mime-mail-parser
+ *
+ * Fully Tested Mailparse Extension Wrapper for PHP 5.4+
+ *
+ */
+class Attachment
+{
+ /**
+ * @var string $filename Filename
+ */
+ protected $filename;
+
+ /**
+ * @var string $contentType Mime Type
+ */
+ protected $contentType;
+
+ /**
+ * @var string $content File Content
+ */
+ protected $content;
+
+ /**
+ * @var string $contentDisposition Content-Disposition (attachment or inline)
+ */
+ protected $contentDisposition;
+
+ /**
+ * @var string $contentId Content-ID
+ */
+ protected $contentId;
+
+ /**
+ * @var array $headers An Array of the attachment headers
+ */
+ protected $headers;
+
+ /**
+ * @var resource $stream
+ */
+ protected $stream;
+
+ /**
+ * @var string $mimePartStr
+ */
+ protected $mimePartStr;
+
+ /**
+ * Attachment constructor.
+ *
+ * @param string $filename
+ * @param string $contentType
+ * @param resource $stream
+ * @param string $contentDisposition
+ * @param string $contentId
+ * @param array $headers
+ * @param string $mimePartStr
+ */
+ public function __construct(
+ $filename,
+ $contentType,
+ $stream,
+ $contentDisposition = 'attachment',
+ $contentId = '',
+ $headers = [],
+ $mimePartStr = ''
+ ) {
+ $this->filename = $filename;
+ $this->contentType = $contentType;
+ $this->stream = $stream;
+ $this->content = null;
+ $this->contentDisposition = $contentDisposition;
+ $this->contentId = $contentId;
+ $this->headers = $headers;
+ $this->mimePartStr = $mimePartStr;
+ }
+
+ /**
+ * retrieve the attachment filename
+ *
+ * @return string
+ */
+ public function getFilename()
+ {
+ return $this->filename;
+ }
+
+ /**
+ * Retrieve the Attachment Content-Type
+ *
+ * @return string
+ */
+ public function getContentType()
+ {
+ return $this->contentType;
+ }
+
+ /**
+ * Retrieve the Attachment Content-Disposition
+ *
+ * @return string
+ */
+ public function getContentDisposition()
+ {
+ return $this->contentDisposition;
+ }
+
+ /**
+ * Retrieve the Attachment Content-ID
+ *
+ * @return string
+ */
+ public function getContentID()
+ {
+ return $this->contentId;
+ }
+
+ /**
+ * Retrieve the Attachment Headers
+ *
+ * @return array
+ */
+ public function getHeaders()
+ {
+ return $this->headers;
+ }
+
+ /**
+ * Get a handle to the stream
+ *
+ * @return stream
+ */
+ public function getStream()
+ {
+ return $this->stream;
+ }
+
+ /**
+ * Read the contents a few bytes at a time until completed
+ * Once read to completion, it always returns false
+ *
+ * @param int $bytes (default: 2082)
+ *
+ * @return string|bool
+ */
+ public function read($bytes = 2082)
+ {
+ return feof($this->stream) ? false : fread($this->stream, $bytes);
+ }
+
+ /**
+ * Retrieve the file content in one go
+ * Once you retrieve the content you cannot use MimeMailParser_attachment::read()
+ *
+ * @return string
+ */
+ public function getContent()
+ {
+ if ($this->content === null) {
+ fseek($this->stream, 0);
+ while (($buf = $this->read()) !== false) {
+ $this->content .= $buf;
+ }
+ }
+
+ return $this->content;
+ }
+
+ /**
+ * Get mime part string for this attachment
+ *
+ * @return string
+ */
+ public function getMimePartStr()
+ {
+ return $this->mimePartStr;
+ }
+}
diff --git a/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/src/Charset.php b/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/src/Charset.php
new file mode 100644
index 00000000..04315c1e
--- /dev/null
+++ b/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/src/Charset.php
@@ -0,0 +1,338 @@
+<?php namespace PhpMimeMailParser;
+
+use PhpMimeMailParser\Contracts\CharsetManager;
+
+class Charset implements CharsetManager
+{
+ /**
+ * Charset Aliases
+ */
+ private $charsetAlias = [
+ 'ascii' => 'us-ascii',
+ 'us-ascii' => 'us-ascii',
+ 'ansi_x3.4-1968' => 'us-ascii',
+ '646' => 'us-ascii',
+ 'iso-8859-1' => 'ISO-8859-1',
+ 'iso-8859-2' => 'ISO-8859-2',
+ 'iso-8859-3' => 'ISO-8859-3',
+ 'iso-8859-4' => 'ISO-8859-4',
+ 'iso-8859-5' => 'ISO-8859-5',
+ 'iso-8859-6' => 'ISO-8859-6',
+ 'iso-8859-6-i' => 'ISO-8859-6-I',
+ 'iso-8859-6-e' => 'ISO-8859-6-E',
+ 'iso-8859-7' => 'ISO-8859-7',
+ 'iso-8859-8' => 'ISO-8859-8',
+ 'iso-8859-8-i' => 'ISO-8859-8',
+ 'iso-8859-8-e' => 'ISO-8859-8-E',
+ 'iso-8859-9' => 'ISO-8859-9',
+ 'iso-8859-10' => 'ISO-8859-10',
+ 'iso-8859-11' => 'ISO-8859-11',
+ 'iso-8859-13' => 'ISO-8859-13',
+ 'iso-8859-14' => 'ISO-8859-14',
+ 'iso-8859-15' => 'ISO-8859-15',
+ 'iso-8859-16' => 'ISO-8859-16',
+ 'iso-ir-111' => 'ISO-IR-111',
+ 'iso-2022-cn' => 'ISO-2022-CN',
+ 'iso-2022-cn-ext' => 'ISO-2022-CN',
+ 'iso-2022-kr' => 'ISO-2022-KR',
+ 'iso-2022-jp' => 'ISO-2022-JP',
+ 'utf-16be' => 'UTF-16BE',
+ 'utf-16le' => 'UTF-16LE',
+ 'utf-16' => 'UTF-16',
+ 'windows-1250' => 'windows-1250',
+ 'windows-1251' => 'windows-1251',
+ 'windows-1252' => 'windows-1252',
+ 'windows-1253' => 'windows-1253',
+ 'windows-1254' => 'windows-1254',
+ 'windows-1255' => 'windows-1255',
+ 'windows-1256' => 'windows-1256',
+ 'windows-1257' => 'windows-1257',
+ 'windows-1258' => 'windows-1258',
+ 'ibm866' => 'IBM866',
+ 'ibm850' => 'IBM850',
+ 'ibm852' => 'IBM852',
+ 'ibm855' => 'IBM855',
+ 'ibm857' => 'IBM857',
+ 'ibm862' => 'IBM862',
+ 'ibm864' => 'IBM864',
+ 'utf-8' => 'UTF-8',
+ 'utf-7' => 'UTF-7',
+ 'shift_jis' => 'Shift_JIS',
+ 'big5' => 'Big5',
+ 'euc-jp' => 'EUC-JP',
+ 'euc-kr' => 'EUC-KR',
+ 'gb2312' => 'GB2312',
+ 'gb18030' => 'gb18030',
+ 'viscii' => 'VISCII',
+ 'koi8-r' => 'KOI8-R',
+ 'koi8_r' => 'KOI8-R',
+ 'cskoi8r' => 'KOI8-R',
+ 'koi' => 'KOI8-R',
+ 'koi8' => 'KOI8-R',
+ 'koi8-u' => 'KOI8-U',
+ 'tis-620' => 'TIS-620',
+ 't.61-8bit' => 'T.61-8bit',
+ 'hz-gb-2312' => 'HZ-GB-2312',
+ 'big5-hkscs' => 'Big5-HKSCS',
+ 'gbk' => 'gbk',
+ 'cns11643' => 'x-euc-tw',
+ 'x-imap4-modified-utf7' => 'x-imap4-modified-utf7',
+ 'x-euc-tw' => 'x-euc-tw',
+ 'x-mac-ce' => 'x-mac-ce',
+ 'x-mac-turkish' => 'x-mac-turkish',
+ 'x-mac-greek' => 'x-mac-greek',
+ 'x-mac-icelandic' => 'x-mac-icelandic',
+ 'x-mac-croatian' => 'x-mac-croatian',
+ 'x-mac-romanian' => 'x-mac-romanian',
+ 'x-mac-cyrillic' => 'x-mac-cyrillic',
+ 'x-mac-ukrainian' => 'x-mac-cyrillic',
+ 'x-mac-hebrew' => 'x-mac-hebrew',
+ 'x-mac-arabic' => 'x-mac-arabic',
+ 'x-mac-farsi' => 'x-mac-farsi',
+ 'x-mac-devanagari' => 'x-mac-devanagari',
+ 'x-mac-gujarati' => 'x-mac-gujarati',
+ 'x-mac-gurmukhi' => 'x-mac-gurmukhi',
+ 'armscii-8' => 'armscii-8',
+ 'x-viet-tcvn5712' => 'x-viet-tcvn5712',
+ 'x-viet-vps' => 'x-viet-vps',
+ 'iso-10646-ucs-2' => 'UTF-16BE',
+ 'x-iso-10646-ucs-2-be' => 'UTF-16BE',
+ 'x-iso-10646-ucs-2-le' => 'UTF-16LE',
+ 'x-user-defined' => 'x-user-defined',
+ 'x-johab' => 'x-johab',
+ 'latin1' => 'ISO-8859-1',
+ 'iso_8859-1' => 'ISO-8859-1',
+ 'iso8859-1' => 'ISO-8859-1',
+ 'iso8859-2' => 'ISO-8859-2',
+ 'iso8859-3' => 'ISO-8859-3',
+ 'iso8859-4' => 'ISO-8859-4',
+ 'iso8859-5' => 'ISO-8859-5',
+ 'iso8859-6' => 'ISO-8859-6',
+ 'iso8859-7' => 'ISO-8859-7',
+ 'iso8859-8' => 'ISO-8859-8',
+ 'iso8859-9' => 'ISO-8859-9',
+ 'iso8859-10' => 'ISO-8859-10',
+ 'iso8859-11' => 'ISO-8859-11',
+ 'iso8859-13' => 'ISO-8859-13',
+ 'iso8859-14' => 'ISO-8859-14',
+ 'iso8859-15' => 'ISO-8859-15',
+ 'iso_8859-1:1987' => 'ISO-8859-1',
+ 'iso-ir-100' => 'ISO-8859-1',
+ 'l1' => 'ISO-8859-1',
+ 'ibm819' => 'ISO-8859-1',
+ 'cp819' => 'ISO-8859-1',
+ 'csisolatin1' => 'ISO-8859-1',
+ 'latin2' => 'ISO-8859-2',
+ 'iso_8859-2' => 'ISO-8859-2',
+ 'iso_8859-2:1987' => 'ISO-8859-2',
+ 'iso-ir-101' => 'ISO-8859-2',
+ 'l2' => 'ISO-8859-2',
+ 'csisolatin2' => 'ISO-8859-2',
+ 'latin3' => 'ISO-8859-3',
+ 'iso_8859-3' => 'ISO-8859-3',
+ 'iso_8859-3:1988' => 'ISO-8859-3',
+ 'iso-ir-109' => 'ISO-8859-3',
+ 'l3' => 'ISO-8859-3',
+ 'csisolatin3' => 'ISO-8859-3',
+ 'latin4' => 'ISO-8859-4',
+ 'iso_8859-4' => 'ISO-8859-4',
+ 'iso_8859-4:1988' => 'ISO-8859-4',
+ 'iso-ir-110' => 'ISO-8859-4',
+ 'l4' => 'ISO-8859-4',
+ 'csisolatin4' => 'ISO-8859-4',
+ 'cyrillic' => 'ISO-8859-5',
+ 'iso_8859-5' => 'ISO-8859-5',
+ 'iso_8859-5:1988' => 'ISO-8859-5',
+ 'iso-ir-144' => 'ISO-8859-5',
+ 'csisolatincyrillic' => 'ISO-8859-5',
+ 'arabic' => 'ISO-8859-6',
+ 'iso_8859-6' => 'ISO-8859-6',
+ 'iso_8859-6:1987' => 'ISO-8859-6',
+ 'iso-ir-127' => 'ISO-8859-6',
+ 'ecma-114' => 'ISO-8859-6',
+ 'asmo-708' => 'ISO-8859-6',
+ 'csisolatinarabic' => 'ISO-8859-6',
+ 'csiso88596i' => 'ISO-8859-6-I',
+ 'csiso88596e' => 'ISO-8859-6-E',
+ 'greek' => 'ISO-8859-7',
+ 'greek8' => 'ISO-8859-7',
+ 'sun_eu_greek' => 'ISO-8859-7',
+ 'iso_8859-7' => 'ISO-8859-7',
+ 'iso_8859-7:1987' => 'ISO-8859-7',
+ 'iso-ir-126' => 'ISO-8859-7',
+ 'elot_928' => 'ISO-8859-7',
+ 'ecma-118' => 'ISO-8859-7',
+ 'csisolatingreek' => 'ISO-8859-7',
+ 'hebrew' => 'ISO-8859-8',
+ 'iso_8859-8' => 'ISO-8859-8',
+ 'visual' => 'ISO-8859-8',
+ 'iso_8859-8:1988' => 'ISO-8859-8',
+ 'iso-ir-138' => 'ISO-8859-8',
+ 'csisolatinhebrew' => 'ISO-8859-8',
+ 'csiso88598i' => 'ISO-8859-8',
+ 'iso-8859-8i' => 'ISO-8859-8',
+ 'logical' => 'ISO-8859-8',
+ 'csiso88598e' => 'ISO-8859-8-E',
+ 'latin5' => 'ISO-8859-9',
+ 'iso_8859-9' => 'ISO-8859-9',
+ 'iso_8859-9:1989' => 'ISO-8859-9',
+ 'iso-ir-148' => 'ISO-8859-9',
+ 'l5' => 'ISO-8859-9',
+ 'csisolatin5' => 'ISO-8859-9',
+ 'unicode-1-1-utf-8' => 'UTF-8',
+ 'utf8' => 'UTF-8',
+ 'x-sjis' => 'Shift_JIS',
+ 'shift-jis' => 'Shift_JIS',
+ 'ms_kanji' => 'Shift_JIS',
+ 'csshiftjis' => 'Shift_JIS',
+ 'windows-31j' => 'Shift_JIS',
+ 'cp932' => 'Shift_JIS',
+ 'sjis' => 'Shift_JIS',
+ 'cseucpkdfmtjapanese' => 'EUC-JP',
+ 'x-euc-jp' => 'EUC-JP',
+ 'csiso2022jp' => 'ISO-2022-JP',
+ 'iso-2022-jp-2' => 'ISO-2022-JP',
+ 'csiso2022jp2' => 'ISO-2022-JP',
+ 'csbig5' => 'Big5',
+ 'cn-big5' => 'Big5',
+ 'x-x-big5' => 'Big5',
+ 'zh_tw-big5' => 'Big5',
+ 'cseuckr' => 'EUC-KR',
+ 'ks_c_5601-1987' => 'EUC-KR',
+ 'iso-ir-149' => 'EUC-KR',
+ 'ks_c_5601-1989' => 'EUC-KR',
+ 'ksc_5601' => 'EUC-KR',
+ 'ksc5601' => 'EUC-KR',
+ 'korean' => 'EUC-KR',
+ 'csksc56011987' => 'EUC-KR',
+ '5601' => 'EUC-KR',
+ 'windows-949' => 'EUC-KR',
+ 'gb_2312-80' => 'GB2312',
+ 'iso-ir-58' => 'GB2312',
+ 'chinese' => 'GB2312',
+ 'csiso58gb231280' => 'GB2312',
+ 'csgb2312' => 'GB2312',
+ 'zh_cn.euc' => 'GB2312',
+ 'gb_2312' => 'GB2312',
+ 'x-cp1250' => 'windows-1250',
+ 'x-cp1251' => 'windows-1251',
+ 'x-cp1252' => 'windows-1252',
+ 'x-cp1253' => 'windows-1253',
+ 'x-cp1254' => 'windows-1254',
+ 'x-cp1255' => 'windows-1255',
+ 'x-cp1256' => 'windows-1256',
+ 'x-cp1257' => 'windows-1257',
+ 'x-cp1258' => 'windows-1258',
+ 'windows-874' => 'windows-874',
+ 'ibm874' => 'windows-874',
+ 'dos-874' => 'windows-874',
+ 'macintosh' => 'macintosh',
+ 'x-mac-roman' => 'macintosh',
+ 'mac' => 'macintosh',
+ 'csmacintosh' => 'macintosh',
+ 'cp866' => 'IBM866',
+ 'cp-866' => 'IBM866',
+ '866' => 'IBM866',
+ 'csibm866' => 'IBM866',
+ 'cp850' => 'IBM850',
+ '850' => 'IBM850',
+ 'csibm850' => 'IBM850',
+ 'cp852' => 'IBM852',
+ '852' => 'IBM852',
+ 'csibm852' => 'IBM852',
+ 'cp855' => 'IBM855',
+ '855' => 'IBM855',
+ 'csibm855' => 'IBM855',
+ 'cp857' => 'IBM857',
+ '857' => 'IBM857',
+ 'csibm857' => 'IBM857',
+ 'cp862' => 'IBM862',
+ '862' => 'IBM862',
+ 'csibm862' => 'IBM862',
+ 'cp864' => 'IBM864',
+ '864' => 'IBM864',
+ 'csibm864' => 'IBM864',
+ 'ibm-864' => 'IBM864',
+ 't.61' => 'T.61-8bit',
+ 'iso-ir-103' => 'T.61-8bit',
+ 'csiso103t618bit' => 'T.61-8bit',
+ 'x-unicode-2-0-utf-7' => 'UTF-7',
+ 'unicode-2-0-utf-7' => 'UTF-7',
+ 'unicode-1-1-utf-7' => 'UTF-7',
+ 'csunicode11utf7' => 'UTF-7',
+ 'csunicode' => 'UTF-16BE',
+ 'csunicode11' => 'UTF-16BE',
+ 'iso-10646-ucs-basic' => 'UTF-16BE',
+ 'csunicodeascii' => 'UTF-16BE',
+ 'iso-10646-unicode-latin1' => 'UTF-16BE',
+ 'csunicodelatin1' => 'UTF-16BE',
+ 'iso-10646' => 'UTF-16BE',
+ 'iso-10646-j-1' => 'UTF-16BE',
+ 'latin6' => 'ISO-8859-10',
+ 'iso-ir-157' => 'ISO-8859-10',
+ 'l6' => 'ISO-8859-10',
+ 'csisolatin6' => 'ISO-8859-10',
+ 'iso_8859-15' => 'ISO-8859-15',
+ 'csisolatin9' => 'ISO-8859-15',
+ 'l9' => 'ISO-8859-15',
+ 'ecma-cyrillic' => 'ISO-IR-111',
+ 'csiso111ecmacyrillic' => 'ISO-IR-111',
+ 'csiso2022kr' => 'ISO-2022-KR',
+ 'csviscii' => 'VISCII',
+ 'zh_tw-euc' => 'x-euc-tw',
+ 'iso88591' => 'ISO-8859-1',
+ 'iso88592' => 'ISO-8859-2',
+ 'iso88593' => 'ISO-8859-3',
+ 'iso88594' => 'ISO-8859-4',
+ 'iso88595' => 'ISO-8859-5',
+ 'iso88596' => 'ISO-8859-6',
+ 'iso88597' => 'ISO-8859-7',
+ 'iso88598' => 'ISO-8859-8',
+ 'iso88599' => 'ISO-8859-9',
+ 'iso885910' => 'ISO-8859-10',
+ 'iso885911' => 'ISO-8859-11',
+ 'iso885912' => 'ISO-8859-12',
+ 'iso885913' => 'ISO-8859-13',
+ 'iso885914' => 'ISO-8859-14',
+ 'iso885915' => 'ISO-8859-15',
+ 'tis620' => 'TIS-620',
+ 'cp1250' => 'windows-1250',
+ 'cp1251' => 'windows-1251',
+ 'cp1252' => 'windows-1252',
+ 'cp1253' => 'windows-1253',
+ 'cp1254' => 'windows-1254',
+ 'cp1255' => 'windows-1255',
+ 'cp1256' => 'windows-1256',
+ 'cp1257' => 'windows-1257',
+ 'cp1258' => 'windows-1258',
+ 'x-gbk' => 'gbk',
+ 'windows-936' => 'gbk',
+ 'ansi-1251' => 'windows-1251',
+ ];
+
+ /**
+ * {@inheritdoc}
+ */
+ public function decodeCharset($encodedString, $charset)
+ {
+ if (strtolower($charset) == 'utf-8' || strtolower($charset) == 'us-ascii') {
+ return $encodedString;
+ } else {
+ return iconv($this->getCharsetAlias($charset), 'UTF-8//TRANSLIT//IGNORE', $encodedString);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getCharsetAlias($charset)
+ {
+ $charset = strtolower($charset);
+
+ if (array_key_exists($charset, $this->charsetAlias)) {
+ return $this->charsetAlias[$charset];
+ } else {
+ return null;
+ }
+ }
+}
diff --git a/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/src/Contracts/CharsetManager.php b/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/src/Contracts/CharsetManager.php
new file mode 100644
index 00000000..660ec00c
--- /dev/null
+++ b/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/src/Contracts/CharsetManager.php
@@ -0,0 +1,24 @@
+<?php namespace PhpMimeMailParser\Contracts;
+
+interface CharsetManager
+{
+
+ /**
+ * Decode the string from Charset
+ *
+ * @param string $encodedString The string in its original encoded state
+ * @param string $charset The Charset header of the part.
+ *
+ * @return string The decoded string
+ */
+ public function decodeCharset($encodedString, $charset);
+
+ /**
+ * Get charset alias
+ *
+ * @param string $charset .
+ *
+ * @return string The charset alias
+ */
+ public function getCharsetAlias($charset);
+}
diff --git a/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/src/Exception.php b/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/src/Exception.php
new file mode 100644
index 00000000..cc537e21
--- /dev/null
+++ b/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/src/Exception.php
@@ -0,0 +1,8 @@
+<?php
+
+namespace PhpMimeMailParser;
+
+class Exception extends \RuntimeException
+{
+
+}
diff --git a/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/src/Parser.php b/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/src/Parser.php
new file mode 100644
index 00000000..689363cc
--- /dev/null
+++ b/data/web/inc/lib/vendor/php-mime-mail-parser/php-mime-mail-parser/src/Parser.php
@@ -0,0 +1,893 @@
+<?php
+
+namespace PhpMimeMailParser;
+
+use PhpMimeMailParser\Contracts\CharsetManager;
+
+/**
+ * Parser of php-mime-mail-parser
+ *
+ * Fully Tested Mailparse Extension Wrapper for PHP 5.4+
+ *
+ */
+class Parser
+{
+ /**
+ * Attachment filename argument option for ->saveAttachments().
+ */
+ const ATTACHMENT_DUPLICATE_THROW = 'DuplicateThrow';
+ const ATTACHMENT_DUPLICATE_SUFFIX = 'DuplicateSuffix';
+ const ATTACHMENT_RANDOM_FILENAME = 'RandomFilename';
+
+ /**
+ * PHP MimeParser Resource ID
+ *
+ * @var resource $resource
+ */
+ protected $resource;
+
+ /**
+ * A file pointer to email
+ *
+ * @var resource $stream
+ */
+ protected $stream;
+
+ /**
+ * A text of an email
+ *
+ * @var string $data
+ */
+ protected $data;
+
+ /**
+ * Parts of an email
+ *
+ * @var array $parts
+ */
+ protected $parts;
+
+ /**
+ * @var CharsetManager object
+ */
+ protected $charset;
+
+ /**
+ * Parser constructor.
+ *
+ * @param CharsetManager|null $charset
+ */
+ public function __construct(CharsetManager $charset = null)
+ {
+ if ($charset == null) {
+ $charset = new Charset();
+ }
+
+ $this->charset = $charset;
+ }
+
+ /**
+ * Free the held resources
+ *
+ * @return void
+ */
+ public function __destruct()
+ {
+ // clear the email file resource
+ if (is_resource($this->stream)) {
+ fclose($this->stream);
+ }
+ // clear the MailParse resource
+ if (is_resource($this->resource)) {
+ mailparse_msg_free($this->resource);
+ }
+ }
+
+ /**
+ * Set the file path we use to get the email text
+ *
+ * @param string $path File path to the MIME mail
+ *
+ * @return Parser MimeMailParser Instance
+ */
+ public function setPath($path)
+ {
+ // should parse message incrementally from file
+ $this->resource = mailparse_msg_parse_file($path);
+ $this->stream = fopen($path, 'r');
+ $this->parse();
+
+ return $this;
+ }
+
+ /**
+ * Set the Stream resource we use to get the email text
+ *
+ * @param resource $stream
+ *
+ * @return Parser MimeMailParser Instance
+ * @throws Exception
+ */
+ public function setStream($stream)
+ {
+ // streams have to be cached to file first
+ $meta = @stream_get_meta_data($stream);
+ if (!$meta || !$meta['mode'] || $meta['mode'][0] != 'r' || $meta['eof']) {
+ throw new Exception(
+ 'setStream() expects parameter stream to be readable stream resource.'
+ );
+ }
+
+ /** @var resource $tmp_fp */
+ $tmp_fp = tmpfile();
+ if ($tmp_fp) {
+ while (!feof($stream)) {
+ fwrite($tmp_fp, fread($stream, 2028));
+ }
+ fseek($tmp_fp, 0);
+ $this->stream = &$tmp_fp;
+ } else {
+ throw new Exception(
+ 'Could not create temporary files for attachments. Your tmp directory may be unwritable by PHP.'
+ );
+ }
+ fclose($stream);
+
+ $this->resource = mailparse_msg_create();
+ // parses the message incrementally (low memory usage but slower)
+ while (!feof($this->stream)) {
+ mailparse_msg_parse($this->resource, fread($this->stream, 2082));
+ }
+ $this->parse();
+
+ return $this;
+ }
+
+ /**
+ * Set the email text
+ *
+ * @param string $data
+ *
+ * @return Parser MimeMailParser Instance
+ */
+ public function setText($data)
+ {
+ if (!$data) {
+ throw new Exception('You must not call MimeMailParser::setText with an empty string parameter');
+ }
+ $this->resource = mailparse_msg_create();
+ // does not parse incrementally, fast memory hog might explode
+ mailparse_msg_parse($this->resource, $data);
+ $this->data = $data;
+ $this->parse();
+
+ return $this;
+ }
+
+ /**
+ * Parse the Message into parts
+ *
+ * @return void
+ */
+ protected function parse()
+ {
+ $structure = mailparse_msg_get_structure($this->resource);
+ $this->parts = [];
+ foreach ($structure as $part_id) {
+ $part = mailparse_msg_get_part($this->resource, $part_id);
+ $this->parts[$part_id] = mailparse_msg_get_part_data($part);
+ }
+ }
+
+ /**
+ * Retrieve a specific Email Header, without charset conversion.
+ *
+ * @param string $name Header name (case-insensitive)
+ *
+ * @return string
+ * @throws Exception
+ */
+ public function getRawHeader($name)
+ {
+ $name = strtolower($name);
+ if (isset($this->parts[1])) {
+ $headers = $this->getPart('headers', $this->parts[1]);
+
+ return (isset($headers[$name])) ? $headers[$name] : false;
+ } else {
+ throw new Exception(
+ 'setPath() or setText() or setStream() must be called before retrieving email headers.'
+ );
+ }
+ }
+
+ /**
+ * Retrieve a specific Email Header
+ *
+ * @param string $name Header name (case-insensitive)
+ *
+ * @return string
+ */
+ public function getHeader($name)
+ {
+ $rawHeader = $this->getRawHeader($name);
+ if ($rawHeader === false) {
+ return false;
+ }
+
+ return $this->decodeHeader($rawHeader);
+ }
+
+ /**
+ * Retrieve all mail headers
+ *
+ * @return array
+ * @throws Exception
+ */
+ public function getHeaders()
+ {
+ if (isset($this->parts[1])) {
+ $headers = $this->getPart('headers', $this->parts[1]);
+ foreach ($headers as $name => &$value) {
+ if (is_array($value)) {
+ foreach ($value as &$v) {
+ $v = $this->decodeSingleHeader($v);
+ }
+ } else {
+ $value = $this->decodeSingleHeader($value);
+ }
+ }
+
+ return $headers;
+ } else {
+ throw new Exception(
+ 'setPath() or setText() or setStream() must be called before retrieving email headers.'
+ );
+ }
+ }
+
+ /**
+ * Retrieve the raw mail headers as a string
+ *
+ * @return string
+ * @throws Exception
+ */
+ public function getHeadersRaw()
+ {
+ if (isset($this->parts[1])) {
+ return $this->getPartHeader($this->parts[1]);
+ } else {
+ throw new Exception(
+ 'setPath() or setText() or setStream() must be called before retrieving email headers.'
+ );
+ }
+ }
+
+ /**
+ * Retrieve the raw Header of a MIME part
+ *
+ * @return String
+ * @param $part Object
+ * @throws Exception
+ */
+ protected function getPartHeader(&$part)
+ {
+ $header = '';
+ if ($this->stream) {
+ $header = $this->getPartHeaderFromFile($part);
+ } elseif ($this->data) {
+ $header = $this->getPartHeaderFromText($part);
+ }
+ return $header;
+ }
+
+ /**
+ * Retrieve the Header from a MIME part from file
+ *
+ * @return String Mime Header Part
+ * @param $part Array
+ */
+ protected function getPartHeaderFromFile(&$part)
+ {
+ $start = $part['starting-pos'];
+ $end = $part['starting-pos-body'];
+ fseek($this->stream, $start, SEEK_SET);
+ $header = fread($this->stream, $end-$start);
+ return $header;
+ }
+
+ /**
+ * Retrieve the Header from a MIME part from text
+ *
+ * @return String Mime Header Part
+ * @param $part Array
+ */
+ protected function getPartHeaderFromText(&$part)
+ {
+ $start = $part['starting-pos'];
+ $end = $part['starting-pos-body'];
+ $header = substr($this->data, $start, $end-$start);
+ return $header;
+ }
+
+ /**
+ * Checks whether a given part ID is a child of another part
+ * eg. an RFC822 attachment may have one or more text parts
+ *
+ * @param string $partId
+ * @param string $parentPartId
+ * @return bool
+ */
+ protected function partIdIsChildOfPart($partId, $parentPartId)
+ {
+ return substr($partId, 0, strlen($parentPartId)) == $parentPartId;
+ }
+
+ /**
+ * Whether the given part ID is a child of any attachment part in the message.
+ *
+ * @param string $checkPartId
+ * @return bool
+ */
+ protected function partIdIsChildOfAnAttachment($checkPartId)
+ {
+ foreach ($this->parts as $partId => $part) {
+ if ($this->getPart('content-disposition', $part) == 'attachment') {
+ if ($this->partIdIsChildOfPart($checkPartId, $partId)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns the email message body in the specified format
+ *
+ * @param string $type text, html or htmlEmbedded
+ *
+ * @return false|string Body or False if not found
+ * @throws Exception
+ */
+ public function getMessageBody($type = 'text')
+ {
+ $body = false;
+ $mime_types = [
+ 'text' => 'text/plain',
+ 'html' => 'text/html',
+ 'htmlEmbedded' => 'text/html',
+ ];
+
+ if (in_array($type, array_keys($mime_types))) {
+ $part_type = $type === 'htmlEmbedded' ? 'html' : $type;
+ $inline_parts = $this->getInlineParts($part_type);
+ $body = empty($inline_parts) ? '' : $inline_parts[0];
+ } else {
+ throw new Exception(
+ 'Invalid type specified for getMessageBody(). Expected: text, html or htmlEmbeded.'
+ );
+ }
+
+ if ($type == 'htmlEmbedded') {
+ $attachments = $this->getAttachments();
+ foreach ($attachments as $attachment) {
+ if ($attachment->getContentID() != '') {
+ $body = str_replace(
+ '"cid:'.$attachment->getContentID().'"',
+ '"'.$this->getEmbeddedData($attachment->getContentID()).'"',
+ $body
+ );
+ }
+ }
+ }
+
+ return $body;
+ }
+
+ /**
+ * Returns the embedded data structure
+ *
+ * @param string $contentId Content-Id
+ *
+ * @return string
+ */
+ protected function getEmbeddedData($contentId)
+ {
+ foreach ($this->parts as $part) {
+ if ($this->getPart('content-id', $part) == $contentId) {
+ $embeddedData = 'data:';
+ $embeddedData .= $this->getPart('content-type', $part);
+ $embeddedData .= ';'.$this->getPart('transfer-encoding', $part);
+ $embeddedData .= ','.$this->getPartBody($part);
+ return $embeddedData;
+ }
+ }
+ return '';
+ }
+
+ /**
+ * Return an array with the following keys display, address, is_group
+ *
+ * @param string $name Header name (case-insensitive)
+ *
+ * @return array
+ */
+ public function getAddresses($name)
+ {
+ $value = $this->getHeader($name);
+
+ return mailparse_rfc822_parse_addresses($value);
+ }
+
+ /**
+ * Returns the attachments contents in order of appearance
+ *
+ * @return Attachment[]
+ */
+ public function getInlineParts($type = 'text')
+ {
+ $inline_parts = [];
+ $dispositions = ['inline'];
+ $mime_types = [
+ 'text' => 'text/plain',
+ 'html' => 'text/html',
+ ];
+
+ if (!in_array($type, array_keys($mime_types))) {
+ throw new Exception('Invalid type specified for getInlineParts(). "type" can either be text or html.');
+ }
+
+ foreach ($this->parts as $partId => $part) {
+ if ($this->getPart('content-type', $part) == $mime_types[$type]
+ && $this->getPart('content-disposition', $part) != 'attachment'
+ && !$this->partIdIsChildOfAnAttachment($partId)
+ ) {
+ $headers = $this->getPart('headers', $part);
+ $encodingType = array_key_exists('content-transfer-encoding', $headers) ?
+ $headers['content-transfer-encoding'] : '';
+ if (is_array($encodingType)) {
+ $encodingType = $encodingType[0];
+ }
+ $undecoded_body = $this->decodeContentTransfer($this->getPartBody($part), $encodingType);
+ $inline_parts[] = $this->charset->decodeCharset($undecoded_body, $this->getPartCharset($part));
+ }
+ }
+
+ return $inline_parts;
+ }
+
+ /**
+ * Returns the attachments contents in order of appearance
+ *
+ * @return Attachment[]
+ */
+ public function getAttachments($include_inline = true)
+ {
+ $attachments = [];
+ $dispositions = $include_inline ?
+ ['attachment', 'inline'] :
+ ['attachment'];
+ $non_attachment_types = ['text/plain', 'text/html'];
+ $nonameIter = 0;
+
+ foreach ($this->parts as $part) {
+ $disposition = $this->getPart('content-disposition', $part);
+ $filename = 'noname';
+
+ if (isset($part['disposition-filename'])) {
+ $filename = $this->decodeHeader($part['disposition-filename']);
+ // Escape all potentially unsafe characters from the filename
+ $filename = preg_replace('((^\.)|\/|(\.$))', '_', $filename);
+ } elseif (isset($part['content-name'])) {
+ // if we have no disposition but we have a content-name, it's a valid attachment.
+ // we simulate the presence of an attachment disposition with a disposition filename
+ $filename = $this->decodeHeader($part['content-name']);
+ // Escape all potentially unsafe characters from the filename
+ $filename = preg_replace('((^\.)|\/|(\.$))', '_', $filename);
+ $disposition = 'attachment';
+ } elseif (in_array($part['content-type'], $non_attachment_types, true)
+ && $disposition !== 'attachment') {
+ // it is a message body, no attachment
+ continue;
+ } elseif (substr($part['content-type'], 0, 10) !== 'multipart/') {
+ // if we cannot get it by getMessageBody(), we assume it is an attachment
+ $disposition = 'attachment';
+ }
+
+ if (in_array($disposition, $dispositions) === true) {
+ if ($filename == 'noname') {
+ $nonameIter++;
+ $filename = 'noname'.$nonameIter;
+ }
+
+ $headersAttachments = $this->getPart('headers', $part);
+ $contentidAttachments = $this->getPart('content-id', $part);
+
+ $mimePartStr = $this->getPartComplete($part);
+
+ $attachments[] = new Attachment(
+ $filename,
+ $this->getPart('content-type', $part),
+ $this->getAttachmentStream($part),
+ $disposition,
+ $contentidAttachments,
+ $headersAttachments,
+ $mimePartStr
+ );
+ }
+ }
+
+ return $attachments;
+ }
+
+ /**
+ * Save attachments in a folder
+ *
+ * @param string $attach_dir directory
+ * @param bool $include_inline
+ * @param string $filenameStrategy How to generate attachment filenames
+ *
+ * @return array Saved attachments paths
+ * @throws Exception
+ */
+ public function saveAttachments(
+ $attach_dir,
+ $include_inline = true,
+ $filenameStrategy = self::ATTACHMENT_DUPLICATE_SUFFIX
+ ) {
+ $attachments = $this->getAttachments($include_inline);
+ if (empty($attachments)) {
+ return false;
+ }
+
+ if (!is_dir($attach_dir)) {
+ mkdir($attach_dir);
+ }
+
+ $attachments_paths = [];
+ foreach ($attachments as $attachment) {
+ // Determine filename
+ switch ($filenameStrategy) {
+ case self::ATTACHMENT_RANDOM_FILENAME:
+ $attachment_path = tempnam($attach_dir, '');
+ break;
+ case self::ATTACHMENT_DUPLICATE_THROW:
+ case self::ATTACHMENT_DUPLICATE_SUFFIX:
+ $attachment_path = $attach_dir . $attachment->getFilename();
+ break;
+ default:
+ throw new Exception('Invalid filename strategy argument provided.');
+ }
+
+ // Handle duplicate filename
+ if (file_exists($attachment_path)) {
+ switch ($filenameStrategy) {
+ case self::ATTACHMENT_DUPLICATE_THROW:
+ throw new Exception('Could not create file for attachment: duplicate filename.');
+ case self::ATTACHMENT_DUPLICATE_SUFFIX:
+ $attachment_path = tempnam($attach_dir, $attachment->getFilename());
+ break;
+ }
+ }
+
+ /** @var resource $fp */
+ if ($fp = fopen($attachment_path, 'w')) {
+ while ($bytes = $attachment->read()) {
+ fwrite($fp, $bytes);
+ }
+ fclose($fp);
+ $attachments_paths[] = realpath($attachment_path);
+ } else {
+ throw new Exception('Could not write attachments. Your directory may be unwritable by PHP.');
+ }
+ }
+
+ return $attachments_paths;
+ }
+
+ /**
+ * Read the attachment Body and save temporary file resource
+ *
+ * @param array $part
+ *
+ * @return resource Mime Body Part
+ * @throws Exception
+ */
+ protected function getAttachmentStream(&$part)
+ {
+ /** @var resource $temp_fp */
+ $temp_fp = tmpfile();
+
+ $headers = $this->getPart('headers', $part);
+ $encodingType = array_key_exists('content-transfer-encoding', $headers) ?
+ $headers['content-transfer-encoding'] : '';
+
+ if ($temp_fp) {
+ if ($this->stream) {
+ $start = $part['starting-pos-body'];
+ $end = $part['ending-pos-body'];
+ fseek($this->stream, $start, SEEK_SET);
+ $len = $end - $start;
+ $written = 0;
+ while ($written < $len) {
+ $write = $len;
+ $part = fread($this->stream, $write);
+ fwrite($temp_fp, $this->decodeContentTransfer($part, $encodingType));
+ $written += $write;
+ }
+ } elseif ($this->data) {
+ $attachment = $this->decodeContentTransfer($this->getPartBodyFromText($part), $encodingType);
+ fwrite($temp_fp, $attachment, strlen($attachment));
+ }
+ fseek($temp_fp, 0, SEEK_SET);
+ } else {
+ throw new Exception(
+ 'Could not create temporary files for attachments. Your tmp directory may be unwritable by PHP.'
+ );
+ }
+
+ return $temp_fp;
+ }
+
+ /**
+ * Decode the string from Content-Transfer-Encoding
+ *
+ * @param string $encodedString The string in its original encoded state
+ * @param string $encodingType The encoding type from the Content-Transfer-Encoding header of the part.
+ *
+ * @return string The decoded string
+ */
+ protected function decodeContentTransfer($encodedString, $encodingType)
+ {
+ $encodingType = strtolower($encodingType);
+ if ($encodingType == 'base64') {
+ return base64_decode($encodedString);
+ } elseif ($encodingType == 'quoted-printable') {
+ return quoted_printable_decode($encodedString);
+ } else {
+ return $encodedString; //8bit, 7bit, binary
+ }
+ }
+
+ /**
+ * $input can be a string or array
+ *
+ * @param string|array $input
+ *
+ * @return string
+ */
+ protected function decodeHeader($input)
+ {
+ //Sometimes we have 2 label From so we take only the first
+ if (is_array($input)) {
+ return $this->decodeSingleHeader($input[0]);
+ }
+
+ return $this->decodeSingleHeader($input);
+ }
+
+ /**
+ * Decodes a single header (= string)
+ *
+ * @param string $input
+ *
+ * @return string
+ */
+ protected function decodeSingleHeader($input)
+ {
+ // For each encoded-word...
+ while (preg_match('/(=\?([^?]+)\?(q|b)\?([^?]*)\?=)((\s+)=\?)?/i', $input, $matches)) {
+ $encoded = $matches[1];
+ $charset = $matches[2];
+ $encoding = $matches[3];
+ $text = $matches[4];
+ $space = isset($matches[6]) ? $matches[6] : '';
+
+ switch (strtolower($encoding)) {
+ case 'b':
+ $text = $this->decodeContentTransfer($text, 'base64');
+ break;
+
+ case 'q':
+ $text = str_replace('_', ' ', $text);
+ preg_match_all('/=([a-f0-9]{2})/i', $text, $matches);
+ foreach ($matches[1] as $value) {
+ $text = str_replace('='.$value, chr(hexdec($value)), $text);
+ }
+ break;
+ }
+
+ $text = $this->charset->decodeCharset($text, $this->charset->getCharsetAlias($charset));
+ $input = str_replace($encoded . $space, $text, $input);
+ }
+
+ return $input;
+ }
+
+ /**
+ * Return the charset of the MIME part
+ *
+ * @param array $part
+ *
+ * @return string|false
+ */
+ protected function getPartCharset($part)
+ {
+ if (isset($part['charset'])) {
+ return $this->charset->getCharsetAlias($part['charset']);
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Retrieve a specified MIME part
+ *
+ * @param string $type
+ * @param array $parts
+ *
+ * @return string|array
+ */
+ protected function getPart($type, $parts)
+ {
+ return (isset($parts[$type])) ? $parts[$type] : false;
+ }
+
+ /**
+ * Retrieve the Body of a MIME part
+ *
+ * @param array $part
+ *
+ * @return string
+ */
+ protected function getPartBody(&$part)
+ {
+ $body = '';
+ if ($this->stream) {
+ $body = $this->getPartBodyFromFile($part);
+ } elseif ($this->data) {
+ $body = $this->getPartBodyFromText($part);
+ }
+
+ return $body;
+ }
+
+ /**
+ * Retrieve the Body from a MIME part from file
+ *
+ * @param array $part
+ *
+ * @return string Mime Body Part
+ */
+ protected function getPartBodyFromFile(&$part)
+ {
+ $start = $part['starting-pos-body'];
+ $end = $part['ending-pos-body'];
+ $body = '';
+ if ($end - $start > 0) {
+ fseek($this->stream, $start, SEEK_SET);
+ $body = fread($this->stream, $end - $start);
+ }
+
+ return $body;
+ }
+
+ /**
+ * Retrieve the Body from a MIME part from text
+ *
+ * @param array $part
+ *
+ * @return string Mime Body Part
+ */
+ protected function getPartBodyFromText(&$part)
+ {
+ $start = $part['starting-pos-body'];
+ $end = $part['ending-pos-body'];
+
+ return substr($this->data, $start, $end - $start);
+ }
+
+ /**
+ * Retrieve the content of a MIME part
+ *
+ * @param array $part
+ *
+ * @return string
+ */
+ protected function getPartComplete(&$part)
+ {
+ $body = '';
+ if ($this->stream) {
+ $body = $this->getPartFromFile($part);
+ } elseif ($this->data) {
+ $body = $this->getPartFromText($part);
+ }
+
+ return $body;
+ }
+
+ /**
+ * Retrieve the content from a MIME part from file
+ *
+ * @param array $part
+ *
+ * @return string Mime Content
+ */
+ protected function getPartFromFile(&$part)
+ {
+ $start = $part['starting-pos'];
+ $end = $part['ending-pos'];
+ $body = '';
+ if ($end - $start > 0) {
+ fseek($this->stream, $start, SEEK_SET);
+ $body = fread($this->stream, $end - $start);
+ }
+
+ return $body;
+ }
+
+ /**
+ * Retrieve the content from a MIME part from text
+ *
+ * @param array $part
+ *
+ * @return string Mime Content
+ */
+ protected function getPartFromText(&$part)
+ {
+ $start = $part['starting-pos'];
+ $end = $part['ending-pos'];
+
+ return substr($this->data, $start, $end - $start);
+ }
+
+ /**
+ * Retrieve the resource
+ *
+ * @return resource resource
+ */
+ public function getResource()
+ {
+ return $this->resource;
+ }
+
+ /**
+ * Retrieve the file pointer to email
+ *
+ * @return resource stream
+ */
+ public function getStream()
+ {
+ return $this->stream;
+ }
+
+ /**
+ * Retrieve the text of an email
+ *
+ * @return string data
+ */
+ public function getData()
+ {
+ return $this->data;
+ }
+
+ /**
+ * Retrieve the parts of an email
+ *
+ * @return array parts
+ */
+ public function getParts()
+ {
+ return $this->parts;
+ }
+
+ /**
+ * Retrieve the charset manager object
+ *
+ * @return CharsetManager charset
+ */
+ public function getCharset()
+ {
+ return $this->charset;
+ }
+}
diff --git a/data/web/inc/lib/vendor/phpmailer/phpmailer/VERSION b/data/web/inc/lib/vendor/phpmailer/phpmailer/VERSION
index f0fb1a22..f23b9706 100644
--- a/data/web/inc/lib/vendor/phpmailer/phpmailer/VERSION
+++ b/data/web/inc/lib/vendor/phpmailer/phpmailer/VERSION
@@ -1 +1 @@
-5.2.26
+5.2.25
diff --git a/data/web/inc/lib/vendor/phpmailer/phpmailer/class.phpmailer.php b/data/web/inc/lib/vendor/phpmailer/phpmailer/class.phpmailer.php
index 99f9092c..8042b384 100644
--- a/data/web/inc/lib/vendor/phpmailer/phpmailer/class.phpmailer.php
+++ b/data/web/inc/lib/vendor/phpmailer/phpmailer/class.phpmailer.php
@@ -31,7 +31,7 @@ class PHPMailer
* The PHPMailer Version number.
* @var string
*/
- public $Version = '5.2.26';
+ public $Version = '5.2.25';
/**
* Email priority.
@@ -659,8 +659,6 @@ class PHPMailer
if ($exceptions !== null) {
$this->exceptions = (boolean)$exceptions;
}
- //Pick an appropriate debug output format automatically
- $this->Debugoutput = (strpos(PHP_SAPI, 'cli') !== false ? 'echo' : 'html');
}
/**
diff --git a/data/web/inc/lib/vendor/phpmailer/phpmailer/class.pop3.php b/data/web/inc/lib/vendor/phpmailer/phpmailer/class.pop3.php
index f833ac61..f2c4e374 100644
--- a/data/web/inc/lib/vendor/phpmailer/phpmailer/class.pop3.php
+++ b/data/web/inc/lib/vendor/phpmailer/phpmailer/class.pop3.php
@@ -34,7 +34,7 @@ class POP3
* @var string
* @access public
*/
- public $Version = '5.2.26';
+ public $Version = '5.2.25';
/**
* Default POP3 port number.
diff --git a/data/web/inc/lib/vendor/phpmailer/phpmailer/class.smtp.php b/data/web/inc/lib/vendor/phpmailer/phpmailer/class.smtp.php
index be6ddce4..d8af427e 100644
--- a/data/web/inc/lib/vendor/phpmailer/phpmailer/class.smtp.php
+++ b/data/web/inc/lib/vendor/phpmailer/phpmailer/class.smtp.php
@@ -30,7 +30,7 @@ class SMTP
* The PHPMailer SMTP version number.
* @var string
*/
- const VERSION = '5.2.26';
+ const VERSION = '5.2.25';
/**
* SMTP line break constant.
@@ -81,7 +81,7 @@ class SMTP
* @deprecated Use the `VERSION` constant instead
* @see SMTP::VERSION
*/
- public $Version = '5.2.26';
+ public $Version = '5.2.25';
/**
* SMTP server port number.
diff --git a/data/web/inc/lib/vendor/robthree/twofactorauth/.gitignore b/data/web/inc/lib/vendor/robthree/twofactorauth/.gitignore
index 8a25841c..1a31666a 100644
--- a/data/web/inc/lib/vendor/robthree/twofactorauth/.gitignore
+++ b/data/web/inc/lib/vendor/robthree/twofactorauth/.gitignore
@@ -183,7 +183,4 @@ UpgradeLog*.htm
FakesAssemblies/
# Composer
-/vendor
-
-# .vs
-.vs/
\ No newline at end of file
+/vendor
\ No newline at end of file
diff --git a/data/web/inc/lib/vendor/robthree/twofactorauth/.travis.yml b/data/web/inc/lib/vendor/robthree/twofactorauth/.travis.yml
index 204dc63a..034653bb 100644
--- a/data/web/inc/lib/vendor/robthree/twofactorauth/.travis.yml
+++ b/data/web/inc/lib/vendor/robthree/twofactorauth/.travis.yml
@@ -1,18 +1,11 @@
language: php
-dist: trusty
-matrix:
- include:
- - php: 5.3
- dist: precise
-
php:
+ - 5.3
- 5.4
- 5.5
- 5.6
- - 7.0
- - 7.1
+ - 7
- hhvm
-script:
- - if [[ "$TRAVIS_PHP_VERSION" == '5.6' ]]; then phpunit --coverage-text tests ; fi
\ No newline at end of file
+script: phpunit --coverage-text tests
diff --git a/data/web/inc/lib/vendor/robthree/twofactorauth/.vs/config/applicationhost.config b/data/web/inc/lib/vendor/robthree/twofactorauth/.vs/config/applicationhost.config
new file mode 100644
index 00000000..4b9bf477
--- /dev/null
+++ b/data/web/inc/lib/vendor/robthree/twofactorauth/.vs/config/applicationhost.config
@@ -0,0 +1,1031 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ IIS configuration sections.
+
+ For schema documentation, see
+ %IIS_BIN%\config\schema\IIS_schema.xml.
+
+ Please make a backup of this file before making any changes to it.
+
+ NOTE: The following environment variables are available to be used
+ within this file and are understood by the IIS Express.
+
+ %IIS_USER_HOME% - The IIS Express home directory for the user
+ %IIS_SITES_HOME% - The default home directory for sites
+ %IIS_BIN% - The location of the IIS Express binaries
+ %SYSTEMDRIVE% - The drive letter of %IIS_BIN%
+
+-->
+<configuration>
+
+ <!--
+
+ The <configSections> section controls the registration of sections.
+ Section is the basic unit of deployment, locking, searching and
+ containment for configuration settings.
+
+ Every section belongs to one section group.
+ A section group is a container of logically-related sections.
+
+ Sections cannot be nested.
+ Section groups may be nested.
+
+ <section
+ name="" [Required, Collection Key] [XML name of the section]
+ allowDefinition="Everywhere" [MachineOnly|MachineToApplication|AppHostOnly|Everywhere] [Level where it can be set]
+ overrideModeDefault="Allow" [Allow|Deny] [Default delegation mode]
+ allowLocation="true" [true|false] [Allowed in location tags]
+ />
+
+ The recommended way to unlock sections is by using a location tag:
+ <location path="Default Web Site" overrideMode="Allow">
+ <system.webServer>
+ <asp />
+ </system.webServer>
+ </location>
+
+ -->
+ <configSections>
+ <sectionGroup name="system.applicationHost">
+ <section name="applicationPools" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+ <section name="configHistory" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+ <section name="customMetadata" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+ <section name="listenerAdapters" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+ <section name="log" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+ <section name="serviceAutoStartProviders" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+ <section name="sites" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+ <section name="webLimits" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+ </sectionGroup>
+
+ <sectionGroup name="system.webServer">
+ <section name="asp" overrideModeDefault="Deny" />
+ <section name="caching" overrideModeDefault="Allow" />
+ <section name="cgi" overrideModeDefault="Deny" />
+ <section name="defaultDocument" overrideModeDefault="Allow" />
+ <section name="directoryBrowse" overrideModeDefault="Allow" />
+ <section name="fastCgi" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+ <section name="globalModules" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+ <section name="handlers" overrideModeDefault="Deny" />
+ <section name="httpCompression" overrideModeDefault="Allow" />
+ <section name="httpErrors" overrideModeDefault="Allow" />
+ <section name="httpLogging" overrideModeDefault="Deny" />
+ <section name="httpProtocol" overrideModeDefault="Allow" />
+ <section name="httpRedirect" overrideModeDefault="Allow" />
+ <section name="httpTracing" overrideModeDefault="Deny" />
+ <section name="isapiFilters" allowDefinition="MachineToApplication" overrideModeDefault="Deny" />
+ <section name="modules" allowDefinition="MachineToApplication" overrideModeDefault="Deny" />
+ <section name="applicationInitialization" allowDefinition="MachineToApplication" overrideModeDefault="Allow" />
+ <section name="odbcLogging" overrideModeDefault="Deny" />
+ <sectionGroup name="security">
+ <section name="access" overrideModeDefault="Deny" />
+ <section name="applicationDependencies" overrideModeDefault="Deny" />
+ <sectionGroup name="authentication">
+ <section name="anonymousAuthentication" overrideModeDefault="Deny" />
+ <section name="basicAuthentication" overrideModeDefault="Deny" />
+ <section name="clientCertificateMappingAuthentication" overrideModeDefault="Deny" />
+ <section name="digestAuthentication" overrideModeDefault="Deny" />
+ <section name="iisClientCertificateMappingAuthentication" overrideModeDefault="Deny" />
+ <section name="windowsAuthentication" overrideModeDefault="Deny" />
+ </sectionGroup>
+ <section name="authorization" overrideModeDefault="Allow" />
+ <section name="ipSecurity" overrideModeDefault="Deny" />
+ <section name="dynamicIpSecurity" overrideModeDefault="Deny" />
+ <section name="isapiCgiRestriction" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />
+ <section name="requestFiltering" overrideModeDefault="Allow" />
+ </sectionGroup>
+ <section name="serverRuntime" overrideModeDefault="Deny" />
+ <section name="serverSideInclude" overrideModeDefault="Deny" />
+ <section name="staticContent" overrideModeDefault="Allow" />
+ <sectionGroup name="tracing">
+ <section name="traceFailedRequests" overrideModeDefault="Allow" />
+ <section name="traceProviderDefinitions" overrideModeDefault="Deny" />
+ </sectionGroup>
+ <section name="urlCompression" overrideModeDefault="Allow" />
+ <section name="validation" overrideModeDefault="Allow" />
+ <sectionGroup name="webdav">
+ <section name="globalSettings" overrideModeDefault="Deny" />
+ <section name="authoring" overrideModeDefault="Deny" />
+ <section name="authoringRules" overrideModeDefault="Deny" />
+ </sectionGroup>
+ <sectionGroup name="rewrite">
+ <section name="allowedServerVariables" overrideModeDefault="Deny" />
+ <section name="rules" overrideModeDefault="Allow" />
+ <section name="outboundRules" overrideModeDefault="Allow" />
+ <section name="globalRules" overrideModeDefault="Deny" allowDefinition="AppHostOnly" />
+ <section name="providers" overrideModeDefault="Allow" />
+ <section name="rewriteMaps" overrideModeDefault="Allow" />
+ </sectionGroup>
+ <section name="webSocket" overrideModeDefault="Deny" />
+ <section name="aspNetCore" overrideModeDefault="Allow" /></sectionGroup>
+ </configSections>
+
+ <configProtectedData>
+ <providers>
+ <add name="IISWASOnlyRsaProvider" type="" description="Uses RsaCryptoServiceProvider to encrypt and decrypt" keyContainerName="iisWasKey" cspProviderName="" useMachineContainer="true" useOAEP="false" />
+ <add name="AesProvider" type="Microsoft.ApplicationHost.AesProtectedConfigurationProvider" description="Uses an AES session key to encrypt and decrypt" keyContainerName="iisConfigurationKey" cspProviderName="" useOAEP="false" useMachineContainer="true" sessionKey="AQIAAA5mAAAApAAAKmFQvWHDEETRz8l2bjZlRxIkwcqTFaCUnCLljn3Q1OkesrhEO9YyLyx4bUhsj1/DyShAv7OAFFhXlrlomaornnk5PLeyO4lIXxaiT33yOFUUgxDx4GSaygkqghVV0tO5yQ/XguUBp2juMfZyztnsNa4pLcz7ZNZQ6p4yn9hxwNs=" />
+ <add name="IISWASOnlyAesProvider" type="Microsoft.ApplicationHost.AesProtectedConfigurationProvider" description="Uses an AES session key to encrypt and decrypt" keyContainerName="iisWasKey" cspProviderName="" useOAEP="false" useMachineContainer="true" sessionKey="AQIAAA5mAAAApAAA4WoiRJ8KHwzAG8AgejPxEOO4/2Vhkolbwo/8gZeNdUDSD36m55hWv4uC9tr/MlKdnwRLL0NhT50Gccyftqz5xTZ0dg5FtvQhTw/he1NwexTKbV+I4Zrd+sZUqHZTsr7JiEr6OHGXL70qoISW5G2m9U8wKT3caPiDPNj2aAaYPLo=" />
+ </providers>
+ </configProtectedData>
+
+ <system.applicationHost>
+
+ <applicationPools>
+ <add name="Clr4IntegratedAppPool" managedRuntimeVersion="v4.0" managedPipelineMode="Integrated" CLRConfigFile="%IIS_USER_HOME%\config\aspnet.config" autoStart="true" />
+ <add name="Clr4ClassicAppPool" managedRuntimeVersion="v4.0" managedPipelineMode="Classic" CLRConfigFile="%IIS_USER_HOME%\config\aspnet.config" autoStart="true" />
+ <add name="Clr2IntegratedAppPool" managedRuntimeVersion="v2.0" managedPipelineMode="Integrated" CLRConfigFile="%IIS_USER_HOME%\config\aspnet.config" autoStart="true" />
+ <add name="Clr2ClassicAppPool" managedRuntimeVersion="v2.0" managedPipelineMode="Classic" CLRConfigFile="%IIS_USER_HOME%\config\aspnet.config" autoStart="true" />
+ <add name="UnmanagedClassicAppPool" managedRuntimeVersion="" managedPipelineMode="Classic" autoStart="true" />
+ <applicationPoolDefaults managedRuntimeLoader="v4.0">
+ <processModel />
+ </applicationPoolDefaults>
+ </applicationPools>
+
+ <!--
+
+ The <listenerAdapters> section defines the protocols with which the
+ Windows Process Activation Service (WAS) binds.
+
+ -->
+ <listenerAdapters>
+ <add name="http" />
+ </listenerAdapters>
+
+ <sites>
+ <site name="WebSite1" id="1" serverAutoStart="true">
+ <application path="/">
+ <virtualDirectory path="/" physicalPath="%IIS_SITES_HOME%\WebSite1" />
+ </application>
+ <bindings>
+ <binding protocol="http" bindingInformation=":8080:localhost" />
+ </bindings>
+ </site>
+ <siteDefaults>
+ <logFile logFormat="W3C" directory="%IIS_USER_HOME%\Logs" />
+ <traceFailedRequestsLogging directory="%IIS_USER_HOME%\TraceLogFiles" enabled="true" maxLogFileSizeKB="1024" />
+ </siteDefaults>
+ <applicationDefaults applicationPool="Clr4IntegratedAppPool" />
+ <virtualDirectoryDefaults allowSubDirConfig="true" />
+ </sites>
+
+ <webLimits />
+
+ </system.applicationHost>
+
+ <system.webServer>
+
+ <serverRuntime />
+
+ <asp scriptErrorSentToBrowser="true">
+ <cache diskTemplateCacheDirectory="%TEMP%\iisexpress\ASP Compiled Templates" />
+ <limits />
+ </asp>
+
+ <caching enabled="true" enableKernelCache="true">
+ </caching>
+
+ <cgi />
+
+ <defaultDocument enabled="true">
+ <files>
+ <add value="Default.htm" />
+ <add value="Default.asp" />
+ <add value="index.htm" />
+ <add value="index.html" />
+ <add value="iisstart.htm" />
+ <add value="default.aspx" />
+ </files>
+ </defaultDocument>
+
+ <directoryBrowse enabled="false" />
+
+ <fastCgi />
+
+ <!--
+
+ The <globalModules> section defines all native-code modules.
+ To enable a module, specify it in the <modules> section.
+
+ -->
+ <globalModules>
+ <add name="HttpLoggingModule" image="%IIS_BIN%\loghttp.dll" />
+ <add name="UriCacheModule" image="%IIS_BIN%\cachuri.dll" />
+<!-- <add name="FileCacheModule" image="%IIS_BIN%\cachfile.dll" /> -->
+ <add name="TokenCacheModule" image="%IIS_BIN%\cachtokn.dll" />
+<!-- <add name="HttpCacheModule" image="%IIS_BIN%\cachhttp.dll" /> -->
+ <add name="DynamicCompressionModule" image="%IIS_BIN%\compdyn.dll" />
+ <add name="StaticCompressionModule" image="%IIS_BIN%\compstat.dll" />
+ <add name="DefaultDocumentModule" image="%IIS_BIN%\defdoc.dll" />
+ <add name="DirectoryListingModule" image="%IIS_BIN%\dirlist.dll" />
+ <add name="ProtocolSupportModule" image="%IIS_BIN%\protsup.dll" />
+ <add name="HttpRedirectionModule" image="%IIS_BIN%\redirect.dll" />
+ <add name="ServerSideIncludeModule" image="%IIS_BIN%\iis_ssi.dll" />
+ <add name="StaticFileModule" image="%IIS_BIN%\static.dll" />
+ <add name="AnonymousAuthenticationModule" image="%IIS_BIN%\authanon.dll" />
+ <add name="CertificateMappingAuthenticationModule" image="%IIS_BIN%\authcert.dll" />
+ <add name="UrlAuthorizationModule" image="%IIS_BIN%\urlauthz.dll" />
+ <add name="BasicAuthenticationModule" image="%IIS_BIN%\authbas.dll" />
+ <add name="WindowsAuthenticationModule" image="%IIS_BIN%\authsspi.dll" />
+<!-- <add name="DigestAuthenticationModule" image="%IIS_BIN%\authmd5.dll" /> -->
+ <add name="IISCertificateMappingAuthenticationModule" image="%IIS_BIN%\authmap.dll" />
+ <add name="IpRestrictionModule" image="%IIS_BIN%\iprestr.dll" />
+ <add name="DynamicIpRestrictionModule" image="%IIS_BIN%\diprestr.dll" />
+ <add name="RequestFilteringModule" image="%IIS_BIN%\modrqflt.dll" />
+ <add name="CustomLoggingModule" image="%IIS_BIN%\logcust.dll" />
+ <add name="CustomErrorModule" image="%IIS_BIN%\custerr.dll" />
+<!-- <add name="TracingModule" image="%IIS_BIN%\iisetw.dll" /> -->
+ <add name="FailedRequestsTracingModule" image="%IIS_BIN%\iisfreb.dll" />
+ <add name="RequestMonitorModule" image="%IIS_BIN%\iisreqs.dll" />
+ <add name="IsapiModule" image="%IIS_BIN%\isapi.dll" />
+ <add name="IsapiFilterModule" image="%IIS_BIN%\filter.dll" />
+ <add name="CgiModule" image="%IIS_BIN%\cgi.dll" />
+ <add name="FastCgiModule" image="%IIS_BIN%\iisfcgi.dll" />
+<!-- <add name="WebDAVModule" image="%IIS_BIN%\webdav.dll" /> -->
+ <add name="RewriteModule" image="%IIS_BIN%\rewrite.dll" />
+ <add name="ConfigurationValidationModule" image="%IIS_BIN%\validcfg.dll" />
+ <add name="WebSocketModule" image="%IIS_BIN%\iiswsock.dll" />
+ <add name="WebMatrixSupportModule" image="%IIS_BIN%\webmatrixsup.dll" />
+ <add name="ManagedEngine" image="%windir%\Microsoft.NET\Framework\v2.0.50727\webengine.dll" preCondition="integratedMode,runtimeVersionv2.0,bitness32" />
+ <add name="ManagedEngine64" image="%windir%\Microsoft.NET\Framework64\v2.0.50727\webengine.dll" preCondition="integratedMode,runtimeVersionv2.0,bitness64" />
+ <add name="ManagedEngineV4.0_32bit" image="%windir%\Microsoft.NET\Framework\v4.0.30319\webengine4.dll" preCondition="integratedMode,runtimeVersionv4.0,bitness32" />
+ <add name="ManagedEngineV4.0_64bit" image="%windir%\Microsoft.NET\Framework64\v4.0.30319\webengine4.dll" preCondition="integratedMode,runtimeVersionv4.0,bitness64" />
+ <add name="ApplicationInitializationModule" image="%IIS_BIN%\warmup.dll" />
+ <add name="AspNetCoreModule" image="%IIS_BIN%\aspnetcore.dll" />
+ </globalModules>
+
+ <httpCompression directory="%TEMP%\iisexpress\IIS Temporary Compressed Files">
+ <scheme name="gzip" dll="%IIS_BIN%\gzip.dll" />
+ <dynamicTypes>
+ <add mimeType="text/*" enabled="true" />
+ <add mimeType="message/*" enabled="true" />
+ <add mimeType="application/javascript" enabled="true" />
+ <add mimeType="application/atom+xml" enabled="true" />
+ <add mimeType="application/xaml+xml" enabled="true" />
+ <add mimeType="*/*" enabled="false" />
+ </dynamicTypes>
+ <staticTypes>
+ <add mimeType="text/*" enabled="true" />
+ <add mimeType="message/*" enabled="true" />
+ <add mimeType="image/svg+xml" enabled="true" />
+ <add mimeType="application/javascript" enabled="true" />
+ <add mimeType="application/atom+xml" enabled="true" />
+ <add mimeType="application/xaml+xml" enabled="true" />
+ <add mimeType="*/*" enabled="false" />
+ </staticTypes>
+ </httpCompression>
+
+ <httpErrors lockAttributes="allowAbsolutePathsWhenDelegated,defaultPath">
+ <error statusCode="401" prefixLanguageFilePath="%IIS_BIN%\custerr" path="401.htm" />
+ <error statusCode="403" prefixLanguageFilePath="%IIS_BIN%\custerr" path="403.htm" />
+ <error statusCode="404" prefixLanguageFilePath="%IIS_BIN%\custerr" path="404.htm" />
+ <error statusCode="405" prefixLanguageFilePath="%IIS_BIN%\custerr" path="405.htm" />
+ <error statusCode="406" prefixLanguageFilePath="%IIS_BIN%\custerr" path="406.htm" />
+ <error statusCode="412" prefixLanguageFilePath="%IIS_BIN%\custerr" path="412.htm" />
+ <error statusCode="500" prefixLanguageFilePath="%IIS_BIN%\custerr" path="500.htm" />
+ <error statusCode="501" prefixLanguageFilePath="%IIS_BIN%\custerr" path="501.htm" />
+ <error statusCode="502" prefixLanguageFilePath="%IIS_BIN%\custerr" path="502.htm" />
+ </httpErrors>
+
+ <httpLogging dontLog="false" />
+
+ <httpProtocol>
+ <customHeaders>
+ <clear />
+ <add name="X-Powered-By" value="ASP.NET" />
+ </customHeaders>
+ <redirectHeaders>
+ <clear />
+ </redirectHeaders>
+ </httpProtocol>
+
+ <httpRedirect enabled="false" />
+
+ <httpTracing>
+ </httpTracing>
+
+ <isapiFilters>
+ <filter name="ASP.Net_2.0.50727-64" path="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_filter.dll" enableCache="true" preCondition="bitness64,runtimeVersionv2.0" />
+ <filter name="ASP.Net_2.0.50727.0" path="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_filter.dll" enableCache="true" preCondition="bitness32,runtimeVersionv2.0" />
+ <filter name="ASP.Net_2.0_for_v1.1" path="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_filter.dll" enableCache="true" preCondition="runtimeVersionv1.1" />
+ <filter name="ASP.Net_4.0_32bit" path="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_filter.dll" enableCache="true" preCondition="bitness32,runtimeVersionv4.0" />
+ <filter name="ASP.Net_4.0_64bit" path="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_filter.dll" enableCache="true" preCondition="bitness64,runtimeVersionv4.0" />
+ </isapiFilters>
+
+ <odbcLogging />
+
+ <security>
+
+ <access sslFlags="None" />
+
+ <applicationDependencies>
+ <application name="Active Server Pages" groupId="ASP" />
+ </applicationDependencies>
+
+ <authentication>
+
+ <anonymousAuthentication enabled="true" userName="" />
+
+ <basicAuthentication enabled="false" />
+
+ <clientCertificateMappingAuthentication enabled="false" />
+
+ <digestAuthentication enabled="false" />
+
+ <iisClientCertificateMappingAuthentication enabled="false">
+ </iisClientCertificateMappingAuthentication>
+
+ <windowsAuthentication enabled="false">
+ <providers>
+ <add value="Negotiate" />
+ <add value="NTLM" />
+ </providers>
+ </windowsAuthentication>
+
+ </authentication>
+
+ <authorization>
+ <add accessType="Allow" users="*" />
+ </authorization>
+
+ <ipSecurity allowUnlisted="true" />
+
+ <isapiCgiRestriction notListedIsapisAllowed="true" notListedCgisAllowed="true">
+ <add path="%windir%\Microsoft.NET\Framework64\v4.0.30319\webengine4.dll" allowed="true" groupId="ASP.NET_v4.0" description="ASP.NET_v4.0" />
+ <add path="%windir%\Microsoft.NET\Framework\v4.0.30319\webengine4.dll" allowed="true" groupId="ASP.NET_v4.0" description="ASP.NET_v4.0" />
+ <add path="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" allowed="true" groupId="ASP.NET v2.0.50727" description="ASP.NET v2.0.50727" />
+ <add path="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" allowed="true" groupId="ASP.NET v2.0.50727" description="ASP.NET v2.0.50727" />
+ </isapiCgiRestriction>
+
+ <requestFiltering>
+ <fileExtensions allowUnlisted="true" applyToWebDAV="true">
+ <add fileExtension=".asa" allowed="false" />
+ <add fileExtension=".asax" allowed="false" />
+ <add fileExtension=".ascx" allowed="false" />
+ <add fileExtension=".master" allowed="false" />
+ <add fileExtension=".skin" allowed="false" />
+ <add fileExtension=".browser" allowed="false" />
+ <add fileExtension=".sitemap" allowed="false" />
+ <add fileExtension=".config" allowed="false" />
+ <add fileExtension=".cs" allowed="false" />
+ <add fileExtension=".csproj" allowed="false" />
+ <add fileExtension=".vb" allowed="false" />
+ <add fileExtension=".vbproj" allowed="false" />
+ <add fileExtension=".webinfo" allowed="false" />
+ <add fileExtension=".licx" allowed="false" />
+ <add fileExtension=".resx" allowed="false" />
+ <add fileExtension=".resources" allowed="false" />
+ <add fileExtension=".mdb" allowed="false" />
+ <add fileExtension=".vjsproj" allowed="false" />
+ <add fileExtension=".java" allowed="false" />
+ <add fileExtension=".jsl" allowed="false" />
+ <add fileExtension=".ldb" allowed="false" />
+ <add fileExtension=".dsdgm" allowed="false" />
+ <add fileExtension=".ssdgm" allowed="false" />
+ <add fileExtension=".lsad" allowed="false" />
+ <add fileExtension=".ssmap" allowed="false" />
+ <add fileExtension=".cd" allowed="false" />
+ <add fileExtension=".dsprototype" allowed="false" />
+ <add fileExtension=".lsaprototype" allowed="false" />
+ <add fileExtension=".sdm" allowed="false" />
+ <add fileExtension=".sdmDocument" allowed="false" />
+ <add fileExtension=".mdf" allowed="false" />
+ <add fileExtension=".ldf" allowed="false" />
+ <add fileExtension=".ad" allowed="false" />
+ <add fileExtension=".dd" allowed="false" />
+ <add fileExtension=".ldd" allowed="false" />
+ <add fileExtension=".sd" allowed="false" />
+ <add fileExtension=".adprototype" allowed="false" />
+ <add fileExtension=".lddprototype" allowed="false" />
+ <add fileExtension=".exclude" allowed="false" />
+ <add fileExtension=".refresh" allowed="false" />
+ <add fileExtension=".compiled" allowed="false" />
+ <add fileExtension=".msgx" allowed="false" />
+ <add fileExtension=".vsdisco" allowed="false" />
+ <add fileExtension=".rules" allowed="false" />
+ </fileExtensions>
+ <verbs allowUnlisted="true" applyToWebDAV="true" />
+ <hiddenSegments applyToWebDAV="true">
+ <add segment="web.config" />
+ <add segment="bin" />
+ <add segment="App_code" />
+ <add segment="App_GlobalResources" />
+ <add segment="App_LocalResources" />
+ <add segment="App_WebReferences" />
+ <add segment="App_Data" />
+ <add segment="App_Browsers" />
+ </hiddenSegments>
+ </requestFiltering>
+
+ </security>
+
+ <serverSideInclude ssiExecDisable="false" />
+
+ <staticContent lockAttributes="isDocFooterFileName">
+ <mimeMap fileExtension=".323" mimeType="text/h323" />
+ <mimeMap fileExtension=".3g2" mimeType="video/3gpp2" />
+ <mimeMap fileExtension=".3gp2" mimeType="video/3gpp2" />
+ <mimeMap fileExtension=".3gp" mimeType="video/3gpp" />
+ <mimeMap fileExtension=".3gpp" mimeType="video/3gpp" />
+ <mimeMap fileExtension=".aac" mimeType="audio/aac" />
+ <mimeMap fileExtension=".aaf" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".aca" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".accdb" mimeType="application/msaccess" />
+ <mimeMap fileExtension=".accde" mimeType="application/msaccess" />
+ <mimeMap fileExtension=".accdt" mimeType="application/msaccess" />
+ <mimeMap fileExtension=".acx" mimeType="application/internet-property-stream" />
+ <mimeMap fileExtension=".adt" mimeType="audio/vnd.dlna.adts" />
+ <mimeMap fileExtension=".adts" mimeType="audio/vnd.dlna.adts" />
+ <mimeMap fileExtension=".afm" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".ai" mimeType="application/postscript" />
+ <mimeMap fileExtension=".aif" mimeType="audio/x-aiff" />
+ <mimeMap fileExtension=".aifc" mimeType="audio/aiff" />
+ <mimeMap fileExtension=".aiff" mimeType="audio/aiff" />
+ <mimeMap fileExtension=".appcache" mimeType="text/cache-manifest" />
+ <mimeMap fileExtension=".application" mimeType="application/x-ms-application" />
+ <mimeMap fileExtension=".art" mimeType="image/x-jg" />
+ <mimeMap fileExtension=".asd" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".asf" mimeType="video/x-ms-asf" />
+ <mimeMap fileExtension=".asi" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".asm" mimeType="text/plain" />
+ <mimeMap fileExtension=".asr" mimeType="video/x-ms-asf" />
+ <mimeMap fileExtension=".asx" mimeType="video/x-ms-asf" />
+ <mimeMap fileExtension=".atom" mimeType="application/atom+xml" />
+ <mimeMap fileExtension=".au" mimeType="audio/basic" />
+ <mimeMap fileExtension=".avi" mimeType="video/msvideo" />
+ <mimeMap fileExtension=".axs" mimeType="application/olescript" />
+ <mimeMap fileExtension=".bas" mimeType="text/plain" />
+ <mimeMap fileExtension=".bcpio" mimeType="application/x-bcpio" />
+ <mimeMap fileExtension=".bin" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".bmp" mimeType="image/bmp" />
+ <mimeMap fileExtension=".c" mimeType="text/plain" />
+ <mimeMap fileExtension=".cab" mimeType="application/vnd.ms-cab-compressed" />
+ <mimeMap fileExtension=".calx" mimeType="application/vnd.ms-office.calx" />
+ <mimeMap fileExtension=".cat" mimeType="application/vnd.ms-pki.seccat" />
+ <mimeMap fileExtension=".cdf" mimeType="application/x-cdf" />
+ <mimeMap fileExtension=".chm" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".class" mimeType="application/x-java-applet" />
+ <mimeMap fileExtension=".clp" mimeType="application/x-msclip" />
+ <mimeMap fileExtension=".cmx" mimeType="image/x-cmx" />
+ <mimeMap fileExtension=".cnf" mimeType="text/plain" />
+ <mimeMap fileExtension=".cod" mimeType="image/cis-cod" />
+ <mimeMap fileExtension=".cpio" mimeType="application/x-cpio" />
+ <mimeMap fileExtension=".cpp" mimeType="text/plain" />
+ <mimeMap fileExtension=".crd" mimeType="application/x-mscardfile" />
+ <mimeMap fileExtension=".crl" mimeType="application/pkix-crl" />
+ <mimeMap fileExtension=".crt" mimeType="application/x-x509-ca-cert" />
+ <mimeMap fileExtension=".csh" mimeType="application/x-csh" />
+ <mimeMap fileExtension=".css" mimeType="text/css" />
+ <mimeMap fileExtension=".csv" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".cur" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".dcr" mimeType="application/x-director" />
+ <mimeMap fileExtension=".deploy" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".der" mimeType="application/x-x509-ca-cert" />
+ <mimeMap fileExtension=".dib" mimeType="image/bmp" />
+ <mimeMap fileExtension=".dir" mimeType="application/x-director" />
+ <mimeMap fileExtension=".disco" mimeType="text/xml" />
+ <mimeMap fileExtension=".dll" mimeType="application/x-msdownload" />
+ <mimeMap fileExtension=".dll.config" mimeType="text/xml" />
+ <mimeMap fileExtension=".dlm" mimeType="text/dlm" />
+ <mimeMap fileExtension=".doc" mimeType="application/msword" />
+ <mimeMap fileExtension=".docm" mimeType="application/vnd.ms-word.document.macroEnabled.12" />
+ <mimeMap fileExtension=".docx" mimeType="application/vnd.openxmlformats-officedocument.wordprocessingml.document" />
+ <mimeMap fileExtension=".dot" mimeType="application/msword" />
+ <mimeMap fileExtension=".dotm" mimeType="application/vnd.ms-word.template.macroEnabled.12" />
+ <mimeMap fileExtension=".dotx" mimeType="application/vnd.openxmlformats-officedocument.wordprocessingml.template" />
+ <mimeMap fileExtension=".dsp" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".dtd" mimeType="text/xml" />
+ <mimeMap fileExtension=".dvi" mimeType="application/x-dvi" />
+ <mimeMap fileExtension=".dvr-ms" mimeType="video/x-ms-dvr" />
+ <mimeMap fileExtension=".dwf" mimeType="drawing/x-dwf" />
+ <mimeMap fileExtension=".dwp" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".dxr" mimeType="application/x-director" />
+ <mimeMap fileExtension=".eml" mimeType="message/rfc822" />
+ <mimeMap fileExtension=".emz" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".eot" mimeType="application/vnd.ms-fontobject" />
+ <mimeMap fileExtension=".eps" mimeType="application/postscript" />
+ <mimeMap fileExtension=".etx" mimeType="text/x-setext" />
+ <mimeMap fileExtension=".evy" mimeType="application/envoy" />
+ <mimeMap fileExtension=".exe" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".exe.config" mimeType="text/xml" />
+ <mimeMap fileExtension=".fdf" mimeType="application/vnd.fdf" />
+ <mimeMap fileExtension=".fif" mimeType="application/fractals" />
+ <mimeMap fileExtension=".fla" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".flr" mimeType="x-world/x-vrml" />
+ <mimeMap fileExtension=".flv" mimeType="video/x-flv" />
+ <mimeMap fileExtension=".gif" mimeType="image/gif" />
+ <mimeMap fileExtension=".gtar" mimeType="application/x-gtar" />
+ <mimeMap fileExtension=".gz" mimeType="application/x-gzip" />
+ <mimeMap fileExtension=".h" mimeType="text/plain" />
+ <mimeMap fileExtension=".hdf" mimeType="application/x-hdf" />
+ <mimeMap fileExtension=".hdml" mimeType="text/x-hdml" />
+ <mimeMap fileExtension=".hhc" mimeType="application/x-oleobject" />
+ <mimeMap fileExtension=".hhk" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".hhp" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".hlp" mimeType="application/winhlp" />
+ <mimeMap fileExtension=".hqx" mimeType="application/mac-binhex40" />
+ <mimeMap fileExtension=".hta" mimeType="application/hta" />
+ <mimeMap fileExtension=".htc" mimeType="text/x-component" />
+ <mimeMap fileExtension=".htm" mimeType="text/html" />
+ <mimeMap fileExtension=".html" mimeType="text/html" />
+ <mimeMap fileExtension=".htt" mimeType="text/webviewhtml" />
+ <mimeMap fileExtension=".hxt" mimeType="text/html" />
+ <mimeMap fileExtension=".ico" mimeType="image/x-icon" />
+ <mimeMap fileExtension=".ics" mimeType="text/calendar" />
+ <mimeMap fileExtension=".ief" mimeType="image/ief" />
+ <mimeMap fileExtension=".iii" mimeType="application/x-iphone" />
+ <mimeMap fileExtension=".inf" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".ins" mimeType="application/x-internet-signup" />
+ <mimeMap fileExtension=".isp" mimeType="application/x-internet-signup" />
+ <mimeMap fileExtension=".IVF" mimeType="video/x-ivf" />
+ <mimeMap fileExtension=".jar" mimeType="application/java-archive" />
+ <mimeMap fileExtension=".java" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".jck" mimeType="application/liquidmotion" />
+ <mimeMap fileExtension=".jcz" mimeType="application/liquidmotion" />
+ <mimeMap fileExtension=".jfif" mimeType="image/pjpeg" />
+ <mimeMap fileExtension=".jpb" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".jpe" mimeType="image/jpeg" />
+ <mimeMap fileExtension=".jpeg" mimeType="image/jpeg" />
+ <mimeMap fileExtension=".jpg" mimeType="image/jpeg" />
+ <mimeMap fileExtension=".js" mimeType="application/javascript" />
+ <mimeMap fileExtension=".json" mimeType="application/json" />
+ <mimeMap fileExtension=".jsonld" mimeType="application/ld+json" />
+ <mimeMap fileExtension=".jsx" mimeType="text/jscript" />
+ <mimeMap fileExtension=".latex" mimeType="application/x-latex" />
+ <mimeMap fileExtension=".less" mimeType="text/css" />
+ <mimeMap fileExtension=".lit" mimeType="application/x-ms-reader" />
+ <mimeMap fileExtension=".lpk" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".lsf" mimeType="video/x-la-asf" />
+ <mimeMap fileExtension=".lsx" mimeType="video/x-la-asf" />
+ <mimeMap fileExtension=".lzh" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".m13" mimeType="application/x-msmediaview" />
+ <mimeMap fileExtension=".m14" mimeType="application/x-msmediaview" />
+ <mimeMap fileExtension=".m1v" mimeType="video/mpeg" />
+ <mimeMap fileExtension=".m2ts" mimeType="video/vnd.dlna.mpeg-tts" />
+ <mimeMap fileExtension=".m3u" mimeType="audio/x-mpegurl" />
+ <mimeMap fileExtension=".m4a" mimeType="audio/mp4" />
+ <mimeMap fileExtension=".m4v" mimeType="video/mp4" />
+ <mimeMap fileExtension=".man" mimeType="application/x-troff-man" />
+ <mimeMap fileExtension=".manifest" mimeType="application/x-ms-manifest" />
+ <mimeMap fileExtension=".map" mimeType="text/plain" />
+ <mimeMap fileExtension=".mdb" mimeType="application/x-msaccess" />
+ <mimeMap fileExtension=".mdp" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".me" mimeType="application/x-troff-me" />
+ <mimeMap fileExtension=".mht" mimeType="message/rfc822" />
+ <mimeMap fileExtension=".mhtml" mimeType="message/rfc822" />
+ <mimeMap fileExtension=".mid" mimeType="audio/mid" />
+ <mimeMap fileExtension=".midi" mimeType="audio/mid" />
+ <mimeMap fileExtension=".mix" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".mmf" mimeType="application/x-smaf" />
+ <mimeMap fileExtension=".mno" mimeType="text/xml" />
+ <mimeMap fileExtension=".mny" mimeType="application/x-msmoney" />
+ <mimeMap fileExtension=".mov" mimeType="video/quicktime" />
+ <mimeMap fileExtension=".movie" mimeType="video/x-sgi-movie" />
+ <mimeMap fileExtension=".mp2" mimeType="video/mpeg" />
+ <mimeMap fileExtension=".mp3" mimeType="audio/mpeg" />
+ <mimeMap fileExtension=".mp4" mimeType="video/mp4" />
+ <mimeMap fileExtension=".mp4v" mimeType="video/mp4" />
+ <mimeMap fileExtension=".mpa" mimeType="video/mpeg" />
+ <mimeMap fileExtension=".mpe" mimeType="video/mpeg" />
+ <mimeMap fileExtension=".mpeg" mimeType="video/mpeg" />
+ <mimeMap fileExtension=".mpg" mimeType="video/mpeg" />
+ <mimeMap fileExtension=".mpp" mimeType="application/vnd.ms-project" />
+ <mimeMap fileExtension=".mpv2" mimeType="video/mpeg" />
+ <mimeMap fileExtension=".ms" mimeType="application/x-troff-ms" />
+ <mimeMap fileExtension=".msi" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".mso" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".mvb" mimeType="application/x-msmediaview" />
+ <mimeMap fileExtension=".mvc" mimeType="application/x-miva-compiled" />
+ <mimeMap fileExtension=".nc" mimeType="application/x-netcdf" />
+ <mimeMap fileExtension=".nsc" mimeType="video/x-ms-asf" />
+ <mimeMap fileExtension=".nws" mimeType="message/rfc822" />
+ <mimeMap fileExtension=".ocx" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".oda" mimeType="application/oda" />
+ <mimeMap fileExtension=".odc" mimeType="text/x-ms-odc" />
+ <mimeMap fileExtension=".ods" mimeType="application/oleobject" />
+ <mimeMap fileExtension=".oga" mimeType="audio/ogg" />
+ <mimeMap fileExtension=".ogg" mimeType="video/ogg" />
+ <mimeMap fileExtension=".ogv" mimeType="video/ogg" />
+ <mimeMap fileExtension=".one" mimeType="application/onenote" />
+ <mimeMap fileExtension=".onea" mimeType="application/onenote" />
+ <mimeMap fileExtension=".onetoc" mimeType="application/onenote" />
+ <mimeMap fileExtension=".onetoc2" mimeType="application/onenote" />
+ <mimeMap fileExtension=".onetmp" mimeType="application/onenote" />
+ <mimeMap fileExtension=".onepkg" mimeType="application/onenote" />
+ <mimeMap fileExtension=".osdx" mimeType="application/opensearchdescription+xml" />
+ <mimeMap fileExtension=".otf" mimeType="font/otf" />
+ <mimeMap fileExtension=".p10" mimeType="application/pkcs10" />
+ <mimeMap fileExtension=".p12" mimeType="application/x-pkcs12" />
+ <mimeMap fileExtension=".p7b" mimeType="application/x-pkcs7-certificates" />
+ <mimeMap fileExtension=".p7c" mimeType="application/pkcs7-mime" />
+ <mimeMap fileExtension=".p7m" mimeType="application/pkcs7-mime" />
+ <mimeMap fileExtension=".p7r" mimeType="application/x-pkcs7-certreqresp" />
+ <mimeMap fileExtension=".p7s" mimeType="application/pkcs7-signature" />
+ <mimeMap fileExtension=".pbm" mimeType="image/x-portable-bitmap" />
+ <mimeMap fileExtension=".pcx" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".pcz" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".pdf" mimeType="application/pdf" />
+ <mimeMap fileExtension=".pfb" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".pfm" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".pfx" mimeType="application/x-pkcs12" />
+ <mimeMap fileExtension=".pgm" mimeType="image/x-portable-graymap" />
+ <mimeMap fileExtension=".pko" mimeType="application/vnd.ms-pki.pko" />
+ <mimeMap fileExtension=".pma" mimeType="application/x-perfmon" />
+ <mimeMap fileExtension=".pmc" mimeType="application/x-perfmon" />
+ <mimeMap fileExtension=".pml" mimeType="application/x-perfmon" />
+ <mimeMap fileExtension=".pmr" mimeType="application/x-perfmon" />
+ <mimeMap fileExtension=".pmw" mimeType="application/x-perfmon" />
+ <mimeMap fileExtension=".png" mimeType="image/png" />
+ <mimeMap fileExtension=".pnm" mimeType="image/x-portable-anymap" />
+ <mimeMap fileExtension=".pnz" mimeType="image/png" />
+ <mimeMap fileExtension=".pot" mimeType="application/vnd.ms-powerpoint" />
+ <mimeMap fileExtension=".potm" mimeType="application/vnd.ms-powerpoint.template.macroEnabled.12" />
+ <mimeMap fileExtension=".potx" mimeType="application/vnd.openxmlformats-officedocument.presentationml.template" />
+ <mimeMap fileExtension=".ppam" mimeType="application/vnd.ms-powerpoint.addin.macroEnabled.12" />
+ <mimeMap fileExtension=".ppm" mimeType="image/x-portable-pixmap" />
+ <mimeMap fileExtension=".pps" mimeType="application/vnd.ms-powerpoint" />
+ <mimeMap fileExtension=".ppsm" mimeType="application/vnd.ms-powerpoint.slideshow.macroEnabled.12" />
+ <mimeMap fileExtension=".ppsx" mimeType="application/vnd.openxmlformats-officedocument.presentationml.slideshow" />
+ <mimeMap fileExtension=".ppt" mimeType="application/vnd.ms-powerpoint" />
+ <mimeMap fileExtension=".pptm" mimeType="application/vnd.ms-powerpoint.presentation.macroEnabled.12" />
+ <mimeMap fileExtension=".pptx" mimeType="application/vnd.openxmlformats-officedocument.presentationml.presentation" />
+ <mimeMap fileExtension=".prf" mimeType="application/pics-rules" />
+ <mimeMap fileExtension=".prm" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".prx" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".ps" mimeType="application/postscript" />
+ <mimeMap fileExtension=".psd" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".psm" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".psp" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".pub" mimeType="application/x-mspublisher" />
+ <mimeMap fileExtension=".qt" mimeType="video/quicktime" />
+ <mimeMap fileExtension=".qtl" mimeType="application/x-quicktimeplayer" />
+ <mimeMap fileExtension=".qxd" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".ra" mimeType="audio/x-pn-realaudio" />
+ <mimeMap fileExtension=".ram" mimeType="audio/x-pn-realaudio" />
+ <mimeMap fileExtension=".rar" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".ras" mimeType="image/x-cmu-raster" />
+ <mimeMap fileExtension=".rf" mimeType="image/vnd.rn-realflash" />
+ <mimeMap fileExtension=".rgb" mimeType="image/x-rgb" />
+ <mimeMap fileExtension=".rm" mimeType="application/vnd.rn-realmedia" />
+ <mimeMap fileExtension=".rmi" mimeType="audio/mid" />
+ <mimeMap fileExtension=".roff" mimeType="application/x-troff" />
+ <mimeMap fileExtension=".rpm" mimeType="audio/x-pn-realaudio-plugin" />
+ <mimeMap fileExtension=".rtf" mimeType="application/rtf" />
+ <mimeMap fileExtension=".rtx" mimeType="text/richtext" />
+ <mimeMap fileExtension=".scd" mimeType="application/x-msschedule" />
+ <mimeMap fileExtension=".sct" mimeType="text/scriptlet" />
+ <mimeMap fileExtension=".sea" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".setpay" mimeType="application/set-payment-initiation" />
+ <mimeMap fileExtension=".setreg" mimeType="application/set-registration-initiation" />
+ <mimeMap fileExtension=".sgml" mimeType="text/sgml" />
+ <mimeMap fileExtension=".sh" mimeType="application/x-sh" />
+ <mimeMap fileExtension=".shar" mimeType="application/x-shar" />
+ <mimeMap fileExtension=".sit" mimeType="application/x-stuffit" />
+ <mimeMap fileExtension=".sldm" mimeType="application/vnd.ms-powerpoint.slide.macroEnabled.12" />
+ <mimeMap fileExtension=".sldx" mimeType="application/vnd.openxmlformats-officedocument.presentationml.slide" />
+ <mimeMap fileExtension=".smd" mimeType="audio/x-smd" />
+ <mimeMap fileExtension=".smi" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".smx" mimeType="audio/x-smd" />
+ <mimeMap fileExtension=".smz" mimeType="audio/x-smd" />
+ <mimeMap fileExtension=".snd" mimeType="audio/basic" />
+ <mimeMap fileExtension=".snp" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".spc" mimeType="application/x-pkcs7-certificates" />
+ <mimeMap fileExtension=".spl" mimeType="application/futuresplash" />
+ <mimeMap fileExtension=".spx" mimeType="audio/ogg" />
+ <mimeMap fileExtension=".src" mimeType="application/x-wais-source" />
+ <mimeMap fileExtension=".ssm" mimeType="application/streamingmedia" />
+ <mimeMap fileExtension=".sst" mimeType="application/vnd.ms-pki.certstore" />
+ <mimeMap fileExtension=".stl" mimeType="application/vnd.ms-pki.stl" />
+ <mimeMap fileExtension=".sv4cpio" mimeType="application/x-sv4cpio" />
+ <mimeMap fileExtension=".sv4crc" mimeType="application/x-sv4crc" />
+ <mimeMap fileExtension=".svg" mimeType="image/svg+xml" />
+ <mimeMap fileExtension=".svgz" mimeType="image/svg+xml" />
+ <mimeMap fileExtension=".swf" mimeType="application/x-shockwave-flash" />
+ <mimeMap fileExtension=".t" mimeType="application/x-troff" />
+ <mimeMap fileExtension=".tar" mimeType="application/x-tar" />
+ <mimeMap fileExtension=".tcl" mimeType="application/x-tcl" />
+ <mimeMap fileExtension=".tex" mimeType="application/x-tex" />
+ <mimeMap fileExtension=".texi" mimeType="application/x-texinfo" />
+ <mimeMap fileExtension=".texinfo" mimeType="application/x-texinfo" />
+ <mimeMap fileExtension=".tgz" mimeType="application/x-compressed" />
+ <mimeMap fileExtension=".thmx" mimeType="application/vnd.ms-officetheme" />
+ <mimeMap fileExtension=".thn" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".tif" mimeType="image/tiff" />
+ <mimeMap fileExtension=".tiff" mimeType="image/tiff" />
+ <mimeMap fileExtension=".toc" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".tr" mimeType="application/x-troff" />
+ <mimeMap fileExtension=".trm" mimeType="application/x-msterminal" />
+ <mimeMap fileExtension=".ts" mimeType="video/vnd.dlna.mpeg-tts" />
+ <mimeMap fileExtension=".tsv" mimeType="text/tab-separated-values" />
+ <mimeMap fileExtension=".ttf" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".tts" mimeType="video/vnd.dlna.mpeg-tts" />
+ <mimeMap fileExtension=".txt" mimeType="text/plain" />
+ <mimeMap fileExtension=".u32" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".uls" mimeType="text/iuls" />
+ <mimeMap fileExtension=".ustar" mimeType="application/x-ustar" />
+ <mimeMap fileExtension=".vbs" mimeType="text/vbscript" />
+ <mimeMap fileExtension=".vcf" mimeType="text/x-vcard" />
+ <mimeMap fileExtension=".vcs" mimeType="text/plain" />
+ <mimeMap fileExtension=".vdx" mimeType="application/vnd.ms-visio.viewer" />
+ <mimeMap fileExtension=".vml" mimeType="text/xml" />
+ <mimeMap fileExtension=".vsd" mimeType="application/vnd.visio" />
+ <mimeMap fileExtension=".vss" mimeType="application/vnd.visio" />
+ <mimeMap fileExtension=".vst" mimeType="application/vnd.visio" />
+ <mimeMap fileExtension=".vsto" mimeType="application/x-ms-vsto" />
+ <mimeMap fileExtension=".vsw" mimeType="application/vnd.visio" />
+ <mimeMap fileExtension=".vsx" mimeType="application/vnd.visio" />
+ <mimeMap fileExtension=".vtx" mimeType="application/vnd.visio" />
+ <mimeMap fileExtension=".wav" mimeType="audio/wav" />
+ <mimeMap fileExtension=".wax" mimeType="audio/x-ms-wax" />
+ <mimeMap fileExtension=".wbmp" mimeType="image/vnd.wap.wbmp" />
+ <mimeMap fileExtension=".wcm" mimeType="application/vnd.ms-works" />
+ <mimeMap fileExtension=".wdb" mimeType="application/vnd.ms-works" />
+ <mimeMap fileExtension=".webm" mimeType="video/webm" />
+ <mimeMap fileExtension=".wks" mimeType="application/vnd.ms-works" />
+ <mimeMap fileExtension=".wm" mimeType="video/x-ms-wm" />
+ <mimeMap fileExtension=".wma" mimeType="audio/x-ms-wma" />
+ <mimeMap fileExtension=".wmd" mimeType="application/x-ms-wmd" />
+ <mimeMap fileExtension=".wmf" mimeType="application/x-msmetafile" />
+ <mimeMap fileExtension=".wml" mimeType="text/vnd.wap.wml" />
+ <mimeMap fileExtension=".wmlc" mimeType="application/vnd.wap.wmlc" />
+ <mimeMap fileExtension=".wmls" mimeType="text/vnd.wap.wmlscript" />
+ <mimeMap fileExtension=".wmlsc" mimeType="application/vnd.wap.wmlscriptc" />
+ <mimeMap fileExtension=".wmp" mimeType="video/x-ms-wmp" />
+ <mimeMap fileExtension=".wmv" mimeType="video/x-ms-wmv" />
+ <mimeMap fileExtension=".wmx" mimeType="video/x-ms-wmx" />
+ <mimeMap fileExtension=".wmz" mimeType="application/x-ms-wmz" />
+ <mimeMap fileExtension=".woff" mimeType="font/x-woff" />
+ <mimeMap fileExtension=".woff2" mimeType="application/font-woff2" />
+ <mimeMap fileExtension=".wps" mimeType="application/vnd.ms-works" />
+ <mimeMap fileExtension=".wri" mimeType="application/x-mswrite" />
+ <mimeMap fileExtension=".wrl" mimeType="x-world/x-vrml" />
+ <mimeMap fileExtension=".wrz" mimeType="x-world/x-vrml" />
+ <mimeMap fileExtension=".wsdl" mimeType="text/xml" />
+ <mimeMap fileExtension=".wtv" mimeType="video/x-ms-wtv" />
+ <mimeMap fileExtension=".wvx" mimeType="video/x-ms-wvx" />
+ <mimeMap fileExtension=".x" mimeType="application/directx" />
+ <mimeMap fileExtension=".xaf" mimeType="x-world/x-vrml" />
+ <mimeMap fileExtension=".xaml" mimeType="application/xaml+xml" />
+ <mimeMap fileExtension=".xap" mimeType="application/x-silverlight-app" />
+ <mimeMap fileExtension=".xbap" mimeType="application/x-ms-xbap" />
+ <mimeMap fileExtension=".xbm" mimeType="image/x-xbitmap" />
+ <mimeMap fileExtension=".xdr" mimeType="text/plain" />
+ <mimeMap fileExtension=".xht" mimeType="application/xhtml+xml" />
+ <mimeMap fileExtension=".xhtml" mimeType="application/xhtml+xml" />
+ <mimeMap fileExtension=".xla" mimeType="application/vnd.ms-excel" />
+ <mimeMap fileExtension=".xlam" mimeType="application/vnd.ms-excel.addin.macroEnabled.12" />
+ <mimeMap fileExtension=".xlc" mimeType="application/vnd.ms-excel" />
+ <mimeMap fileExtension=".xlm" mimeType="application/vnd.ms-excel" />
+ <mimeMap fileExtension=".xls" mimeType="application/vnd.ms-excel" />
+ <mimeMap fileExtension=".xlsb" mimeType="application/vnd.ms-excel.sheet.binary.macroEnabled.12" />
+ <mimeMap fileExtension=".xlsm" mimeType="application/vnd.ms-excel.sheet.macroEnabled.12" />
+ <mimeMap fileExtension=".xlsx" mimeType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" />
+ <mimeMap fileExtension=".xlt" mimeType="application/vnd.ms-excel" />
+ <mimeMap fileExtension=".xltm" mimeType="application/vnd.ms-excel.template.macroEnabled.12" />
+ <mimeMap fileExtension=".xltx" mimeType="application/vnd.openxmlformats-officedocument.spreadsheetml.template" />
+ <mimeMap fileExtension=".xlw" mimeType="application/vnd.ms-excel" />
+ <mimeMap fileExtension=".xml" mimeType="text/xml" />
+ <mimeMap fileExtension=".xof" mimeType="x-world/x-vrml" />
+ <mimeMap fileExtension=".xpm" mimeType="image/x-xpixmap" />
+ <mimeMap fileExtension=".xps" mimeType="application/vnd.ms-xpsdocument" />
+ <mimeMap fileExtension=".xsd" mimeType="text/xml" />
+ <mimeMap fileExtension=".xsf" mimeType="text/xml" />
+ <mimeMap fileExtension=".xsl" mimeType="text/xml" />
+ <mimeMap fileExtension=".xslt" mimeType="text/xml" />
+ <mimeMap fileExtension=".xsn" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".xtp" mimeType="application/octet-stream" />
+ <mimeMap fileExtension=".xwd" mimeType="image/x-xwindowdump" />
+ <mimeMap fileExtension=".z" mimeType="application/x-compress" />
+ <mimeMap fileExtension=".zip" mimeType="application/x-zip-compressed" />
+ </staticContent>
+
+ <tracing>
+
+ <traceProviderDefinitions>
+ <add name="WWW Server" guid="{3a2a4e84-4c21-4981-ae10-3fda0d9b0f83}">
+ <areas>
+ <clear />
+ <add name="Authentication" value="2" />
+ <add name="Security" value="4" />
+ <add name="Filter" value="8" />
+ <add name="StaticFile" value="16" />
+ <add name="CGI" value="32" />
+ <add name="Compression" value="64" />
+ <add name="Cache" value="128" />
+ <add name="RequestNotifications" value="256" />
+ <add name="Module" value="512" />
+ <add name="Rewrite" value="1024" />
+ <add name="FastCGI" value="4096" />
+ <add name="WebSocket" value="16384" />
+ </areas>
+ </add>
+ <add name="ASP" guid="{06b94d9a-b15e-456e-a4ef-37c984a2cb4b}">
+ <areas>
+ <clear />
+ </areas>
+ </add>
+ <add name="ISAPI Extension" guid="{a1c2040e-8840-4c31-ba11-9871031a19ea}">
+ <areas>
+ <clear />
+ </areas>
+ </add>
+ <add name="ASPNET" guid="{AFF081FE-0247-4275-9C4E-021F3DC1DA35}">
+ <areas>
+ <add name="Infrastructure" value="1" />
+ <add name="Module" value="2" />
+ <add name="Page" value="4" />
+ <add name="AppServices" value="8" />
+ </areas>
+ </add>
+ </traceProviderDefinitions>
+
+ <traceFailedRequests>
+ <add path="*">
+ <traceAreas>
+ <add provider="ASP" verbosity="Verbose" />
+ <add provider="ASPNET" areas="Infrastructure,Module,Page,AppServices" verbosity="Verbose" />
+ <add provider="ISAPI Extension" verbosity="Verbose" />
+ <add provider="WWW Server" areas="Authentication,Security,Filter,StaticFile,CGI,Compression,Cache,RequestNotifications,Module,Rewrite,WebSocket" verbosity="Verbose" />
+ </traceAreas>
+ <failureDefinitions statusCodes="200-999" />
+ </add>
+ </traceFailedRequests>
+
+ </tracing>
+
+ <urlCompression />
+
+ <validation />
+ <webdav>
+ <globalSettings>
+ <propertyStores>
+ <add name="webdav_simple_prop" image="%IIS_BIN%\webdav_simple_prop.dll" image32="%IIS_BIN%\webdav_simple_prop.dll" />
+ </propertyStores>
+ <lockStores>
+ <add name="webdav_simple_lock" image="%IIS_BIN%\webdav_simple_lock.dll" image32="%IIS_BIN%\webdav_simple_lock.dll" />
+ </lockStores>
+
+ </globalSettings>
+ <authoring>
+ <locks enabled="true" lockStore="webdav_simple_lock" />
+ </authoring>
+ <authoringRules />
+ </webdav>
+ <webSocket />
+ <applicationInitialization />
+
+ </system.webServer>
+ <location path="" overrideMode="Allow">
+ <system.webServer>
+ <modules>
+ <add name="IsapiFilterModule" lockItem="true" />
+ <add name="BasicAuthenticationModule" lockItem="true" />
+ <add name="IsapiModule" lockItem="true" />
+ <add name="HttpLoggingModule" lockItem="true" />
+ <!--
+ <add name="HttpCacheModule" lockItem="true" />
+-->
+ <add name="DynamicCompressionModule" lockItem="true" />
+ <add name="StaticCompressionModule" lockItem="true" />
+ <add name="DefaultDocumentModule" lockItem="true" />
+ <add name="DirectoryListingModule" lockItem="true" />
+
+ <add name="ProtocolSupportModule" lockItem="true" />
+ <add name="HttpRedirectionModule" lockItem="true" />
+ <add name="ServerSideIncludeModule" lockItem="true" />
+ <add name="StaticFileModule" lockItem="true" />
+ <add name="AnonymousAuthenticationModule" lockItem="true" />
+ <add name="CertificateMappingAuthenticationModule" lockItem="true" />
+ <add name="UrlAuthorizationModule" lockItem="true" />
+ <add name="WindowsAuthenticationModule" lockItem="true" />
+ <!--
+ <add name="DigestAuthenticationModule" lockItem="true" />
+-->
+ <add name="IISCertificateMappingAuthenticationModule" lockItem="true" />
+ <add name="WebMatrixSupportModule" lockItem="true" />
+ <add name="IpRestrictionModule" lockItem="true" />
+ <add name="DynamicIpRestrictionModule" lockItem="true" />
+ <add name="RequestFilteringModule" lockItem="true" />
+ <add name="CustomLoggingModule" lockItem="true" />
+ <add name="CustomErrorModule" lockItem="true" />
+ <add name="FailedRequestsTracingModule" lockItem="true" />
+ <add name="CgiModule" lockItem="true" />
+ <add name="FastCgiModule" lockItem="true" />
+ <!-- <add name="WebDAVModule" /> -->
+ <add name="RewriteModule" />
+ <add name="OutputCache" type="System.Web.Caching.OutputCacheModule" preCondition="managedHandler" />
+ <add name="Session" type="System.Web.SessionState.SessionStateModule" preCondition="managedHandler" />
+ <add name="WindowsAuthentication" type="System.Web.Security.WindowsAuthenticationModule" preCondition="managedHandler" />
+ <add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" preCondition="managedHandler" />
+ <add name="DefaultAuthentication" type="System.Web.Security.DefaultAuthenticationModule" preCondition="managedHandler" />
+ <add name="RoleManager" type="System.Web.Security.RoleManagerModule" preCondition="managedHandler" />
+ <add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule" preCondition="managedHandler" />
+ <add name="FileAuthorization" type="System.Web.Security.FileAuthorizationModule" preCondition="managedHandler" />
+ <add name="AnonymousIdentification" type="System.Web.Security.AnonymousIdentificationModule" preCondition="managedHandler" />
+ <add name="Profile" type="System.Web.Profile.ProfileModule" preCondition="managedHandler" />
+ <add name="UrlMappingsModule" type="System.Web.UrlMappingsModule" preCondition="managedHandler" />
+ <add name="ConfigurationValidationModule" lockItem="true" />
+ <add name="WebSocketModule" lockItem="true" />
+ <add name="ServiceModel-4.0" type="System.ServiceModel.Activation.ServiceHttpModule,System.ServiceModel.Activation,Version=4.0.0.0,Culture=neutral,PublicKeyToken=31bf3856ad364e35" preCondition="managedHandler,runtimeVersionv4.0" />
+ <add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="managedHandler,runtimeVersionv4.0" />
+ <add name="ScriptModule-4.0" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="managedHandler,runtimeVersionv4.0" />
+ <add name="ServiceModel" type="System.ServiceModel.Activation.HttpModule, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler,runtimeVersionv2.0" />
+ <add name="ApplicationInitializationModule" lockItem="true" />
+ <add name="AspNetCoreModule" lockItem="true" />
+ </modules>
+ <handlers accessPolicy="Read, Script">
+ <!-- <add name="WebDAV" path="*" verb="PROPFIND,PROPPATCH,MKCOL,PUT,COPY,DELETE,MOVE,LOCK,UNLOCK" modules="WebDAVModule" resourceType="Unspecified" requireAccess="None" /> -->
+ <add name="AXD-ISAPI-4.0_64bit" path="*.axd" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+ <add name="PageHandlerFactory-ISAPI-4.0_64bit" path="*.aspx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+ <add name="SimpleHandlerFactory-ISAPI-4.0_64bit" path="*.ashx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+ <add name="WebServiceHandlerFactory-ISAPI-4.0_64bit" path="*.asmx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+ <add name="HttpRemotingHandlerFactory-rem-ISAPI-4.0_64bit" path="*.rem" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+ <add name="HttpRemotingHandlerFactory-soap-ISAPI-4.0_64bit" path="*.soap" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+ <add name="svc-ISAPI-4.0_64bit" path="*.svc" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
+ <add name="rules-ISAPI-4.0_64bit" path="*.rules" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
+ <add name="xoml-ISAPI-4.0_64bit" path="*.xoml" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
+ <add name="xamlx-ISAPI-4.0_64bit" path="*.xamlx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
+ <add name="aspq-ISAPI-4.0_64bit" path="*.aspq" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+ <add name="cshtm-ISAPI-4.0_64bit" path="*.cshtm" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+ <add name="cshtml-ISAPI-4.0_64bit" path="*.cshtml" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+ <add name="vbhtm-ISAPI-4.0_64bit" path="*.vbhtm" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+ <add name="vbhtml-ISAPI-4.0_64bit" path="*.vbhtml" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+ <add name="svc-Integrated" path="*.svc" verb="*" type="System.ServiceModel.Activation.HttpHandler, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv2.0" />
+ <add name="svc-ISAPI-2.0" path="*.svc" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" />
+ <add name="xoml-Integrated" path="*.xoml" verb="*" type="System.ServiceModel.Activation.HttpHandler, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv2.0" />
+ <add name="xoml-ISAPI-2.0" path="*.xoml" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" />
+ <add name="rules-Integrated" path="*.rules" verb="*" type="System.ServiceModel.Activation.HttpHandler, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv2.0" />
+ <add name="rules-ISAPI-2.0" path="*.rules" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" />
+ <add name="AXD-ISAPI-4.0_32bit" path="*.axd" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+ <add name="PageHandlerFactory-ISAPI-4.0_32bit" path="*.aspx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+ <add name="SimpleHandlerFactory-ISAPI-4.0_32bit" path="*.ashx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+ <add name="WebServiceHandlerFactory-ISAPI-4.0_32bit" path="*.asmx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+ <add name="HttpRemotingHandlerFactory-rem-ISAPI-4.0_32bit" path="*.rem" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+ <add name="HttpRemotingHandlerFactory-soap-ISAPI-4.0_32bit" path="*.soap" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+ <add name="svc-ISAPI-4.0_32bit" path="*.svc" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" />
+ <add name="rules-ISAPI-4.0_32bit" path="*.rules" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" />
+ <add name="xoml-ISAPI-4.0_32bit" path="*.xoml" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" />
+ <add name="xamlx-ISAPI-4.0_32bit" path="*.xamlx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" />
+ <add name="aspq-ISAPI-4.0_32bit" path="*.aspq" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+ <add name="cshtm-ISAPI-4.0_32bit" path="*.cshtm" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+ <add name="cshtml-ISAPI-4.0_32bit" path="*.cshtml" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+ <add name="vbhtm-ISAPI-4.0_32bit" path="*.vbhtm" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+ <add name="vbhtml-ISAPI-4.0_32bit" path="*.vbhtml" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+ <add name="TraceHandler-Integrated-4.0" path="trace.axd" verb="GET,HEAD,POST,DEBUG" type="System.Web.Handlers.TraceHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+ <add name="WebAdminHandler-Integrated-4.0" path="WebAdmin.axd" verb="GET,DEBUG" type="System.Web.Handlers.WebAdminHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+ <add name="AssemblyResourceLoader-Integrated-4.0" path="WebResource.axd" verb="GET,DEBUG" type="System.Web.Handlers.AssemblyResourceLoader" preCondition="integratedMode,runtimeVersionv4.0" />
+ <add name="PageHandlerFactory-Integrated-4.0" path="*.aspx" verb="GET,HEAD,POST,DEBUG" type="System.Web.UI.PageHandlerFactory" preCondition="integratedMode,runtimeVersionv4.0" />
+ <add name="SimpleHandlerFactory-Integrated-4.0" path="*.ashx" verb="GET,HEAD,POST,DEBUG" type="System.Web.UI.SimpleHandlerFactory" preCondition="integratedMode,runtimeVersionv4.0" />
+ <add name="WebServiceHandlerFactory-Integrated-4.0" path="*.asmx" verb="GET,HEAD,POST,DEBUG" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="integratedMode,runtimeVersionv4.0" />
+ <add name="HttpRemotingHandlerFactory-rem-Integrated-4.0" path="*.rem" verb="GET,HEAD,POST,DEBUG" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory, System.Runtime.Remoting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv4.0" />
+ <add name="HttpRemotingHandlerFactory-soap-Integrated-4.0" path="*.soap" verb="GET,HEAD,POST,DEBUG" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory, System.Runtime.Remoting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv4.0" />
+ <add name="svc-Integrated-4.0" path="*.svc" verb="*" type="System.ServiceModel.Activation.ServiceHttpHandlerFactory, System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="integratedMode,runtimeVersionv4.0" />
+ <add name="rules-Integrated-4.0" path="*.rules" verb="*" type="System.ServiceModel.Activation.ServiceHttpHandlerFactory, System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="integratedMode,runtimeVersionv4.0" />
+ <add name="xoml-Integrated-4.0" path="*.xoml" verb="*" type="System.ServiceModel.Activation.ServiceHttpHandlerFactory, System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="integratedMode,runtimeVersionv4.0" />
+ <add name="xamlx-Integrated-4.0" path="*.xamlx" verb="GET,HEAD,POST,DEBUG" type="System.Xaml.Hosting.XamlHttpHandlerFactory, System.Xaml.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="integratedMode,runtimeVersionv4.0" />
+ <add name="aspq-Integrated-4.0" path="*.aspq" verb="GET,HEAD,POST,DEBUG" type="System.Web.HttpForbiddenHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+ <add name="cshtm-Integrated-4.0" path="*.cshtm" verb="GET,HEAD,POST,DEBUG" type="System.Web.HttpForbiddenHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+ <add name="cshtml-Integrated-4.0" path="*.cshtml" verb="GET,HEAD,POST,DEBUG" type="System.Web.HttpForbiddenHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+ <add name="vbhtm-Integrated-4.0" path="*.vbhtm" verb="GET,HEAD,POST,DEBUG" type="System.Web.HttpForbiddenHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+ <add name="vbhtml-Integrated-4.0" path="*.vbhtml" verb="GET,HEAD,POST,DEBUG" type="System.Web.HttpForbiddenHandler" preCondition="integratedMode,runtimeVersionv4.0" />
+ <add name="ScriptHandlerFactoryAppServices-Integrated-4.0" path="*_AppService.axd" verb="*" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" preCondition="integratedMode,runtimeVersionv4.0" />
+ <add name="ScriptResourceIntegrated-4.0" path="*ScriptResource.axd" verb="GET,HEAD" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" preCondition="integratedMode,runtimeVersionv4.0" />
+ <add name="ASPClassic" path="*.asp" verb="GET,HEAD,POST" modules="IsapiModule" scriptProcessor="%IIS_BIN%\asp.dll" resourceType="File" />
+ <add name="SecurityCertificate" path="*.cer" verb="GET,HEAD,POST" modules="IsapiModule" scriptProcessor="%IIS_BIN%\asp.dll" resourceType="File" />
+ <add name="ISAPI-dll" path="*.dll" verb="*" modules="IsapiModule" resourceType="File" requireAccess="Execute" allowPathInfo="true" />
+ <add name="TraceHandler-Integrated" path="trace.axd" verb="GET,HEAD,POST,DEBUG" type="System.Web.Handlers.TraceHandler" preCondition="integratedMode,runtimeVersionv2.0" />
+ <add name="WebAdminHandler-Integrated" path="WebAdmin.axd" verb="GET,DEBUG" type="System.Web.Handlers.WebAdminHandler" preCondition="integratedMode,runtimeVersionv2.0" />
+ <add name="AssemblyResourceLoader-Integrated" path="WebResource.axd" verb="GET,DEBUG" type="System.Web.Handlers.AssemblyResourceLoader" preCondition="integratedMode,runtimeVersionv2.0" />
+ <add name="PageHandlerFactory-Integrated" path="*.aspx" verb="GET,HEAD,POST,DEBUG" type="System.Web.UI.PageHandlerFactory" preCondition="integratedMode,runtimeVersionv2.0" />
+ <add name="SimpleHandlerFactory-Integrated" path="*.ashx" verb="GET,HEAD,POST,DEBUG" type="System.Web.UI.SimpleHandlerFactory" preCondition="integratedMode,runtimeVersionv2.0" />
+ <add name="WebServiceHandlerFactory-Integrated" path="*.asmx" verb="GET,HEAD,POST,DEBUG" type="System.Web.Services.Protocols.WebServiceHandlerFactory,System.Web.Services,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a" preCondition="integratedMode,runtimeVersionv2.0" />
+ <add name="HttpRemotingHandlerFactory-rem-Integrated" path="*.rem" verb="GET,HEAD,POST,DEBUG" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory,System.Runtime.Remoting,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv2.0" />
+ <add name="HttpRemotingHandlerFactory-soap-Integrated" path="*.soap" verb="GET,HEAD,POST,DEBUG" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory,System.Runtime.Remoting,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089" preCondition="integratedMode,runtimeVersionv2.0" />
+ <add name="AXD-ISAPI-2.0" path="*.axd" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+ <add name="PageHandlerFactory-ISAPI-2.0" path="*.aspx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+ <add name="SimpleHandlerFactory-ISAPI-2.0" path="*.ashx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+ <add name="WebServiceHandlerFactory-ISAPI-2.0" path="*.asmx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+ <add name="HttpRemotingHandlerFactory-rem-ISAPI-2.0" path="*.rem" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+ <add name="HttpRemotingHandlerFactory-soap-ISAPI-2.0" path="*.soap" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
+ <add name="svc-ISAPI-2.0-64" path="*.svc" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" />
+ <add name="AXD-ISAPI-2.0-64" path="*.axd" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+ <add name="PageHandlerFactory-ISAPI-2.0-64" path="*.aspx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+ <add name="SimpleHandlerFactory-ISAPI-2.0-64" path="*.ashx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+ <add name="WebServiceHandlerFactory-ISAPI-2.0-64" path="*.asmx" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+ <add name="HttpRemotingHandlerFactory-rem-ISAPI-2.0-64" path="*.rem" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+ <add name="HttpRemotingHandlerFactory-soap-ISAPI-2.0-64" path="*.soap" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0" />
+ <add name="rules-64-ISAPI-2.0" path="*.rules" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" />
+ <add name="xoml-64-ISAPI-2.0" path="*.xoml" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv2.0,bitness64" />
+ <add name="CGI-exe" path="*.exe" verb="*" modules="CgiModule" resourceType="File" requireAccess="Execute" allowPathInfo="true" />
+ <add name="SSINC-stm" path="*.stm" verb="GET,HEAD,POST" modules="ServerSideIncludeModule" resourceType="File" />
+ <add name="SSINC-shtm" path="*.shtm" verb="GET,HEAD,POST" modules="ServerSideIncludeModule" resourceType="File" />
+ <add name="SSINC-shtml" path="*.shtml" verb="GET,HEAD,POST" modules="ServerSideIncludeModule" resourceType="File" />
+ <add name="TRACEVerbHandler" path="*" verb="TRACE" modules="ProtocolSupportModule" requireAccess="None" />
+ <add name="OPTIONSVerbHandler" path="*" verb="OPTIONS" modules="ProtocolSupportModule" requireAccess="None" />
+ <add name="ExtensionlessUrl-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
+ <add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
+ <add name="ExtensionlessUrl-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" responseBufferLimit="0" />
+ <add name="StaticFile" path="*" verb="*" modules="StaticFileModule,DefaultDocumentModule,DirectoryListingModule" resourceType="Either" requireAccess="Read" />
+ </handlers>
+ </system.webServer>
+ </location>
+</configuration>
diff --git a/data/web/inc/lib/vendor/robthree/twofactorauth/README.md b/data/web/inc/lib/vendor/robthree/twofactorauth/README.md
index ba6cfeab..d65eb199 100644
--- a/data/web/inc/lib/vendor/robthree/twofactorauth/README.md
+++ b/data/web/inc/lib/vendor/robthree/twofactorauth/README.md
@@ -10,7 +10,7 @@ PHP library for [two-factor (or multi-factor) authentication](http://en.wikipedi
## Requirements
-* Tested on PHP 5.3, 5.4, 5.5 and 5.6, 7.0, 7.1 and HHVM
+* Tested on PHP 5.3, 5.4, 5.5 and 5.6, 7 and HHVM
* [cURL](http://php.net/manual/en/book.curl.php) when using the provided `GoogleQRCodeProvider` (default), `QRServerProvider` or `QRicketProvider` but you can also provide your own QR-code provider.
* [random_bytes()](http://php.net/manual/en/function.random-bytes.php), [MCrypt](http://php.net/manual/en/book.mcrypt.php), [OpenSSL](http://php.net/manual/en/book.openssl.php) or [Hash](http://php.net/manual/en/book.hash.php) depending on which built-in RNG you use (TwoFactorAuth will try to 'autodetect' and use the best available); however: feel free to provide your own (CS)RNG.
diff --git a/data/web/inc/lib/vendor/robthree/twofactorauth/composer.json b/data/web/inc/lib/vendor/robthree/twofactorauth/composer.json
index 1ea66ab0..a4c13758 100644
--- a/data/web/inc/lib/vendor/robthree/twofactorauth/composer.json
+++ b/data/web/inc/lib/vendor/robthree/twofactorauth/composer.json
@@ -1,7 +1,7 @@
{
"name": "robthree/twofactorauth",
"description": "Two Factor Authentication",
- "version": "1.6.1",
+ "version": "1.6",
"type": "library",
"keywords": [ "Authentication", "Two Factor Authentication", "Multi Factor Authentication", "TFA", "MFA", "PHP", "Authenticator", "Authy" ],
"homepage": "https://github.com/RobThree/TwoFactorAuth",
diff --git a/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Time/ConvertUnixTimeDotComTimeProvider.php b/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Time/ConvertUnixTimeDotComTimeProvider.php
index 9a775fc8..4939f0d4 100644
--- a/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Time/ConvertUnixTimeDotComTimeProvider.php
+++ b/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Time/ConvertUnixTimeDotComTimeProvider.php
@@ -6,7 +6,7 @@ class ConvertUnixTimeDotComTimeProvider implements ITimeProvider
{
public function getTime() {
$json = @json_decode(
- @file_get_contents('http://www.convert-unix-time.com/api?timestamp=now&r=' . uniqid(null, true))
+ @file_get_contents('http://www.convert-unix-time.com/api?timestamp=now')
);
if ($json === null || !is_int($json->timestamp))
throw new \TimeException('Unable to retrieve time from convert-unix-time.com');
diff --git a/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Time/HttpTimeProvider.php b/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Time/HttpTimeProvider.php
index 8e7806e2..c761bd97 100644
--- a/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Time/HttpTimeProvider.php
+++ b/data/web/inc/lib/vendor/robthree/twofactorauth/lib/Providers/Time/HttpTimeProvider.php
@@ -26,8 +26,7 @@ class HttpTimeProvider implements ITimeProvider
'request_fulluri' => true,
'header' => array(
'Connection: close',
- 'User-agent: TwoFactorAuth HttpTimeProvider (https://github.com/RobThree/TwoFactorAuth)',
- 'Cache-Control: no-cache'
+ 'User-agent: TwoFactorAuth HttpTimeProvider (https://github.com/RobThree/TwoFactorAuth)'
)
)
);
diff --git a/data/web/inc/lib/vendor/yubico/u2flib-server/src/u2flib_server/U2F.php.1 b/data/web/inc/lib/vendor/yubico/u2flib-server/src/u2flib_server/U2F.php.1
deleted file mode 100644
index a11c78fb..00000000
--- a/data/web/inc/lib/vendor/yubico/u2flib-server/src/u2flib_server/U2F.php.1
+++ /dev/null
@@ -1,507 +0,0 @@
-<?php
-/* Copyright (c) 2014 Yubico AB
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials provided
- * with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-namespace u2flib_server;
-
-/** Constant for the version of the u2f protocol */
-const U2F_VERSION = "U2F_V2";
-
-/** Error for the authentication message not matching any outstanding
- * authentication request */
-const ERR_NO_MATCHING_REQUEST = 1;
-
-/** Error for the authentication message not matching any registration */
-const ERR_NO_MATCHING_REGISTRATION = 2;
-
-/** Error for the signature on the authentication message not verifying with
- * the correct key */
-const ERR_AUTHENTICATION_FAILURE = 3;
-
-/** Error for the challenge in the registration message not matching the
- * registration challenge */
-const ERR_UNMATCHED_CHALLENGE = 4;
-
-/** Error for the attestation signature on the registration message not
- * verifying */
-const ERR_ATTESTATION_SIGNATURE = 5;
-
-/** Error for the attestation verification not verifying */
-const ERR_ATTESTATION_VERIFICATION = 6;
-
-/** Error for not getting good random from the system */
-const ERR_BAD_RANDOM = 7;
-
-/** Error when the counter is lower than expected */
-const ERR_COUNTER_TOO_LOW = 8;
-
-/** Error decoding public key */
-const ERR_PUBKEY_DECODE = 9;
-
-/** Error user-agent returned error */
-const ERR_BAD_UA_RETURNING = 10;
-
-/** Error old OpenSSL version */
-const ERR_OLD_OPENSSL = 11;
-
-/** @internal */
-const PUBKEY_LEN = 65;
-
-class U2F
-{
- /** @var string */
- private $appId;
-
- /** @var null|string */
- private $attestDir;
-
- /** @internal */
- private $FIXCERTS = array(
- '349bca1031f8c82c4ceca38b9cebf1a69df9fb3b94eed99eb3fb9aa3822d26e8',
- 'dd574527df608e47ae45fbba75a2afdd5c20fd94a02419381813cd55a2a3398f',
- '1d8764f0f7cd1352df6150045c8f638e517270e8b5dda1c63ade9c2280240cae',
- 'd0edc9a91a1677435a953390865d208c55b3183c6759c9b5a7ff494c322558eb',
- '6073c436dcd064a48127ddbf6032ac1a66fd59a0c24434f070d4e564c124c897',
- 'ca993121846c464d666096d35f13bf44c1b05af205f9b4a1e00cf6cc10c5e511'
- );
-
- /**
- * @param string $appId Application id for the running application
- * @param string|null $attestDir Directory where trusted attestation roots may be found
- * @throws Error If OpenSSL older than 1.0.0 is used
- */
- public function __construct($appId, $attestDir = null)
- {
- if(OPENSSL_VERSION_NUMBER < 0x10000000) {
- throw new Error('OpenSSL has to be at least version 1.0.0, this is ' . OPENSSL_VERSION_TEXT, ERR_OLD_OPENSSL);
- }
- $this->appId = $appId;
- $this->attestDir = $attestDir;
- }
-
- /**
- * Called to get a registration request to send to a user.
- * Returns an array of one registration request and a array of sign requests.
- *
- * @param array $registrations List of current registrations for this
- * user, to prevent the user from registering the same authenticator several
- * times.
- * @return array An array of two elements, the first containing a
- * RegisterRequest the second being an array of SignRequest
- * @throws Error
- */
- public function getRegisterData(array $registrations = array())
- {
- $challenge = $this->createChallenge();
- $request = new RegisterRequest($challenge, $this->appId);
- $signs = $this->getAuthenticateData($registrations);
- return array($request, $signs);
- }
-
- /**
- * Called to verify and unpack a registration message.
- *
- * @param RegisterRequest $request this is a reply to
- * @param object $response response from a user
- * @param bool $includeCert set to true if the attestation certificate should be
- * included in the returned Registration object
- * @return Registration
- * @throws Error
- */
- public function doRegister($request, $response, $includeCert = true)
- {
- if( !is_object( $request ) ) {
- throw new \InvalidArgumentException('$request of doRegister() method only accepts object.');
- }
-
- if( !is_object( $response ) ) {
- throw new \InvalidArgumentException('$response of doRegister() method only accepts object.');
- }
-
- if( property_exists( $response, 'errorCode') && $response->errorCode !== 0 ) {
- throw new Error('User-agent returned error. Error code: ' . $response->errorCode, ERR_BAD_UA_RETURNING );
- }
-
- if( !is_bool( $includeCert ) ) {
- throw new \InvalidArgumentException('$include_cert of doRegister() method only accepts boolean.');
- }
-
- $rawReg = $this->base64u_decode($response->registrationData);
- $regData = array_values(unpack('C*', $rawReg));
- $clientData = $this->base64u_decode($response->clientData);
- $cli = json_decode($clientData);
-
- if($cli->challenge !== $request->challenge) {
- throw new Error('Registration challenge does not match', ERR_UNMATCHED_CHALLENGE );
- }
-
- $registration = new Registration();
- $offs = 1;
- $pubKey = substr($rawReg, $offs, PUBKEY_LEN);
- $offs += PUBKEY_LEN;
- // decode the pubKey to make sure it's good
- $tmpKey = $this->pubkey_to_pem($pubKey);
- if($tmpKey === null) {
- throw new Error('Decoding of public key failed', ERR_PUBKEY_DECODE );
- }
- $registration->publicKey = base64_encode($pubKey);
- $khLen = $regData[$offs++];
- $kh = substr($rawReg, $offs, $khLen);
- $offs += $khLen;
- $registration->keyHandle = $this->base64u_encode($kh);
-
- // length of certificate is stored in byte 3 and 4 (excluding the first 4 bytes)
- $certLen = 4;
- $certLen += ($regData[$offs + 2] << 8);
- $certLen += $regData[$offs + 3];
-
- $rawCert = $this->fixSignatureUnusedBits(substr($rawReg, $offs, $certLen));
- $offs += $certLen;
- $pemCert = "-----BEGIN CERTIFICATE-----\r\n";
- $pemCert .= chunk_split(base64_encode($rawCert), 64);
- $pemCert .= "-----END CERTIFICATE-----";
- if($includeCert) {
- $registration->certificate = base64_encode($rawCert);
- }
- if($this->attestDir) {
- if(openssl_x509_checkpurpose($pemCert, -1, $this->get_certs()) !== true) {
- throw new Error('Attestation certificate can not be validated', ERR_ATTESTATION_VERIFICATION );
- }
- }
-
- if(!openssl_pkey_get_public($pemCert)) {
- throw new Error('Decoding of public key failed', ERR_PUBKEY_DECODE );
- }
- $signature = substr($rawReg, $offs);
-
- $dataToVerify = chr(0);
- $dataToVerify .= hash('sha256', $request->appId, true);
- $dataToVerify .= hash('sha256', $clientData, true);
- $dataToVerify .= $kh;
- $dataToVerify .= $pubKey;
-
- if(openssl_verify($dataToVerify, $signature, $pemCert, 'sha256') === 1) {
- return $registration;
- } else {
- throw new Error('Attestation signature does not match', ERR_ATTESTATION_SIGNATURE );
- }
- }
-
- /**
- * Called to get an authentication request.
- *
- * @param array $registrations An array of the registrations to create authentication requests for.
- * @return array An array of SignRequest
- * @throws Error
- */
- public function getAuthenticateData(array $registrations)
- {
- $sigs = array();
- $challenge = $this->createChallenge();
- foreach ($registrations as $reg) {
- if( !is_object( $reg ) ) {
- throw new \InvalidArgumentException('$registrations of getAuthenticateData() method only accepts array of object.');
- }
-
- $sig = new SignRequest();
- $sig->appId = $this->appId;
- $sig->keyHandle = $reg->keyHandle;
- $sig->challenge = $challenge;
- $sigs[] = $sig;
- }
- return $sigs;
- }
-
- /**
- * Called to verify an authentication response
- *
- * @param array $requests An array of outstanding authentication requests
- * @param array $registrations An array of current registrations
- * @param object $response A response from the authenticator
- * @return Registration
- * @throws Error
- *
- * The Registration object returned on success contains an updated counter
- * that should be saved for future authentications.
- * If the Error returned is ERR_COUNTER_TOO_LOW this is an indication of
- * token cloning or similar and appropriate action should be taken.
- */
- public function doAuthenticate(array $requests, array $registrations, $response)
- {
- if( !is_object( $response ) ) {
- throw new \InvalidArgumentException('$response of doAuthenticate() method only accepts object.');
- }
-
- if( property_exists( $response, 'errorCode') && $response->errorCode !== 0 ) {
- throw new Error('User-agent returned error. Error code: ' . $response->errorCode, ERR_BAD_UA_RETURNING );
- }
-
- /** @var object|null $req */
- $req = null;
-
- /** @var object|null $reg */
- $reg = null;
-
- $clientData = $this->base64u_decode($response->clientData);
- $decodedClient = json_decode($clientData);
- foreach ($requests as $req) {
- if( !is_object( $req ) ) {
- throw new \InvalidArgumentException('$requests of doAuthenticate() method only accepts array of object.');
- }
-
- if($req->keyHandle === $response->keyHandle && $req->challenge === $decodedClient->challenge) {
- break;
- }
-
- $req = null;
- }
- if($req === null) {
- throw new Error('No matching request found', ERR_NO_MATCHING_REQUEST );
- }
- foreach ($registrations as $reg) {
- if( !is_object( $reg ) ) {
- throw new \InvalidArgumentException('$registrations of doAuthenticate() method only accepts array of object.');
- }
-
- if($reg->keyHandle === $response->keyHandle) {
- break;
- }
- $reg = null;
- }
- if($reg === null) {
- throw new Error('No matching registration found', ERR_NO_MATCHING_REGISTRATION );
- }
- $pemKey = $this->pubkey_to_pem($this->base64u_decode($reg->publicKey));
- if($pemKey === null) {
- throw new Error('Decoding of public key failed', ERR_PUBKEY_DECODE );
- }
-
- $signData = $this->base64u_decode($response->signatureData);
- $dataToVerify = hash('sha256', $req->appId, true);
- $dataToVerify .= substr($signData, 0, 5);
- $dataToVerify .= hash('sha256', $clientData, true);
- $signature = substr($signData, 5);
-
- if(openssl_verify($dataToVerify, $signature, $pemKey, 'sha256') === 1) {
- $ctr = unpack("Nctr", substr($signData, 1, 4));
- $counter = $ctr['ctr'];
- /* TODO: wrap-around should be handled somehow.. */
- if($counter > $reg->counter) {
- $reg->counter = $counter;
- return $reg;
- } else {
- throw new Error('Counter too low.', ERR_COUNTER_TOO_LOW );
- }
- } else {
- throw new Error('Authentication failed', ERR_AUTHENTICATION_FAILURE );
- }
- }
-
- /**
- * @return array
- */
- private function get_certs()
- {
- $files = array();
- $dir = $this->attestDir;
- if($dir && $handle = opendir($dir)) {
- while(false !== ($entry = readdir($handle))) {
- if(is_file("$dir/$entry")) {
- $files[] = "$dir/$entry";
- }
- }
- closedir($handle);
- }
- return $files;
- }
-
- /**
- * @param string $data
- * @return string
- */
- private function base64u_encode($data)
- {
- return trim(strtr(base64_encode($data), '+/', '-_'), '=');
- }
-
- /**
- * @param string $data
- * @return string
- */
- private function base64u_decode($data)
- {
- return base64_decode(strtr($data, '-_', '+/'));
- }
-
- /**
- * @param string $key
- * @return null|string
- */
- private function pubkey_to_pem($key)
- {
- if(strlen($key) !== PUBKEY_LEN || $key[0] !== "\x04") {
- return null;
- }
-
- /*
- * Convert the public key to binary DER format first
- * Using the ECC SubjectPublicKeyInfo OIDs from RFC 5480
- *
- * SEQUENCE(2 elem) 30 59
- * SEQUENCE(2 elem) 30 13
- * OID1.2.840.10045.2.1 (id-ecPublicKey) 06 07 2a 86 48 ce 3d 02 01
- * OID1.2.840.10045.3.1.7 (secp256r1) 06 08 2a 86 48 ce 3d 03 01 07
- * BIT STRING(520 bit) 03 42 ..key..
- */
- $der = "\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01";
- $der .= "\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42";
- $der .= "\0".$key;
-
- $pem = "-----BEGIN PUBLIC KEY-----\r\n";
- $pem .= chunk_split(base64_encode($der), 64);
- $pem .= "-----END PUBLIC KEY-----";
-
- return $pem;
- }
-
- /**
- * @return string
- * @throws Error
- */
- private function createChallenge()
- {
- $challenge = openssl_random_pseudo_bytes(32, $crypto_strong );
- if( $crypto_strong !== true ) {
- throw new Error('Unable to obtain a good source of randomness', ERR_BAD_RANDOM);
- }
-
- $challenge = $this->base64u_encode( $challenge );
-
- return $challenge;
- }
-
- /**
- * Fixes a certificate where the signature contains unused bits.
- *
- * @param string $cert
- * @return mixed
- */
- private function fixSignatureUnusedBits($cert)
- {
- if(in_array(hash('sha256', $cert), $this->FIXCERTS)) {
- $cert[strlen($cert) - 257] = "\0";
- }
- return $cert;
- }
-}
-
-/**
- * Class for building a registration request
- *
- * @package u2flib_server
- */
-class RegisterRequest
-{
- /** Protocol version */
- public $version = U2F_VERSION;
-
- /** Registration challenge */
- public $challenge;
-
- /** Application id */
- public $appId;
-
- /**
- * @param string $challenge
- * @param string $appId
- * @internal
- */
- public function __construct($challenge, $appId)
- {
- $this->challenge = $challenge;
- $this->appId = $appId;
- }
-}
-
-/**
- * Class for building up an authentication request
- *
- * @package u2flib_server
- */
-class SignRequest
-{
- /** Protocol version */
- public $version = U2F_VERSION;
-
- /** Authentication challenge */
- public $challenge;
-
- /** Key handle of a registered authenticator */
- public $keyHandle;
-
- /** Application id */
- public $appId;
-}
-
-/**
- * Class returned for successful registrations
- *
- * @package u2flib_server
- */
-class Registration
-{
- /** The key handle of the registered authenticator */
- public $keyHandle;
-
- /** The public key of the registered authenticator */
- public $publicKey;
-
- /** The attestation certificate of the registered authenticator */
- public $certificate;
-
- /** The counter associated with this registration */
- public $counter = -1;
-}
-
-/**
- * Error class, returned on errors
- *
- * @package u2flib_server
- */
-class Error extends \Exception
-{
- /**
- * Override constructor and make message and code mandatory
- * @param string $message
- * @param int $code
- * @param \Exception|null $previous
- */
- public function __construct($message, $code, \Exception $previous = null) {
- parent::__construct($message, $code, $previous);
- }
-}
diff --git a/data/web/inc/prerequisites.inc.php b/data/web/inc/prerequisites.inc.php
index 3f13e7dc..c78b5aad 100644
--- a/data/web/inc/prerequisites.inc.php
+++ b/data/web/inc/prerequisites.inc.php
@@ -6,8 +6,6 @@ if (file_exists($_SERVER['DOCUMENT_ROOT'] . '/inc/vars.local.inc.php')) {
}
$autodiscover_config = array_merge($default_autodiscover_config, $autodiscover_config);
-require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/sessions.inc.php';
-
header_remove("X-Powered-By");
// Yubi OTP API
@@ -49,14 +47,26 @@ try {
}
catch (PDOException $e) {
?>
-<center style='font-family: "Lucida Sans Unicode", "Lucida Grande", Verdana, Arial, Helvetica, sans-serif;'>Connection failed, database may be in warm-up state, please try again later.<br /><br />The following error was reported:<br/> <?=$e->getMessage();?></center>
+<center style='font-family: "Lucida Sans Unicode", "Lucida Grande", Verdana, Arial, Helvetica, sans-serif;'>Connection to database failed.<br /><br />The following error was reported:<br/> <?=$e->getMessage();?></center>
<?php
exit;
}
+require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/sessions.inc.php';
+
// Set language
if (!isset($_SESSION['mailcow_locale'])) {
- $_SESSION['mailcow_locale'] = strtolower(trim($DEFAULT_LANG));
+ if ($DETECT_LANGUAGE && isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
+ $header_lang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2);
+ foreach ($AVAILABLE_LANGUAGES as $available_lang) {
+ if ($header_lang == $available_lang) {
+ $_SESSION['mailcow_locale'] = strtolower(trim($header_lang));
+ }
+ }
+ }
+ else {
+ $_SESSION['mailcow_locale'] = strtolower(trim($DEFAULT_LANG));
+ }
}
if (isset($_GET['lang']) && in_array($_GET['lang'], $AVAILABLE_LANGUAGES)) {
$_SESSION['mailcow_locale'] = $_GET['lang'];
@@ -69,6 +79,7 @@ require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.mailbox.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.customize.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.bcc.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.domain_admin.inc.php';
+require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.quarantaine.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.policy.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.dkim.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.fwdhost.inc.php';
@@ -81,3 +92,4 @@ init_db_schema();
if (isset($_SESSION['mailcow_cc_role'])) {
set_acl();
}
+$UI_TEXTS = customize('get', 'ui_texts');
diff --git a/data/web/inc/sessions.inc.php b/data/web/inc/sessions.inc.php
index fbdabfdc..f5a2184f 100644
--- a/data/web/inc/sessions.inc.php
+++ b/data/web/inc/sessions.inc.php
@@ -26,11 +26,29 @@ if (!isset($_SESSION['SESS_REMOTE_UA'])) {
$_SESSION['SESS_REMOTE_UA'] = $_SERVER['HTTP_USER_AGENT'];
}
+// API
+if (!empty($_SERVER['HTTP_X_API_KEY'])) {
+ $stmt = $pdo->prepare("SELECT `username`, `allow_from` FROM `api` WHERE `api_key` = :api_key AND `active` = '1';");
+ $stmt->execute(array(
+ ':api_key' => preg_replace('/[^A-Z0-9-]/', '', $_SERVER['HTTP_X_API_KEY'])
+ ));
+ $api_return = $stmt->fetch(PDO::FETCH_ASSOC);
+ if (!empty($api_return['username'])) {
+ if (in_array($_SERVER['REMOTE_ADDR'], explode(',', $api_return['allow_from']))) {
+ $_SESSION['mailcow_cc_username'] = $api_return['username'];
+ $_SESSION['mailcow_cc_role'] = 'admin';
+ $_SESSION['mailcow_cc_api'] = true;
+ }
+ }
+}
// Update session cookie
// setcookie(session_name() ,session_id(), time() + $SESSION_LIFETIME);
// Check session
function session_check() {
+ if ($_SESSION['mailcow_cc_api'] === true) {
+ return true;
+ }
if (!isset($_SESSION['SESS_REMOTE_UA'])) {
return false;
}
diff --git a/data/web/inc/triggers.inc.php b/data/web/inc/triggers.inc.php
index 10fbe4cc..bce8a20f 100644
--- a/data/web/inc/triggers.inc.php
+++ b/data/web/inc/triggers.inc.php
@@ -64,6 +64,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
}
}
if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == "admin") {
+ // TODO: Move file upload to API?
if (isset($_POST["submit_main_logo"])) {
if ($_FILES['main_logo']['error'] == 0) {
customize('add', 'main_logo', $_FILES);
@@ -72,5 +73,16 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == "admi
if (isset($_POST["reset_main_logo"])) {
customize('delete', 'main_logo');
}
+ // API cannot be controlled by API
+ if (isset($_POST["admin_api"])) {
+ admin_api('edit', $_POST);
+ }
+ if (isset($_POST["admin_api_regen_key"])) {
+ admin_api('regen_key', $_POST);
+ }
+ // Not available via API
+ if (isset($_POST["rspamd_ui"])) {
+ rspamd_ui('edit', $_POST);
+ }
}
?>
diff --git a/data/web/inc/vars.inc.php b/data/web/inc/vars.inc.php
index 12d8b3d9..5e5923b5 100644
--- a/data/web/inc/vars.inc.php
+++ b/data/web/inc/vars.inc.php
@@ -68,8 +68,12 @@ $autodiscover_config = array(
);
unset($https_port);
+// If false, we will use DEFAULT_LANG
+// Uses HTTP_ACCEPT_LANGUAGE header
+$DETECT_LANGUAGE = true;
+
// Change default language, "de", "en", "es", "nl", "pt", "ru"
-$DEFAULT_LANG = 'en';
+$DEFAULT_LANG = 'de';
// Available languages
$AVAILABLE_LANGUAGES = array('de', 'en', 'es', 'fr', 'nl', 'pl', 'pt', 'ru', 'it');
@@ -92,13 +96,7 @@ $MAILCOW_APPS = array(
array(
'name' => 'SOGo',
'link' => '/SOGo/',
- 'description' => 'SOGo is a web-based client for email, address book and calendar.'
- ),
- // array(
- // 'name' => 'Roundcube',
- // 'link' => '/rc/',
- // 'description' => 'Roundcube is a web-based email client.',
- // ),
+ )
);
// Rows until pagination begins
@@ -119,5 +117,6 @@ $OTP_LABEL = "mailcow UI";
// Default "to" address in relay test tool
$RELAY_TO = "[email protected]";
-// Internal constants, can be ignored
-define("F2B", 1);
\ No newline at end of file
+// Quarantaine data age in days to keep
+$QUARANTAINE_AGE = 10;
+
diff --git a/data/web/index.php b/data/web/index.php
index 42087cdc..8f7dcb20 100644
--- a/data/web/index.php
+++ b/data/web/index.php
@@ -13,9 +13,9 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
header('Location: /user.php');
exit();
}
-
require_once 'inc/header.inc.php';
$_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
+
?>
<div class="container">
<div class="row">
@@ -24,7 +24,7 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
<div class="panel-heading"><span class="glyphicon glyphicon-user" aria-hidden="true"></span> <?= $lang['login']['login']; ?></div>
<div class="panel-body">
<div class="text-center mailcow-logo"><img src="<?=($main_logo = customize('get', 'main_logo')) ? $main_logo : '/img/cow_mailcow.svg';?>" alt="mailcow"></div>
- <legend>mailcow UI</legend>
+ <legend><?=$UI_TEXTS['main_name'];?></legend>
<form method="post" autofill="off">
<div class="form-group">
<label class="sr-only" for="login_user"><?= $lang['login']['username']; ?></label>
@@ -65,7 +65,7 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
<?php
endif;
?>
- <legend>mailcow Apps</legend>
+ <legend><?=$UI_TEXTS['apps_name'];?></legend>
<?php
foreach ($MAILCOW_APPS as $app):
?>
@@ -93,10 +93,14 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
</div>
<div id="collapse1" class="panel-collapse collapse">
<div class="panel-body">
- <p><span style="border-bottom: 1px dotted #999;">mailcow UI</span></p>
+ <?php if ($UI_TEXTS['help_text']): ?>
+ <p><?=$UI_TEXTS['help_text'];?></p>
+ <?php else: ?>
+ <p><span style="border-bottom: 1px dotted #999;"><?=$UI_TEXTS['main_name'];?></span></p>
<p><?= $lang['start']['mailcow_panel_detail']; ?></p>
- <p><span style="border-bottom: 1px dotted #999;">mailcow Apps</span></p>
+ <p><span style="border-bottom: 1px dotted #999;"><?=$UI_TEXTS['apps_name'];?></span></p>
<p><?= $lang['start']['mailcow_apps_detail']; ?></p>
+ <?php endif; ?>
</div>
</div>
</div>
diff --git a/data/web/js/admin.js b/data/web/js/admin.js
index 997e76a3..c0929538 100644
--- a/data/web/js/admin.js
+++ b/data/web/js/admin.js
@@ -5,199 +5,10 @@ jQuery(function($){
var entityMap={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="};
function escapeHtml(n){return String(n).replace(/[&<>"'`=\/]/g,function(n){return entityMap[n]})}
function humanFileSize(i){if(Math.abs(i)<1024)return i+" B";var B=["KiB","MiB","GiB","TiB","PiB","EiB","ZiB","YiB"],e=-1;do{i/=1024,++e}while(Math.abs(i)>=1024&&e<B.length-1);return i.toFixed(1)+" "+B[e]}
- $("#refresh_postfix_log").on('click', function(e) {
- e.preventDefault();
- draw_postfix_logs();
- });
- $("#refresh_autodiscover_log").on('click', function(e) {
- e.preventDefault();
- draw_autodiscover_logs();
- });
- $("#refresh_dovecot_log").on('click', function(e) {
- e.preventDefault();
- draw_dovecot_logs();
- });
- $("#refresh_sogo_log").on('click', function(e) {
- e.preventDefault();
- draw_sogo_logs();
- });
- $("#refresh_fail2ban_log").on('click', function(e) {
- e.preventDefault();
- draw_fail2ban_logs();
- });
- $("#refresh_rspamd_history").on('click', function(e) {
- e.preventDefault();
- draw_rspamd_history();
- });
$("#import_dkim_legend").on('click', function(e) {
e.preventDefault();
$('#import_dkim_arrow').toggleClass("animation");
});
- function draw_autodiscover_logs() {
- ft_autodiscover_logs = FooTable.init('#autodiscover_log', {
- "columns": [
- {"name":"time","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleString();},"title":lang.time,"style":{"width":"170px"}},
- {"name":"ua","title":"User-Agent","style":{"min-width":"200px"}},
- {"name":"user","title":"Username","style":{"min-width":"200px"}},
- {"name":"service","title":"Service"},
- ],
- "rows": $.ajax({
- dataType: 'json',
- url: '/api/v1/get/logs/autodiscover/100',
- jsonp: false,
- error: function () {
- console.log('Cannot draw autodiscover log table');
- },
- success: function (data) {
- return process_table_data(data, 'autodiscover_log');
- }
- }),
- "empty": lang.empty,
- "paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
- "filtering": {"enabled": true,"position": "left","placeholder": lang.filter_table},
- "sorting": {"enabled": true},
- "on": {"ready.ft.table": function(e, ft){
- heading = ft.$el.parents('.tab-pane').find('.panel-heading')
- $(heading).children('.log-lines').text(function(){
- var ft_paging = ft.use(FooTable.Paging)
- return ft_paging.totalRows;
- })
- }
- }
- });
- }
- function draw_postfix_logs() {
- ft_postfix_logs = FooTable.init('#postfix_log', {
- "columns": [
- {"name":"time","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleString();},"title":lang.time,"style":{"width":"170px"}},
- {"name":"priority","title":lang.priority,"style":{"width":"80px"}},
- {"name":"message","title":lang.message},
- ],
- "rows": $.ajax({
- dataType: 'json',
- url: '/api/v1/get/logs/postfix',
- jsonp: false,
- error: function () {
- console.log('Cannot draw postfix log table');
- },
- success: function (data) {
- return process_table_data(data, 'general_syslog');
- }
- }),
- "empty": lang.empty,
- "paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
- "filtering": {"enabled": true,"position": "left","placeholder": lang.filter_table},
- "sorting": {"enabled": true},
- "on": {
- "ready.ft.table": function(e, ft){
- heading = ft.$el.parents('.tab-pane').find('.panel-heading')
- $(heading).children('.log-lines').text(function(){
- var ft_paging = ft.use(FooTable.Paging)
- return ft_paging.totalRows;
- })
- }
- }
- });
- }
- function draw_fail2ban_logs() {
- ft_fail2ban_logs = FooTable.init('#fail2ban_log', {
- "columns": [
- {"name":"time","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleString();},"title":lang.time,"style":{"width":"170px"}},
- {"name":"priority","title":lang.priority,"style":{"width":"80px"}},
- {"name":"message","title":lang.message},
- ],
- "rows": $.ajax({
- dataType: 'json',
- url: '/api/v1/get/logs/fail2ban',
- jsonp: false,
- error: function () {
- console.log('Cannot draw fail2ban log table');
- },
- success: function (data) {
- return process_table_data(data, 'general_syslog');
- }
- }),
- "empty": lang.empty,
- "paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
- "filtering": {"enabled": true,"position": "left","connectors": false,"placeholder": lang.filter_table},
- "sorting": {"enabled": true},
- "on": {
- "ready.ft.table": function(e, ft){
- heading = ft.$el.parents('.tab-pane').find('.panel-heading')
- $(heading).children('.log-lines').text(function(){
- var ft_paging = ft.use(FooTable.Paging)
- return ft_paging.totalRows;
- })
- }
- }
- });
- }
- function draw_sogo_logs() {
- ft_sogo_logs = FooTable.init('#sogo_log', {
- "columns": [
- {"name":"time","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleString();},"title":lang.time,"style":{"width":"170px"}},
- {"name":"priority","title":lang.priority,"style":{"width":"80px"}},
- {"name":"message","title":lang.message},
- ],
- "rows": $.ajax({
- dataType: 'json',
- url: '/api/v1/get/logs/sogo',
- jsonp: false,
- error: function () {
- console.log('Cannot draw sogo log table');
- },
- success: function (data) {
- return process_table_data(data, 'general_syslog');
- }
- }),
- "empty": lang.empty,
- "paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
- "filtering": {"enabled": true,"position": "left","connectors": false,"placeholder": lang.filter_table},
- "sorting": {"enabled": true},
- "on": {
- "ready.ft.table": function(e, ft){
- heading = ft.$el.parents('.tab-pane').find('.panel-heading')
- $(heading).children('.log-lines').text(function(){
- var ft_paging = ft.use(FooTable.Paging)
- return ft_paging.totalRows;
- })
- }
- }
- });
- }
- function draw_dovecot_logs() {
- ft_dovecot_logs = FooTable.init('#dovecot_log', {
- "columns": [
- {"name":"time","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleString();},"title":lang.time,"style":{"width":"170px"}},
- {"name":"priority","title":lang.priority,"style":{"width":"80px"}},
- {"name":"message","title":lang.message},
- ],
- "rows": $.ajax({
- dataType: 'json',
- url: '/api/v1/get/logs/dovecot',
- jsonp: false,
- error: function () {
- console.log('Cannot draw dovecot log table');
- },
- success: function (data) {
- return process_table_data(data, 'general_syslog');
- }
- }),
- "empty": lang.empty,
- "paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
- "filtering": {"enabled": true,"position": "left","connectors": false,"placeholder": lang.filter_table},
- "sorting": {"enabled": true},
- "on": {
- "ready.ft.table": function(e, ft){
- heading = ft.$el.parents('.tab-pane').find('.panel-heading')
- $(heading).children('.log-lines').text(function(){
- var ft_paging = ft.use(FooTable.Paging)
- return ft_paging.totalRows;
- })
- }
- }
- });
- }
function draw_domain_admins() {
ft_domainadmins = FooTable.init('#domainadminstable', {
"columns": [
@@ -278,108 +89,9 @@ jQuery(function($){
"sorting": {"enabled": true}
});
}
- function draw_rspamd_history() {
- ft_rspamd_history = FooTable.init('#rspamd_history', {
- "columns": [
- {"name":"unix_time","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleString();},"title":lang.time,"style":{"width":"170px"}},
- {"name": "ip","title": "IP address","breakpoints": "all","style": {"minWidth": 88}},
- {"name": "sender_mime","title": "From","breakpoints": "xs sm md","style": {"minWidth": 100}},
- {"name": "rcpt_mime","title": "To","breakpoints": "xs sm md","style": {"minWidth": 100}},
- {"name": "subject","title": "Subject","breakpoints": "all","style": {"word-break": "break-all","minWidth": 150}},
- {"name": "action","title": "Action","style": {"minwidth": 82}},
- {"name": "score","title": "Score","style": {"maxWidth": 110},},
- {"name": "symbols","title": "Symbols","breakpoints": "all",},
- {"name": "size","title": "Msg size","breakpoints": "all","style": {"minwidth": 50},"formatter": function(value){return humanFileSize(value);}},
- {"name": "scan_time","title": "Scan time","breakpoints": "all","style": {"maxWidth": 72},},
- {"name": "message-id","title": "ID","breakpoints": "all","style": {"minWidth": 130,"overflow": "hidden","textOverflow": "ellipsis","wordBreak": "break-all","whiteSpace": "normal"}},
- {"name": "user","title": "Authenticated user","breakpoints": "xs sm md","style": {"minWidth": 100}}
- ],
- "rows": $.ajax({
- dataType: 'json',
- url: '/api/v1/get/logs/rspamd-history',
- jsonp: false,
- error: function () {
- console.log('Cannot draw rspamd history table');
- },
- success: function (data) {
- return process_table_data(data, 'rspamd_history');
- }
- }),
- "empty": lang.empty,
- "paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
- "filtering": {"enabled": true,"position": "left","connectors": false,"placeholder": lang.filter_table},
- "sorting": {"enabled": true},
- "on": {
- "ready.ft.table": function(e, ft){
- heading = ft.$el.parents('.tab-pane').find('.panel-heading')
- $(heading).children('.log-lines').text(function(){
- var ft_paging = ft.use(FooTable.Paging)
- return ft_paging.totalRows;
- })
- }
- }
- });
- }
function process_table_data(data, table) {
- if (table == 'rspamd_history') {
- $.each(data, function (i, item) {
- item.rcpt_mime = item.rcpt_mime.join(",​");
- Object.keys(item.symbols).map(function(key) {
- var sym = item.symbols[key];
- if (sym.score <= 0) {
- sym.score_formatted = '(<span class="text-success"><b>' + sym.score + '</b></span>)'
- }
- else {
- sym.score_formatted = '(<span class="text-danger"><b>' + sym.score + '</b></span>)'
- }
- var str = '<strong>' + key + '</strong> ' + sym.score_formatted;
- if (sym.options) {
- str += ' [' + sym.options.join(",") + "]";
- }
- item.symbols[key].str = str;
- });
- item.symbols = Object.keys(item.symbols).
- map(function(key) {
- return item.symbols[key];
- }).sort(function(e1, e2) {
- return Math.abs(e1.score) < Math.abs(e2.score);
- }).map(function(e) {
- return e.str;
- }).join("<br>\n");
- var scan_time = item.time_real.toFixed(3) + ' / ' + item.time_virtual.toFixed(3);
- item.scan_time = {
- "options": {
- "sortValue": item.time_real
- },
- "value": scan_time
- };
- if (item.action === 'clean' || item.action === 'no action') {
- item.action = "<div class='label label-success'>" + item.action + "</div>";
- } else if (item.action === 'rewrite subject' || item.action === 'add header' || item.action === 'probable spam') {
- item.action = "<div class='label label-warning'>" + item.action + "</div>";
- } else if (item.action === 'spam' || item.action === 'reject') {
- item.action = "<div class='label label-danger'>" + item.action + "</div>";
- } else {
- item.action = "<div class='label label-info'>" + item.action + "</div>";
- }
- var score_content;
- if (item.score < item.required_score) {
- score_content = "[ <span class='text-success'>" + item.score.toFixed(2) + " / " + item.required_score + "</span> ]";
- } else {
- score_content = "[ <span class='text-danger'>" + item.score.toFixed(2) + " / " + item.required_score + "</span> ]";
- }
- item.score = {
- "options": {
- "sortValue": item.score
- },
- "value": score_content
- };
- if (item.user == null) {
- item.user = "none";
- }
- });
- } else if (table == 'relayhoststable') {
+ if (table == 'relayhoststable') {
$.each(data, function (i, item) {
item.action = '<div class="btn-group">' +
'<a href="#" data-toggle="modal" id="miau" data-target="#testRelayhostModal" data-relayhost-id="' + encodeURI(item.id) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-stats"></span> Test</a>' +
@@ -409,48 +121,13 @@ jQuery(function($){
'<a href="#" id="delete_selected" data-id="single-domain-admin" data-api-url="delete/domain-admin" data-item="' + encodeURI(item.username) + '" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> ' + lang.remove + '</a>' +
'</div>';
});
- } else if (table == 'autodiscover_log') {
- $.each(data, function (i, item) {
- item.ua = '<span style="font-size:small">' + item.ua + '</span>';
- if (item.service == "activesync") {
- item.service = '<span class="label label-info">ActiveSync</span>';
- }
- else if (item.service == "imap") {
- item.service = '<span class="label label-success">IMAP, SMTP, Cal-/CardDAV</span>';
- }
- else {
- item.service = '<span class="label label-danger">' + item.service + '</span>';
- }
- });
- } else if (table == 'general_syslog') {
- $.each(data, function (i, item) {
- item.message = escapeHtml(item.message);
- var danger_class = ["emerg", "alert", "crit", "err"];
- var warning_class = ["warning", "warn"];
- var info_class = ["notice", "info", "debug"];
- if (jQuery.inArray(item.priority, danger_class) !== -1) {
- item.priority = '<span class="label label-danger">' + item.priority + '</span>';
- }
- else if (jQuery.inArray(item.priority, warning_class) !== -1) {
- item.priority = '<span class="label label-warning">' + item.priority + '</span>';
- }
- else if (jQuery.inArray(item.priority, info_class) !== -1) {
- item.priority = '<span class="label label-info">' + item.priority + '</span>';
- }
- });
}
return data
};
// Initial table drawings
- draw_postfix_logs();
- draw_autodiscover_logs();
- draw_dovecot_logs();
- draw_sogo_logs();
- draw_fail2ban_logs();
draw_domain_admins();
draw_fwd_hosts();
draw_relayhosts();
- draw_rspamd_history();
// Relayhost
$('#testRelayhostModal').on('show.bs.modal', function (e) {
$('#test_relayhost_result').text("-");
@@ -485,31 +162,6 @@ jQuery(function($){
$('#priv_key_pre').text(decoded_key);
}
})
-
- $('.add_log_lines').on('click', function (e) {
- e.preventDefault();
- var log_table= $(this).data("table")
- var new_nrows = ($(this).data("nrows") - 1)
- var post_process = $(this).data("post-process")
- var log_url = $(this).data("log-url")
- if (log_table === undefined || new_nrows === undefined || post_process === undefined || log_url === undefined) {
- console.log("no data-table or data-nrows or log_url or data-post-process attr found");
- return;
- }
- if (ft = FooTable.get($('#' + log_table))) {
- var heading = ft.$el.parents('.tab-pane').find('.panel-heading')
- var ft_paging = ft.use(FooTable.Paging)
- var load_rows = ft_paging.totalRows + '-' + (ft_paging.totalRows + new_nrows)
- $.get('/api/v1/get/logs/' + log_url + '/' + load_rows).then(function(data){
- if (data.length === undefined) { mailcow_alert_box(lang.no_new_rows, "info"); return; }
- var rows = process_table_data(data, post_process);
- var rows_now = (ft_paging.totalRows + data.length);
- $(heading).children('.log-lines').text(rows_now)
- mailcow_alert_box(data.length + lang.additional_rows, "success");
- ft.rows.load(rows, true);
- });
- }
- })
// App links
function add_table_row(table_id) {
var row = $('<tr />');
diff --git a/data/web/js/api.js b/data/web/js/api.js
index 824e2d64..cc036d2f 100644
--- a/data/web/js/api.js
+++ b/data/web/js/api.js
@@ -102,6 +102,7 @@ $(document).ready(function() {
return false;
}
}
+ // alert(JSON.stringify(api_attr));
// If clicked element #edit_selected has data-item attribute, it is added to "items"
if (typeof $(this).data('item') !== 'undefined') {
var id = $(this).data('id');
@@ -126,7 +127,9 @@ $(document).ready(function() {
jsonp: false,
complete: function(data) {
var response = (data.responseText);
- response_obj = JSON.parse(response);
+ if (typeof response !== 'undefined' && response.length !== 0) {
+ response_obj = JSON.parse(response);
+ }
if (api_reload_window === true) {
window.location = window.location.href.split("#")[0];
}
@@ -141,6 +144,11 @@ $(document).ready(function() {
var id = $(this).data('id');
var api_url = $(this).data('api-url');
var api_attr = $(this).data('api-attr');
+ if (typeof $(this).data('api-reload-window') !== 'undefined') {
+ api_reload_window = $(this).data('api-reload-window');
+ } else {
+ api_reload_window = true;
+ }
// If clicked button is in a form with the same data-id as the button,
// we merge all input fields by {"name":"value"} into api-attr
if ($(this).closest("form").data('id') == id) {
@@ -188,10 +196,20 @@ $(document).ready(function() {
url: '/api/v1/' + api_url,
jsonp: false,
complete: function(data) {
- // var reponse = (JSON.parse(data.responseText));
- // console.log(reponse.type);
- // console.log(reponse.msg);
- window.location = window.location.href.split("#")[0];
+ var response = (data.responseText);
+ if (typeof response !== 'undefined' && response.length !== 0) {
+ response_obj = JSON.parse(response);
+ if (response_obj.type == 'success') {
+ $('form').formcache('clear');
+ }
+ else {
+ var add_modal = $('.modal.in').attr('id');
+ localStorage.setItem("add_modal", add_modal);
+ }
+ }
+ if (api_reload_window === true) {
+ window.location = window.location.href.split("#")[0];
+ }
}
});
});
diff --git a/data/web/js/debug.js b/data/web/js/debug.js
new file mode 100644
index 00000000..48ebd5e9
--- /dev/null
+++ b/data/web/js/debug.js
@@ -0,0 +1,503 @@
+jQuery(function($){
+ // http://stackoverflow.com/questions/24816/escaping-html-strings-with-jquery
+ var entityMap={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="};
+ function escapeHtml(n){return String(n).replace(/[&<>"'`=\/]/g,function(n){return entityMap[n]})}
+ function humanFileSize(i){if(Math.abs(i)<1024)return i+" B";var B=["KiB","MiB","GiB","TiB","PiB","EiB","ZiB","YiB"],e=-1;do{i/=1024,++e}while(Math.abs(i)>=1024&&e<B.length-1);return i.toFixed(1)+" "+B[e]}
+ $("#refresh_postfix_log").on('click', function(e) {
+ e.preventDefault();
+ draw_postfix_logs();
+ });
+ $("#refresh_autodiscover_log").on('click', function(e) {
+ e.preventDefault();
+ draw_autodiscover_logs();
+ });
+ $("#refresh_dovecot_log").on('click', function(e) {
+ e.preventDefault();
+ draw_dovecot_logs();
+ });
+ $("#refresh_sogo_log").on('click', function(e) {
+ e.preventDefault();
+ draw_sogo_logs();
+ });
+ $("#refresh_watchdog_log").on('click', function(e) {
+ e.preventDefault();
+ draw_watchdog_logs();
+ });
+ $("#refresh_api_log").on('click', function(e) {
+ e.preventDefault();
+ draw_api_logs();
+ });
+ $("#refresh_acme_log").on('click', function(e) {
+ e.preventDefault();
+ draw_acme_logs();
+ });
+ $("#refresh_fail2ban_log").on('click', function(e) {
+ e.preventDefault();
+ draw_fail2ban_logs();
+ });
+ $("#refresh_rspamd_history").on('click', function(e) {
+ e.preventDefault();
+ draw_rspamd_history();
+ });
+ function draw_autodiscover_logs() {
+ ft_autodiscover_logs = FooTable.init('#autodiscover_log', {
+ "columns": [
+ {"name":"time","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleString();},"title":lang.time,"style":{"width":"170px"}},
+ {"name":"ua","title":"User-Agent","style":{"min-width":"200px"}},
+ {"name":"user","title":"Username","style":{"min-width":"200px"}},
+ {"name":"service","title":"Service"},
+ ],
+ "rows": $.ajax({
+ dataType: 'json',
+ url: '/api/v1/get/logs/autodiscover/100',
+ jsonp: false,
+ error: function () {
+ console.log('Cannot draw autodiscover log table');
+ },
+ success: function (data) {
+ return process_table_data(data, 'autodiscover_log');
+ }
+ }),
+ "empty": lang.empty,
+ "paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
+ "filtering": {"enabled": true,"position": "left","placeholder": lang.filter_table},
+ "sorting": {"enabled": true},
+ "on": {"ready.ft.table": function(e, ft){
+ heading = ft.$el.parents('.tab-pane').find('.panel-heading')
+ $(heading).children('.log-lines').text(function(){
+ var ft_paging = ft.use(FooTable.Paging)
+ return ft_paging.totalRows;
+ })
+ }
+ }
+ });
+ }
+ function draw_postfix_logs() {
+ ft_postfix_logs = FooTable.init('#postfix_log', {
+ "columns": [
+ {"name":"time","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleString();},"title":lang.time,"style":{"width":"170px"}},
+ {"name":"priority","title":lang.priority,"style":{"width":"80px"}},
+ {"name":"message","title":lang.message},
+ ],
+ "rows": $.ajax({
+ dataType: 'json',
+ url: '/api/v1/get/logs/postfix',
+ jsonp: false,
+ error: function () {
+ console.log('Cannot draw postfix log table');
+ },
+ success: function (data) {
+ return process_table_data(data, 'general_syslog');
+ }
+ }),
+ "empty": lang.empty,
+ "paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
+ "filtering": {"enabled": true,"position": "left","placeholder": lang.filter_table},
+ "sorting": {"enabled": true},
+ "on": {
+ "ready.ft.table": function(e, ft){
+ heading = ft.$el.parents('.tab-pane').find('.panel-heading')
+ $(heading).children('.log-lines').text(function(){
+ var ft_paging = ft.use(FooTable.Paging)
+ return ft_paging.totalRows;
+ })
+ }
+ }
+ });
+ }
+ function draw_watchdog_logs() {
+ ft_watchdog_logs = FooTable.init('#watchdog_log', {
+ "columns": [
+ {"name":"time","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleString();},"title":lang.time,"style":{"width":"170px"}},
+ {"name":"service","title":"Service"},
+ {"name":"trend","title":"Trend"},
+ {"name":"message","title":lang.message},
+ ],
+ "rows": $.ajax({
+ dataType: 'json',
+ url: '/api/v1/get/logs/watchdog',
+ jsonp: false,
+ error: function () {
+ console.log('Cannot draw watchdog log table');
+ },
+ success: function (data) {
+ return process_table_data(data, 'watchdog');
+ }
+ }),
+ "empty": lang.empty,
+ "paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
+ "filtering": {"enabled": true,"position": "left","connectors": false,"placeholder": lang.filter_table},
+ "sorting": {"enabled": true},
+ "on": {
+ "ready.ft.table": function(e, ft){
+ heading = ft.$el.parents('.tab-pane').find('.panel-heading')
+ $(heading).children('.log-lines').text(function(){
+ var ft_paging = ft.use(FooTable.Paging)
+ return ft_paging.totalRows;
+ })
+ }
+ }
+ });
+ }
+ function draw_api_logs() {
+ ft_api_logs = FooTable.init('#api_log', {
+ "columns": [
+ {"name":"time","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleString();},"title":lang.time,"style":{"width":"170px"}},
+ {"name":"uri","title":"URI","style":{"width":"310px"}},
+ {"name":"method","title":"Method","style":{"width":"80px"}},
+ {"name":"remote","title":"IP","style":{"width":"80px"}},
+ {"name":"data","title":"Data","style":{"word-break":"break-all"}},
+ ],
+ "rows": $.ajax({
+ dataType: 'json',
+ url: '/api/v1/get/logs/api',
+ jsonp: false,
+ error: function () {
+ console.log('Cannot draw api log table');
+ },
+ success: function (data) {
+ return process_table_data(data, 'apilog');
+ }
+ }),
+ "empty": lang.empty,
+ "paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
+ "filtering": {"enabled": true,"position": "left","connectors": false,"placeholder": lang.filter_table},
+ "sorting": {"enabled": true},
+ "on": {
+ "ready.ft.table": function(e, ft){
+ heading = ft.$el.parents('.tab-pane').find('.panel-heading')
+ $(heading).children('.log-lines').text(function(){
+ var ft_paging = ft.use(FooTable.Paging)
+ return ft_paging.totalRows;
+ })
+ }
+ }
+ });
+ }
+ function draw_acme_logs() {
+ ft_acme_logs = FooTable.init('#acme_log', {
+ "columns": [
+ {"name":"time","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleString();},"title":lang.time,"style":{"width":"170px"}},
+ {"name":"message","title":lang.message},
+ ],
+ "rows": $.ajax({
+ dataType: 'json',
+ url: '/api/v1/get/logs/acme',
+ jsonp: false,
+ error: function () {
+ console.log('Cannot draw acme log table');
+ },
+ success: function (data) {
+ return process_table_data(data, 'general_syslog');
+ }
+ }),
+ "empty": lang.empty,
+ "paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
+ "filtering": {"enabled": true,"position": "left","connectors": false,"placeholder": lang.filter_table},
+ "sorting": {"enabled": true},
+ "on": {
+ "ready.ft.table": function(e, ft){
+ heading = ft.$el.parents('.tab-pane').find('.panel-heading')
+ $(heading).children('.log-lines').text(function(){
+ var ft_paging = ft.use(FooTable.Paging)
+ return ft_paging.totalRows;
+ })
+ }
+ }
+ });
+ }
+ function draw_fail2ban_logs() {
+ ft_fail2ban_logs = FooTable.init('#fail2ban_log', {
+ "columns": [
+ {"name":"time","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleString();},"title":lang.time,"style":{"width":"170px"}},
+ {"name":"priority","title":lang.priority,"style":{"width":"80px"}},
+ {"name":"message","title":lang.message},
+ ],
+ "rows": $.ajax({
+ dataType: 'json',
+ url: '/api/v1/get/logs/fail2ban',
+ jsonp: false,
+ error: function () {
+ console.log('Cannot draw fail2ban log table');
+ },
+ success: function (data) {
+ return process_table_data(data, 'general_syslog');
+ }
+ }),
+ "empty": lang.empty,
+ "paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
+ "filtering": {"enabled": true,"position": "left","connectors": false,"placeholder": lang.filter_table},
+ "sorting": {"enabled": true},
+ "on": {
+ "ready.ft.table": function(e, ft){
+ heading = ft.$el.parents('.tab-pane').find('.panel-heading')
+ $(heading).children('.log-lines').text(function(){
+ var ft_paging = ft.use(FooTable.Paging)
+ return ft_paging.totalRows;
+ })
+ }
+ }
+ });
+ }
+ function draw_sogo_logs() {
+ ft_sogo_logs = FooTable.init('#sogo_log', {
+ "columns": [
+ {"name":"time","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleString();},"title":lang.time,"style":{"width":"170px"}},
+ {"name":"priority","title":lang.priority,"style":{"width":"80px"}},
+ {"name":"message","title":lang.message},
+ ],
+ "rows": $.ajax({
+ dataType: 'json',
+ url: '/api/v1/get/logs/sogo',
+ jsonp: false,
+ error: function () {
+ console.log('Cannot draw sogo log table');
+ },
+ success: function (data) {
+ return process_table_data(data, 'general_syslog');
+ }
+ }),
+ "empty": lang.empty,
+ "paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
+ "filtering": {"enabled": true,"position": "left","connectors": false,"placeholder": lang.filter_table},
+ "sorting": {"enabled": true},
+ "on": {
+ "ready.ft.table": function(e, ft){
+ heading = ft.$el.parents('.tab-pane').find('.panel-heading')
+ $(heading).children('.log-lines').text(function(){
+ var ft_paging = ft.use(FooTable.Paging)
+ return ft_paging.totalRows;
+ })
+ }
+ }
+ });
+ }
+ function draw_dovecot_logs() {
+ ft_dovecot_logs = FooTable.init('#dovecot_log', {
+ "columns": [
+ {"name":"time","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleString();},"title":lang.time,"style":{"width":"170px"}},
+ {"name":"priority","title":lang.priority,"style":{"width":"80px"}},
+ {"name":"message","title":lang.message},
+ ],
+ "rows": $.ajax({
+ dataType: 'json',
+ url: '/api/v1/get/logs/dovecot',
+ jsonp: false,
+ error: function () {
+ console.log('Cannot draw dovecot log table');
+ },
+ success: function (data) {
+ return process_table_data(data, 'general_syslog');
+ }
+ }),
+ "empty": lang.empty,
+ "paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
+ "filtering": {"enabled": true,"position": "left","connectors": false,"placeholder": lang.filter_table},
+ "sorting": {"enabled": true},
+ "on": {
+ "ready.ft.table": function(e, ft){
+ heading = ft.$el.parents('.tab-pane').find('.panel-heading')
+ $(heading).children('.log-lines').text(function(){
+ var ft_paging = ft.use(FooTable.Paging)
+ return ft_paging.totalRows;
+ })
+ }
+ }
+ });
+ }
+ function draw_rspamd_history() {
+ ft_rspamd_history = FooTable.init('#rspamd_history', {
+ "columns": [
+ {"name":"unix_time","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleString();},"title":lang.time,"style":{"width":"170px"}},
+ {"name": "ip","title": "IP address","breakpoints": "all","style": {"minWidth": 88}},
+ {"name": "sender_mime","title": "From","breakpoints": "xs sm md","style": {"minWidth": 100}},
+ {"name": "rcpt_mime","title": "To","breakpoints": "xs sm md","style": {"minWidth": 100}},
+ {"name": "subject","title": "Subject","breakpoints": "all","style": {"word-break": "break-all","minWidth": 150}},
+ {"name": "action","title": "Action","style": {"minwidth": 82}},
+ {"name": "score","title": "Score","style": {"maxWidth": 110},},
+ {"name": "symbols","title": "Symbols","breakpoints": "all",},
+ {"name": "size","title": "Msg size","breakpoints": "all","style": {"minwidth": 50},"formatter": function(value){return humanFileSize(value);}},
+ {"name": "scan_time","title": "Scan time","breakpoints": "all","style": {"maxWidth": 72},},
+ {"name": "message-id","title": "ID","breakpoints": "all","style": {"minWidth": 130,"overflow": "hidden","textOverflow": "ellipsis","wordBreak": "break-all","whiteSpace": "normal"}},
+ {"name": "user","title": "Authenticated user","breakpoints": "xs sm md","style": {"minWidth": 100}}
+ ],
+ "rows": $.ajax({
+ dataType: 'json',
+ url: '/api/v1/get/logs/rspamd-history',
+ jsonp: false,
+ error: function () {
+ console.log('Cannot draw rspamd history table');
+ },
+ success: function (data) {
+ return process_table_data(data, 'rspamd_history');
+ }
+ }),
+ "empty": lang.empty,
+ "paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
+ "filtering": {"enabled": true,"position": "left","connectors": false,"placeholder": lang.filter_table},
+ "sorting": {"enabled": true},
+ "on": {
+ "ready.ft.table": function(e, ft){
+ heading = ft.$el.parents('.tab-pane').find('.panel-heading')
+ $(heading).children('.log-lines').text(function(){
+ var ft_paging = ft.use(FooTable.Paging)
+ return ft_paging.totalRows;
+ })
+ }
+ }
+ });
+ }
+
+ function process_table_data(data, table) {
+ if (table == 'rspamd_history') {
+ $.each(data, function (i, item) {
+ item.rcpt_mime = item.rcpt_mime.join(",​");
+ Object.keys(item.symbols).map(function(key) {
+ var sym = item.symbols[key];
+ if (sym.score <= 0) {
+ sym.score_formatted = '(<span class="text-success"><b>' + sym.score + '</b></span>)'
+ }
+ else {
+ sym.score_formatted = '(<span class="text-danger"><b>' + sym.score + '</b></span>)'
+ }
+ var str = '<strong>' + key + '</strong> ' + sym.score_formatted;
+ if (sym.options) {
+ str += ' [' + sym.options.join(",") + "]";
+ }
+ item.symbols[key].str = str;
+ });
+ item.symbols = Object.keys(item.symbols).
+ map(function(key) {
+ return item.symbols[key];
+ }).sort(function(e1, e2) {
+ return Math.abs(e1.score) < Math.abs(e2.score);
+ }).map(function(e) {
+ return e.str;
+ }).join("<br>\n");
+ var scan_time = item.time_real.toFixed(3) + ' / ' + item.time_virtual.toFixed(3);
+ item.scan_time = {
+ "options": {
+ "sortValue": item.time_real
+ },
+ "value": scan_time
+ };
+ if (item.action === 'clean' || item.action === 'no action') {
+ item.action = "<div class='label label-success'>" + item.action + "</div>";
+ } else if (item.action === 'rewrite subject' || item.action === 'add header' || item.action === 'probable spam') {
+ item.action = "<div class='label label-warning'>" + item.action + "</div>";
+ } else if (item.action === 'spam' || item.action === 'reject') {
+ item.action = "<div class='label label-danger'>" + item.action + "</div>";
+ } else {
+ item.action = "<div class='label label-info'>" + item.action + "</div>";
+ }
+ var score_content;
+ if (item.score < item.required_score) {
+ score_content = "[ <span class='text-success'>" + item.score.toFixed(2) + " / " + item.required_score + "</span> ]";
+ } else {
+ score_content = "[ <span class='text-danger'>" + item.score.toFixed(2) + " / " + item.required_score + "</span> ]";
+ }
+ item.score = {
+ "options": {
+ "sortValue": item.score
+ },
+ "value": score_content
+ };
+ if (item.user == null) {
+ item.user = "none";
+ }
+ });
+ } else if (table == 'autodiscover_log') {
+ $.each(data, function (i, item) {
+ item.ua = '<span style="font-size:small">' + item.ua + '</span>';
+ if (item.service == "activesync") {
+ item.service = '<span class="label label-info">ActiveSync</span>';
+ }
+ else if (item.service == "imap") {
+ item.service = '<span class="label label-success">IMAP, SMTP, Cal-/CardDAV</span>';
+ }
+ else {
+ item.service = '<span class="label label-danger">' + item.service + '</span>';
+ }
+ });
+ } else if (table == 'watchdog') {
+ $.each(data, function (i, item) {
+ if (item.message == null) {
+ item.message = 'Health level: ' + item.lvl + '% (' + item.hpnow + '/' + item.hptotal + ')';
+ if (item.hpdiff < 0) {
+ item.trend = '<span class="label label-danger"><span class="glyphicon glyphicon-arrow-down"></span> ' + item.hpdiff + '</span>';
+ }
+ else if (item.hpdiff == 0) {
+ item.trend = '<span class="label label-info"><span class="glyphicon glyphicon-arrow-right"></span> ' + item.hpdiff + '</span>';
+ }
+ else {
+ item.trend = '<span class="label label-success"><span class="glyphicon glyphicon-arrow-up"></span> ' + item.hpdiff + '</span>';
+ }
+ }
+ else {
+ item.trend = '';
+ item.service = '';
+ }
+ });
+ } else if (table == 'general_syslog') {
+ $.each(data, function (i, item) {
+ if (item === null) { return true; }
+ item.message = escapeHtml(item.message);
+ var danger_class = ["emerg", "alert", "crit", "err"];
+ var warning_class = ["warning", "warn"];
+ var info_class = ["notice", "info", "debug"];
+ if (jQuery.inArray(item.priority, danger_class) !== -1) {
+ item.priority = '<span class="label label-danger">' + item.priority + '</span>';
+ } else if (jQuery.inArray(item.priority, warning_class) !== -1) {
+ item.priority = '<span class="label label-warning">' + item.priority + '</span>';
+ } else if (jQuery.inArray(item.priority, info_class) !== -1) {
+ item.priority = '<span class="label label-info">' + item.priority + '</span>';
+ }
+ });
+ } else if (table == 'apilog') {
+ $.each(data, function (i, item) {
+ if (item === null) { return true; }
+ if (item.method == 'GET') {
+ item.method = '<span class="label label-success">' + item.method + '</span>';
+ } else if (item.method == 'POST') {
+ item.method = '<span class="label label-warning">' + item.method + '</span>';
+ }
+ });
+ }
+ return data
+ };
+ $('.add_log_lines').on('click', function (e) {
+ e.preventDefault();
+ var log_table= $(this).data("table")
+ var new_nrows = ($(this).data("nrows") - 1)
+ var post_process = $(this).data("post-process")
+ var log_url = $(this).data("log-url")
+ if (log_table === undefined || new_nrows === undefined || post_process === undefined || log_url === undefined) {
+ console.log("no data-table or data-nrows or log_url or data-post-process attr found");
+ return;
+ }
+ if (ft = FooTable.get($('#' + log_table))) {
+ var heading = ft.$el.parents('.tab-pane').find('.panel-heading')
+ var ft_paging = ft.use(FooTable.Paging)
+ var load_rows = ft_paging.totalRows + '-' + (ft_paging.totalRows + new_nrows)
+ $.get('/api/v1/get/logs/' + log_url + '/' + load_rows).then(function(data){
+ if (data.length === undefined) { mailcow_alert_box(lang.no_new_rows, "info"); return; }
+ var rows = process_table_data(data, post_process);
+ var rows_now = (ft_paging.totalRows + data.length);
+ $(heading).children('.log-lines').text(rows_now)
+ mailcow_alert_box(data.length + lang.additional_rows, "success");
+ ft.rows.load(rows, true);
+ });
+ }
+ })
+ // Initial table drawings
+ draw_postfix_logs();
+ draw_autodiscover_logs();
+ draw_dovecot_logs();
+ draw_sogo_logs();
+ draw_watchdog_logs();
+ draw_acme_logs();
+ draw_api_logs();
+ draw_fail2ban_logs();
+ draw_rspamd_history();
+
+});
\ No newline at end of file
diff --git a/data/web/js/formcache.min.js b/data/web/js/formcache.min.js
new file mode 100644
index 00000000..10a02884
--- /dev/null
+++ b/data/web/js/formcache.min.js
@@ -0,0 +1,10 @@
+/*!
+ * Form Cache v@VERSION
+ * https://github.com/fengyuanchen/formcache
+ *
+ * Copyright 2014 Fengyuan Chen
+ * Released under the MIT license
+ *
+ * Date: @DATE
+ */
+!function(t){"function"==typeof define&&define.amd?define("formcache",["jquery"],t):t(jQuery)}(function(t){"use strict";var e=t(window),i=window.sessionStorage,s=window.localStorage,n="undefined",o=".formcache",a=/[\.\*\+\^\$\:\!\[\]#>~]+/g,c="change"+o,h="beforeunload"+o,r=function(t){return"checkbox"===t.type||"radio"===t.type},f=function(t){return parseInt(t,10)},u=function(e,i){this.form=e,this.$form=t(e),this.defaults=t.extend({},u.DEFAULTS,t.isPlainObject(i)?i:{}),this.init()};u.prototype={constructor:u,init:function(){var e=this.defaults;e.maxAge=Math.abs(e.maxAge||e.maxage),e.autoStore=Boolean(e.autoStore||e.autostore),this.initKey(),this.initStorage(),this.caches=this.storage.caches,this.index=0,this.activeIndex=0,this.storing=null,t.isArray(e.controls)||(e.controls=[]),this.$controls=this.$form.find(e.controls.join()).not(":file"),this.addListeners(),this.outputCache()},initKey:function(){var e=this.$form,i=this.defaults.key||e.data("key");i||(t("form").each(function(e){t(this).data("key",e)}),i=e.data("key")),this.key=location.pathname+"#formcache-"+i},initStorage:function(){var e,n=this.defaults,o=this.key,a=new Date,c={date:a,maxAge:n.maxAge,caches:[]};i&&(e=i.getItem(o)),!e&&s&&(e=s.getItem(o)),e="string"==typeof e?JSON.parse(e):null,t.isPlainObject(e)?"number"==typeof e.maxAge&&(a-new Date(e.date))/1e3>e.maxAge&&(e=c):e=c,this.storage=e},addListeners:function(){this.defaults.autoStore&&(this.$controls.on(c,t.proxy(this.change,this)),e.on(h,t.proxy(this.beforeunload,this)))},removeListeners:function(){this.defaults.autoStore&&(this.$controls.off(c,this.change),e.off(h,this.beforeunload))},change:function(e){var i,s,n=e.target,o=t(n),c=o.attr("name"),h=[];c&&(i=c.replace(a,""),this.$controls.filter('[name*="'+i+'"]').each(function(){r(n)?h.push(this.checked):(s=t(this).val(),s&&h.push(s))}),h.length&&(this.update(c,h),clearTimeout(this.storing),this.storing=setTimeout(t.proxy(this.store,this),1e3)))},beforeunload:function(){this.update(),this.store()},update:function(t,e){var i=this.activeIndex||this.index,s=this.getCache(i);"string"==typeof t?s[t]=e:s=this.serialize(),this.setCache(i,s)},serialize:function(){var e={};return this.$controls.each(function(){var i,s,n=t(this),o=n.attr("name");o&&(i=e[o],i=t.isArray(i)?i:[],r(this)?i.push(this.checked):(s=n.val(),s&&i.push(s)),i.length&&(e[o]=i))}),e},getCache:function(t){return this.caches[f(t)||this.index]||{}},getCaches:function(){return this.caches},setCache:function(e,i){typeof i===n&&(i=e,e=NaN),t.isPlainObject(i)&&(e=f(e)||this.index,this.caches[e]=i,this.store())},setCaches:function(e){t.isArray(e)&&(this.caches=e,this.store())},removeCache:function(t){this.caches.splice(f(t)||this.index,1),this.store()},removeCaches:function(){this.caches=[],this.store()},outputCache:function(e){var i=this.getCache(e);t.isPlainObject(i)&&(this.activeIndex=f(e)||this.index,i=t.extend(!0,{},i),this.$controls.each(function(){var e,s,n=t(this),o=n.attr("name");o&&(e=i[o],t.isArray(e)&&e.length&&(s=e.shift(),r(this)?this.checked=s:n.val(s)))}))},store:function(){var t=this.storage,e=this.key,n=this.defaults;t.date=new Date,t.maxAge=n.maxAge,t=JSON.stringify(t),n.session&&i&&i.setItem(e,t),n.local&&s&&s.setItem(e,t)},clear:function(){var t=this.key,e=this.defaults;e.session&&i&&i.removeItem(t),e.local&&s&&s.removeItem(t)},destroy:function(){this.removeListeners(),this.$form.removeData("formcache")}},u.DEFAULTS={key:"",local:!0,session:0,autoStore:!0,maxAge:void 0,controls:["select","textarea","input"]},u.setDefaults=function(e){t.extend(u.DEFAULTS,e)},u.other=t.fn.formcache,t.fn.formcache=function(e){var i,s=[].slice.call(arguments,1);return this.each(function(){var n,o=t(this),a=o.data("formcache");a||o.data("formcache",a=new u(this,e)),"string"==typeof e&&t.isFunction(n=a[e])&&(i=n.apply(a,s))}),typeof i!==n?i:this},t.fn.formcache.Constructor=u,t.fn.formcache.setDefaults=u.setDefaults,t.fn.formcache.noConflict=function(){return t.fn.formcache=u.other,this},t(function(){t('form[data-toggle="formcache"]').formcache()})});
\ No newline at end of file
diff --git a/data/web/js/mailbox.js b/data/web/js/mailbox.js
index 9e3c6868..b30ceb80 100644
--- a/data/web/js/mailbox.js
+++ b/data/web/js/mailbox.js
@@ -319,9 +319,9 @@ jQuery(function($){
"columns": [
{"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
{"sorted": true,"name":"id","title":"ID","style":{"maxWidth":"60px","width":"60px","text-align":"center"}},
- {"name":"type","title":"Type"},
- {"name":"local_dest","title":"Local destination"},
- {"name":"bcc_dest","title":"BCC destination/s"},
+ {"name":"type","title":lang.bcc_type},
+ {"name":"local_dest","title":lang.bcc_local_dest},
+ {"name":"bcc_dest","title":lang.bcc_destinations},
{"name":"domain","title":lang.domain,"breakpoints":"xs sm"},
{"name":"active","filterable": false,"style":{"maxWidth":"80px","width":"80px"},"title":lang.active},
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"180px","width":"180px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
diff --git a/data/web/js/quarantaine.js b/data/web/js/quarantaine.js
new file mode 100644
index 00000000..ba9e3bb3
--- /dev/null
+++ b/data/web/js/quarantaine.js
@@ -0,0 +1,82 @@
+// Base64 functions
+var Base64={_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(r){var t,e,o,a,h,n,c,d="",C=0;for(r=Base64._utf8_encode(r);C<r.length;)a=(t=r.charCodeAt(C++))>>2,h=(3&t)<<4|(e=r.charCodeAt(C++))>>4,n=(15&e)<<2|(o=r.charCodeAt(C++))>>6,c=63&o,isNaN(e)?n=c=64:isNaN(o)&&(c=64),d=d+this._keyStr.charAt(a)+this._keyStr.charAt(h)+this._keyStr.charAt(n)+this._keyStr.charAt(c);return d},decode:function(r){var t,e,o,a,h,n,c="",d=0;for(r=r.replace(/[^A-Za-z0-9\+\/\=]/g,"");d<r.length;)t=this._keyStr.indexOf(r.charAt(d++))<<2|(a=this._keyStr.indexOf(r.charAt(d++)))>>4,e=(15&a)<<4|(h=this._keyStr.indexOf(r.charAt(d++)))>>2,o=(3&h)<<6|(n=this._keyStr.indexOf(r.charAt(d++))),c+=String.fromCharCode(t),64!=h&&(c+=String.fromCharCode(e)),64!=n&&(c+=String.fromCharCode(o));return c=Base64._utf8_decode(c)},_utf8_encode:function(r){r=r.replace(/\r\n/g,"\n");for(var t="",e=0;e<r.length;e++){var o=r.charCodeAt(e);o<128?t+=String.fromCharCode(o):o>127&&o<2048?(t+=String.fromCharCode(o>>6|192),t+=String.fromCharCode(63&o|128)):(t+=String.fromCharCode(o>>12|224),t+=String.fromCharCode(o>>6&63|128),t+=String.fromCharCode(63&o|128))}return t},_utf8_decode:function(r){for(var t="",e=0,o=c1=c2=0;e<r.length;)(o=r.charCodeAt(e))<128?(t+=String.fromCharCode(o),e++):o>191&&o<224?(c2=r.charCodeAt(e+1),t+=String.fromCharCode((31&o)<<6|63&c2),e+=2):(c2=r.charCodeAt(e+1),c3=r.charCodeAt(e+2),t+=String.fromCharCode((15&o)<<12|(63&c2)<<6|63&c3),e+=3);return t}};
+jQuery(function($){
+ // http://stackoverflow.com/questions/24816/escaping-html-strings-with-jquery
+ var entityMap={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="};
+ function escapeHtml(n){return String(n).replace(/[&<>"'`=\/]/g,function(n){return entityMap[n]})}
+ function humanFileSize(i){if(Math.abs(i)<1024)return i+" B";var B=["KiB","MiB","GiB","TiB","PiB","EiB","ZiB","YiB"],e=-1;do{i/=1024,++e}while(Math.abs(i)>=1024&&e<B.length-1);return i.toFixed(1)+" "+B[e]}
+
+ function draw_quarantaine_table() {
+ ft_quarantainetable = FooTable.init('#quarantainetable', {
+ "columns": [
+ {"name":"chkbox","title":"","style":{"maxWidth":"40px","width":"40px"},"filterable": false,"sortable": false,"type":"html"},
+ {"name":"id","type":"ID","filterable": false,"sorted": true,"direction":"DESC","title":"ID","style":{"width":"50px"}},
+ {"name":"qid","type":"text","title":lang.qid,"style":{"width":"125px"}},
+ {"name":"sender","title":lang.sender,"breakpoints":"xs sm"},
+ {"name":"rcpt","title":lang.rcpt, "type": "text"},
+ {"name":"created","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleString();},"title":lang.received,"style":{"width":"170px"}},
+ {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right"},"style":{"width":"205px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
+ ],
+ "rows": $.ajax({
+ dataType: 'json',
+ url: '/api/v1/get/quarantaine/all',
+ jsonp: false,
+ error: function () {
+ console.log('Cannot draw quarantaine table');
+ },
+ success: function (data) {
+ $.each(data, function (i, item) {
+ item.action = '<div class="btn-group">' +
+ '<a href="#" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-info show_qid_info"><span class="glyphicon glyphicon-modal-window"></span> ' + lang.show_item + '</a>' +
+ '<a href="#" id="delete_selected" data-id="del-single-qitem" data-api-url="delete/qitem" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> ' + lang.remove + '</a>' +
+ '</div>';
+ item.chkbox = '<input type="checkbox" data-id="qitems" name="multi_select" value="' + item.id + '" />';
+ });
+ }
+ }),
+ "empty": lang.empty,
+ "paging": {"enabled": true,"limit": 5,"size": pagination_size},
+ "sorting": {"enabled": true},
+ "on": {
+ "ready.ft.table": function(ev, ft){
+ $('.show_qid_info').on('click', function (e) {
+ e.preventDefault();
+ var qitem = $(this).data('item');
+ $('#qidDetailModal').modal('show');
+ $( "#qid_error" ).hide();
+ $.ajax({
+ url: '/inc/ajax/qitem_details.php',
+ data: { id: qitem },
+ dataType: 'json',
+ success: function(data){
+ if (typeof data.error !== 'undefined') {
+ $( "#qid_error" ).text(data.error);
+ $( "#qid_error" ).show();
+ }
+ $('#qid_detail_subj').text(escapeHtml(data.subject));
+ $('#qid_detail_text').text(escapeHtml(data.text_plain));
+ if (typeof data.attachments !== 'undefined') {
+ $( "#qid_detail_atts" ).text('');
+ $.each(data.attachments, function( index, value ) {
+ $( "#qid_detail_atts" ).append(
+ '<p><a href="/inc/ajax/qitem_details.php?id=' + qitem + '&att=' + index + '" target="_blank">' + value[0] + '</a> (' + value[1] + ')' +
+ ' - <small><a href="' + value[3] + '" target="_blank">' + lang.check_hash + '</a></small></p>'
+ );
+ });
+ }
+ else {
+ $( "#qid_detail_atts" ).text('-');
+ }
+ }
+ });
+ })
+ }
+ },
+ "filtering": {"enabled": true,"position": "left","connectors": false,"placeholder": lang.filter_table},
+ });
+ }
+
+ // Initial table drawings
+ draw_quarantaine_table();
+
+});
\ No newline at end of file
diff --git a/data/web/json_api.php b/data/web/json_api.php
index cf6d8416..3bcb2ac4 100644
--- a/data/web/json_api.php
+++ b/data/web/json_api.php
@@ -15,6 +15,41 @@ delete/alias => POST data:
header('Content-Type: application/json');
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/prerequisites.inc.php';
error_reporting(0);
+
+function api_log($postarray) {
+ global $redis;
+ $data_var = array();
+ foreach ($postarray as $data => &$value) {
+ if ($data == 'csrf_token') {
+ continue;
+ }
+ if ($value = json_decode($value, true)) {
+ unset($value["csrf_token"]);
+ $value = json_encode($value);
+ }
+ $data_var[] = $data . "='" . $value . "'";
+ }
+ try {
+ $log_line = array(
+ 'time' => time(),
+ 'uri' => $_SERVER['REQUEST_URI'],
+ 'method' => $_SERVER['REQUEST_METHOD'],
+ 'remote' => $_SERVER['REMOTE_ADDR'],
+ 'data' => implode(', ', $data_var)
+ );
+ $redis->lPush('API_LOG', json_encode($log_line));
+ }
+ catch (RedisException $e) {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => 'Redis: '.$e
+ );
+ return false;
+ }
+}
+
+api_log($_POST);
+
if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_username'])) {
if (isset($_GET['query'])) {
@@ -258,10 +293,10 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
));
}
break;
- case "bcc":
+ case "domain-policy":
if (isset($_POST['attr'])) {
$attr = (array)json_decode($_POST['attr'], true);
- if (bcc('add', $attr) === false) {
+ if (policy('add', 'domain', $attr) === false) {
if (isset($_SESSION['return'])) {
echo json_encode($_SESSION['return']);
}
@@ -291,10 +326,10 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
));
}
break;
- case "domain-policy":
+ case "mailbox-policy":
if (isset($_POST['attr'])) {
$attr = (array)json_decode($_POST['attr'], true);
- if (policy('add', 'domain', $attr) === false) {
+ if (policy('add', 'mailbox', $attr) === false) {
if (isset($_SESSION['return'])) {
echo json_encode($_SESSION['return']);
}
@@ -324,10 +359,10 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
));
}
break;
- case "mailbox-policy":
+ case "alias-domain":
if (isset($_POST['attr'])) {
$attr = (array)json_decode($_POST['attr'], true);
- if (policy('add', 'mailbox', $attr) === false) {
+ if (mailbox('add', 'alias_domain', $attr) === false) {
if (isset($_SESSION['return'])) {
echo json_encode($_SESSION['return']);
}
@@ -357,10 +392,10 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
));
}
break;
- case "alias-domain":
+ case "fwdhost":
if (isset($_POST['attr'])) {
$attr = (array)json_decode($_POST['attr'], true);
- if (mailbox('add', 'alias_domain', $attr) === false) {
+ if (fwdhost('add', $attr) === false) {
if (isset($_SESSION['return'])) {
echo json_encode($_SESSION['return']);
}
@@ -390,10 +425,10 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
));
}
break;
- case "fwdhost":
+ case "dkim":
if (isset($_POST['attr'])) {
$attr = (array)json_decode($_POST['attr'], true);
- if (fwdhost('add', $attr) === false) {
+ if (dkim('add', $attr) === false) {
if (isset($_SESSION['return'])) {
echo json_encode($_SESSION['return']);
}
@@ -423,10 +458,10 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
));
}
break;
- case "dkim":
+ case "dkim_import":
if (isset($_POST['attr'])) {
$attr = (array)json_decode($_POST['attr'], true);
- if (dkim('add', $attr) === false) {
+ if (dkim('import', $attr) === false) {
if (isset($_SESSION['return'])) {
echo json_encode($_SESSION['return']);
}
@@ -456,10 +491,10 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
));
}
break;
- case "dkim_import":
+ case "domain-admin":
if (isset($_POST['attr'])) {
$attr = (array)json_decode($_POST['attr'], true);
- if (dkim('import', $attr) === false) {
+ if (domain_admin('add', $attr) === false) {
if (isset($_SESSION['return'])) {
echo json_encode($_SESSION['return']);
}
@@ -489,10 +524,10 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
));
}
break;
- case "domain-admin":
+ case "syncjob":
if (isset($_POST['attr'])) {
$attr = (array)json_decode($_POST['attr'], true);
- if (domain_admin('add', $attr) === false) {
+ if (mailbox('add', 'syncjob', $attr) === false) {
if (isset($_SESSION['return'])) {
echo json_encode($_SESSION['return']);
}
@@ -522,10 +557,10 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
));
}
break;
- case "syncjob":
+ case "bcc":
if (isset($_POST['attr'])) {
$attr = (array)json_decode($_POST['attr'], true);
- if (mailbox('add', 'syncjob', $attr) === false) {
+ if (bcc('add', $attr) === false) {
if (isset($_SESSION['return'])) {
echo json_encode($_SESSION['return']);
}
@@ -752,6 +787,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
break;
}
break;
+
case "relayhost":
switch ($object) {
case "all":
@@ -870,6 +906,54 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
echo '{}';
}
break;
+ case "watchdog":
+ // 0 is first record, so empty is fine
+ if (isset($extra)) {
+ $extra = preg_replace('/[^\d\-]/i', '', $extra);
+ $logs = get_logs('watchdog-mailcow', $extra);
+ }
+ else {
+ $logs = get_logs('watchdog-mailcow');
+ }
+ if (isset($logs) && !empty($logs)) {
+ echo json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
+ }
+ else {
+ echo '{}';
+ }
+ break;
+ case "acme":
+ // 0 is first record, so empty is fine
+ if (isset($extra)) {
+ $extra = preg_replace('/[^\d\-]/i', '', $extra);
+ $logs = get_logs('acme-mailcow', $extra);
+ }
+ else {
+ $logs = get_logs('acme-mailcow');
+ }
+ if (isset($logs) && !empty($logs)) {
+ echo json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
+ }
+ else {
+ echo '{}';
+ }
+ break;
+ case "api":
+ // 0 is first record, so empty is fine
+ if (isset($extra)) {
+ $extra = preg_replace('/[^\d\-]/i', '', $extra);
+ $logs = get_logs('api-mailcow', $extra);
+ }
+ else {
+ $logs = get_logs('api-mailcow');
+ }
+ if (isset($logs) && !empty($logs)) {
+ echo json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
+ }
+ else {
+ echo '{}';
+ }
+ break;
case "rspamd-history":
// 0 is first record, so empty is fine
if (isset($extra)) {
@@ -1088,7 +1172,6 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
}
break;
-
default:
$data = bcc('details', $object);
if (!empty($data)) {
@@ -1230,6 +1313,29 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
break;
}
break;
+ case "quarantaine":
+ // "all" will not print details
+ switch ($object) {
+ case "all":
+ $data = quarantaine('get');
+ if (!isset($data) || empty($data)) {
+ echo '{}';
+ }
+ else {
+ echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
+ }
+ break;
+ default:
+ $data = quarantaine('details', $object);
+ if (!isset($data) || empty($data)) {
+ echo '{}';
+ }
+ else {
+ echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
+ }
+ break;
+ }
+ break;
case "alias-domain":
switch ($object) {
case "all":
@@ -1342,13 +1448,10 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
case "u2f-registration":
header('Content-Type: application/javascript');
if (($_SESSION["mailcow_cc_role"] == "admin" || $_SESSION["mailcow_cc_role"] == "domainadmin") && $_SESSION["mailcow_cc_username"] == $object) {
- list($req, $sigs) = $u2f->getRegisterData(get_u2f_registrations($object));
+ $data = $u2f->getRegisterData(get_u2f_registrations($object));
+ list($req, $sigs) = $data;
$_SESSION['regReq'] = json_encode($req);
- $_SESSION['regSigs'] = json_encode($sigs);
- echo 'var req = ' . json_encode($req) . ';';
- echo 'var registeredKeys = ' . json_encode($sigs) . ';';
- echo 'var appId = req.appId;';
- echo 'var registerRequests = [{version: req.version, challenge: req.challenge}];';
+ echo 'var req = ' . json_encode($req) . '; var sigs = ' . json_encode($sigs) . ';';
}
else {
return;
@@ -1357,19 +1460,9 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
case "u2f-authentication":
header('Content-Type: application/javascript');
if (isset($_SESSION['pending_mailcow_cc_username']) && $_SESSION['pending_mailcow_cc_username'] == $object) {
- $auth_data = $u2f->getAuthenticateData(get_u2f_registrations($object));
- $challenge = $auth_data[0]->challenge;
- $appId = $auth_data[0]->appId;
- foreach ($auth_data as $each) {
- $key = array(); // Empty array
- $key['version'] = $each->version;
- $key['keyHandle'] = $each->keyHandle;
- $registeredKey[] = $key;
- }
- $_SESSION['authReq'] = json_encode($auth_data);
- echo 'var appId = "' . $appId . '";';
- echo 'var challenge = ' . json_encode($challenge) . ';';
- echo 'var registeredKeys = ' . json_encode($registeredKey) . ';';
+ $reqs = json_encode($u2f->getAuthenticateData(get_u2f_registrations($object)));
+ $_SESSION['authReq'] = $reqs;
+ echo 'var req = ' . $reqs . ';';
}
else {
return;
@@ -1546,6 +1639,47 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
));
}
break;
+ case "qitem":
+ if (isset($_POST['items'])) {
+ $items = (array)json_decode($_POST['items'], true);
+ if (is_array($items)) {
+ if (quarantaine('delete', array('id' => $items)) === false) {
+ if (isset($_SESSION['return'])) {
+ echo json_encode($_SESSION['return']);
+ }
+ else {
+ echo json_encode(array(
+ 'type' => 'error',
+ 'msg' => 'Deletion of items/s failed'
+ ));
+ }
+ }
+ else {
+ if (isset($_SESSION['return'])) {
+ echo json_encode($_SESSION['return']);
+ }
+ else {
+ echo json_encode(array(
+ 'type' => 'success',
+ 'msg' => 'Task completed'
+ ));
+ }
+ }
+ }
+ else {
+ echo json_encode(array(
+ 'type' => 'error',
+ 'msg' => 'Cannot find id array in post data'
+ ));
+ }
+ }
+ else {
+ echo json_encode(array(
+ 'type' => 'error',
+ 'msg' => 'Cannot find items in post data'
+ ));
+ }
+ break;
case "bcc":
if (isset($_POST['items'])) {
$items = (array)json_decode($_POST['items'], true);
@@ -2042,6 +2176,50 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
break;
case "edit":
switch ($category) {
+ case "bcc":
+ if (isset($_POST['items']) && isset($_POST['attr'])) {
+ $items = (array)json_decode($_POST['items'], true);
+ $attr = (array)json_decode($_POST['attr'], true);
+ $postarray = array_merge(array('id' => $items), $attr);
+ if (is_array($postarray['id'])) {
+ if (bcc('edit', $postarray) === false) {
+ if (isset($_SESSION['return'])) {
+ echo json_encode($_SESSION['return']);
+ }
+ else {
+ echo json_encode(array(
+ 'type' => 'error',
+ 'msg' => 'Edit failed'
+ ));
+ }
+ exit();
+ }
+ else {
+ if (isset($_SESSION['return'])) {
+ echo json_encode($_SESSION['return']);
+ }
+ else {
+ echo json_encode(array(
+ 'type' => 'success',
+ 'msg' => 'Task completed'
+ ));
+ }
+ }
+ }
+ else {
+ echo json_encode(array(
+ 'type' => 'error',
+ 'msg' => 'Incomplete post data'
+ ));
+ }
+ }
+ else {
+ echo json_encode(array(
+ 'type' => 'error',
+ 'msg' => 'Incomplete post data'
+ ));
+ }
+ break;
case "alias":
if (isset($_POST['items']) && isset($_POST['attr'])) {
$items = (array)json_decode($_POST['items'], true);
@@ -2260,13 +2438,13 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
));
}
break;
- case "time_limited_alias":
+ case "qitem":
if (isset($_POST['items']) && isset($_POST['attr'])) {
$items = (array)json_decode($_POST['items'], true);
$attr = (array)json_decode($_POST['attr'], true);
- $postarray = array_merge(array('address' => $items), $attr);
- if (is_array($postarray['address'])) {
- if (mailbox('edit', 'time_limited_alias', $postarray) === false) {
+ $postarray = array_merge(array('id' => $items), $attr);
+ if (is_array($postarray['id'])) {
+ if (quarantaine('edit', $postarray) === false) {
if (isset($_SESSION['return'])) {
echo json_encode($_SESSION['return']);
}
@@ -2304,14 +2482,48 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
));
}
break;
- case "mailbox":
- // sender_acl:0 removes all entries
+ case "quarantaine":
+ // Edit settings, does not need IDs
+ if (isset($_POST['attr'])) {
+ $postarray = json_decode($_POST['attr'], true);
+ if (quarantaine('edit', $postarray) === false) {
+ if (isset($_SESSION['return'])) {
+ echo json_encode($_SESSION['return']);
+ }
+ else {
+ echo json_encode(array(
+ 'type' => 'error',
+ 'msg' => 'Edit failed'
+ ));
+ }
+ exit();
+ }
+ else {
+ if (isset($_SESSION['return'])) {
+ echo json_encode($_SESSION['return']);
+ }
+ else {
+ echo json_encode(array(
+ 'type' => 'success',
+ 'msg' => 'Task completed'
+ ));
+ }
+ }
+ }
+ else {
+ echo json_encode(array(
+ 'type' => 'error',
+ 'msg' => 'Incomplete post data'
+ ));
+ }
+ break;
+ case "time_limited_alias":
if (isset($_POST['items']) && isset($_POST['attr'])) {
$items = (array)json_decode($_POST['items'], true);
$attr = (array)json_decode($_POST['attr'], true);
- $postarray = array_merge(array('username' => $items), $attr);
- if (is_array($postarray['username'])) {
- if (mailbox('edit', 'mailbox', $postarray) === false) {
+ $postarray = array_merge(array('address' => $items), $attr);
+ if (is_array($postarray['address'])) {
+ if (mailbox('edit', 'time_limited_alias', $postarray) === false) {
if (isset($_SESSION['return'])) {
echo json_encode($_SESSION['return']);
}
@@ -2349,13 +2561,14 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
));
}
break;
- case "syncjob":
+ case "mailbox":
+ // sender_acl:0 removes all entries
if (isset($_POST['items']) && isset($_POST['attr'])) {
$items = (array)json_decode($_POST['items'], true);
$attr = (array)json_decode($_POST['attr'], true);
- $postarray = array_merge(array('id' => $items), $attr);
- if (is_array($postarray['id'])) {
- if (mailbox('edit', 'syncjob', $postarray) === false) {
+ $postarray = array_merge(array('username' => $items), $attr);
+ if (is_array($postarray['username'])) {
+ if (mailbox('edit', 'mailbox', $postarray) === false) {
if (isset($_SESSION['return'])) {
echo json_encode($_SESSION['return']);
}
@@ -2393,13 +2606,13 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
));
}
break;
- case "filter":
+ case "syncjob":
if (isset($_POST['items']) && isset($_POST['attr'])) {
$items = (array)json_decode($_POST['items'], true);
$attr = (array)json_decode($_POST['attr'], true);
$postarray = array_merge(array('id' => $items), $attr);
if (is_array($postarray['id'])) {
- if (mailbox('edit', 'filter', $postarray) === false) {
+ if (mailbox('edit', 'syncjob', $postarray) === false) {
if (isset($_SESSION['return'])) {
echo json_encode($_SESSION['return']);
}
@@ -2437,13 +2650,13 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
));
}
break;
- case "bcc":
+ case "filter":
if (isset($_POST['items']) && isset($_POST['attr'])) {
$items = (array)json_decode($_POST['items'], true);
$attr = (array)json_decode($_POST['attr'], true);
$postarray = array_merge(array('id' => $items), $attr);
if (is_array($postarray['id'])) {
- if (bcc('edit', $postarray) === false) {
+ if (mailbox('edit', 'filter', $postarray) === false) {
if (isset($_SESSION['return'])) {
echo json_encode($_SESSION['return']);
}
@@ -2480,7 +2693,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
'msg' => 'Incomplete post data'
));
}
- break;
+ break;
case "resource":
if (isset($_POST['items']) && isset($_POST['attr'])) {
$items = (array)json_decode($_POST['items'], true);
@@ -2531,7 +2744,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
$attr = (array)json_decode($_POST['attr'], true);
$postarray = array_merge(array('domain' => $items), $attr);
if (is_array($postarray['domain'])) {
- if (mailbox('edit', 'domain', $postarray) === false) {
+ if (mailbox('edit', 'domain', $postarray)) {
if (isset($_SESSION['return'])) {
echo json_encode($_SESSION['return']);
}
@@ -2824,6 +3037,41 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
));
}
break;
+ case "ui_texts":
+ // No items
+ if (isset($_POST['attr'])) {
+ $attr = (array)json_decode($_POST['attr'], true);
+ if (customize('edit', 'ui_texts', $attr) === false) {
+ if (isset($_SESSION['return'])) {
+ echo json_encode($_SESSION['return']);
+ }
+ else {
+ echo json_encode(array(
+ 'type' => 'error',
+ 'msg' => 'Edit failed'
+ ));
+ }
+ exit();
+ }
+ else {
+ if (isset($_SESSION['return'])) {
+ echo json_encode($_SESSION['return']);
+ }
+ else {
+ echo json_encode(array(
+ 'type' => 'success',
+ 'msg' => 'Task completed'
+ ));
+ }
+ }
+ }
+ else {
+ echo json_encode(array(
+ 'type' => 'error',
+ 'msg' => 'Incomplete post data'
+ ));
+ }
+ break;
case "self":
// No items, logged-in user, users and domain admins
if ($_SESSION['mailcow_cc_role'] == "domainadmin") {
diff --git a/data/web/lang/lang.de.php b/data/web/lang/lang.de.php
index 2dd5cd9e..700be0c7 100644
--- a/data/web/lang/lang.de.php
+++ b/data/web/lang/lang.de.php
@@ -5,9 +5,9 @@
$lang['footer']['loading'] = 'Einen Moment bitte...';
$lang['header']['restart_sogo'] = 'SOGo neustarten';
-$lang['footer']['restart_sogo'] = 'SOGo neustarten';
+$lang['footer']['restart_container'] = 'Container neustarten';
$lang['footer']['restart_now'] = 'Jetzt neustarten';
-$lang['footer']['restart_sogo_info'] = 'Einige Änderungen an Domains benötigen einen Neustart SOGos. Hier können Sie SOGo neustarten.<br><br><b>Wichtig:</b> Ein korrekter Neustart SOGos kann eine Weile in Anspruch nehmen, bitte warten Sie, bis der Prozess vollständig beendet wurde.';
+$lang['footer']['restart_container_info'] = '<b>Wichtig:</b> Ein korrekter Neustart eines Containers kann eine Weile in Anspruch nehmen, bitte warten Sie, bis der Prozess vollständig beendet wurde.';
$lang['footer']['confirm_delete'] = 'Löschen bestätigen';
$lang['footer']['delete_these_items'] = 'Sind Sie sicher, dass die Änderungen an Elementen mit folgender ID durchgeführt werden sollen?';
@@ -73,7 +73,7 @@ $lang['danger']['resource_invalid'] = 'Ressourcenname ist ungültig';
$lang['danger']['description_invalid'] = 'Ressourcenbeschreibung ist ungültig';
$lang['danger']['mailbox_invalid_suggest'] = 'Mailboxname ist ungültig, meinten Sie vielleicht %s?';
$lang['danger']['is_alias'] = '%s lautet bereits eine Alias-Adresse';
-$lang['danger']['is_alias_or_mailbox'] = "Eine Mailbox oder ein Alias mit der Adresse %s ist bereits vorhanden";
+$lang['danger']['is_alias_or_mailbox'] = "Eine Mailbox, ein Alias oder eine sich aus einer Alias-Domain ergebende Adresse mit dem Namen %s ist bereits vorhanden";
$lang['danger']['is_spam_alias'] = '%s lautet bereits eine Spam-Alias-Adresse';
$lang['danger']['quota_not_0_not_numeric'] = 'Speicherplatz muss numerisch und >= 0 sein';
$lang['danger']['domain_not_found'] = 'Domain %s nicht gefunden';
@@ -121,6 +121,8 @@ $lang['user']['did_you_know'] = '<b>Wussten Sie schon?</b> Sie können Ihre E-Ma
$lang['user']['spam_aliases'] = 'Temporäre E-Mail Aliasse';
$lang['user']['alias'] = 'Alias';
$lang['user']['aliases'] = 'Aliasse';
+$lang['user']['shared_aliases'] = 'Geteilte Alias-Adressen';
+$lang['user']['direct_aliases'] = 'Direkte Alias-Adressen';
$lang['user']['domain_aliases'] = 'Domain-Alias Adressen';
$lang['user']['is_catch_all'] = 'Ist Catch-All Adresse für Domain(s)';
$lang['user']['aliases_also_send_as'] = 'Darf außerdem versenden als Benutzer';
@@ -248,7 +250,7 @@ $lang['mailbox']['target_domain'] = 'Ziel-Domain';
$lang['mailbox']['target_address'] = 'Ziel-Adresse';
$lang['mailbox']['username'] = 'Benutzername';
$lang['mailbox']['fname'] = 'Name';
-$lang['mailbox']['filter_table'] = 'Tabelle filtern';
+$lang['mailbox']['filter_table'] = 'Filtern';
$lang['mailbox']['yes'] = '✔';
$lang['mailbox']['no'] = '✘';
$lang['mailbox']['quota'] = 'Speicherplatz';
@@ -533,6 +535,10 @@ $lang['admin']['host'] = 'Host';
$lang['admin']['source'] = 'Quelle';
$lang['admin']['add_forwarding_host'] = 'Weiterleitungs-Host hinzufügen';
$lang['admin']['add_relayhost'] = 'Relayhost hinzufügen';
+$lang['admin']['api_allow_from'] = "IP-Adressen für Zugriff";
+$lang['admin']['api_key'] = "API-Key";
+$lang['admin']['activate_api'] = "API aktivieren";
+$lang['admin']['regen_api_key'] = "API-Key regenerieren";
$lang['delete']['remove_forwardinghost_warning'] = '<b>Warnung:</b> Sie entfernen den Weiterleitungs-Host <b>%s</b>!';
$lang['success']['forwarding_host_removed'] = "Weiterleitungs-Host %s wurde entfernt";
$lang['success']['forwarding_host_added'] = "Weiterleitungs-Host %s wurde hinzugefügt";
@@ -559,4 +565,81 @@ $lang['admin']['reset_default'] = "Auf Standard zurücksetzen";
$lang['admin']['merged_vars_hint'] = 'Ausgegraute Zeilen wurden aus der Datei <code>vars.inc.(local.)php</code> gelesen und können nicht mittels UI verändert werden.';
$lang['mailbox']['waiting'] = "Wartend";
$lang['mailbox']['status'] = "Status";
-$lang['mailbox']['running'] = "In Ausführung";
\ No newline at end of file
+$lang['mailbox']['running'] = "In Ausführung";
+
+$lang['admin']['ui_texts'] = "UI Label und Texte";
+$lang['admin']['help_text'] = "Hilfstext unter Login-Maske (HTML zulässig)";
+$lang['admin']['main_name'] = '"mailcow UI" Name';
+$lang['admin']['apps_name'] = '"mailcow Apps" Name';
+
+$lang['admin']['customize'] = "UI Anpassung";
+$lang['admin']['change_logo'] = "Logo ändern";
+$lang['admin']['logo_info'] = "Die hochgeladene Grafik wird für die Navigationsleiste auf eine Höhe von 40px skaliert. Für die Darstellung auf der Login-Maske beträgt die skalierte Breite maximal 250px. Eine frei skalierbare Grafik (etwa SVG) wird empfohlen.";
+$lang['admin']['upload'] = "Hochladen";
+$lang['admin']['app_links'] = "App Links";
+$lang['admin']['app_name'] = "App Name";
+$lang['admin']['link'] = "Link";
+$lang['admin']['remove_row'] = "Entfernen";
+$lang['admin']['add_row'] = "Reihe hinzufügen";
+$lang['admin']['reset_default'] = "Zurücksetzen auf Standard";
+$lang['admin']['merged_vars_hint'] = 'Ausgegraute Reihen wurden aus der Datei <code>vars.inc.(local.)php</code> gelesen und können hier nicht verändert werden.';
+
+$lang['edit']['tls_policy'] = "TLS Policy ändern";
+$lang['edit']['spam_score'] = "Einen benutzerdefiniterten Spam-Score festlegen";
+$lang['edit']['spam_policy'] = "Hinzufügen und Entfernen von Einträgen in White- und Blacklists";
+$lang['edit']['delimiter_action'] = "Delimiter Aktion verändern";
+$lang['edit']['syncjobs'] = "Sync job hinzufügen oder anpassen";
+$lang['edit']['eas_reset'] = "ActiveSync Geräte-Cache zurücksetzen";
+$lang['edit']['spam_alias'] = "Anpassen temporärer Alias-Adressen";
+
+$lang['danger']['img_tmp_missing'] = "Grafik konnte nicht validiert werden: Erstellung temporärer Datei fehlgeschlagen";
+$lang['danger']['img_invalid'] = "Grafik konnte nicht validiert werden";
+$lang['danger']['invalid_mime_type'] = "Grafik konnte nicht validiert werden: Ungültiger MIME-Type";
+$lang['success']['upload_success'] = "Datei wurde erfolgreich hochgeladen";
+$lang['success']['app_links'] = "Änderungen an App Links wurden gespeichert";
+$lang['success']['ui_texts'] = "Änderungen an UI-Texten";
+$lang['success']['reset_main_logo'] = "Standardgrafik wurde wiederhergestellt";
+$lang['success']['items_released'] = "Ausgewählte Objekte wurden an Mailbox versendet";
+$lang['danger']['imagick_exception'] = "Fataler Bildverarbeitungsfehler";
+
+$lang['quarantaine']['quarantaine'] = "Quarantäne";
+$lang['quarantaine']['qinfo'] = "Das Quarantänesystem speichert abgelehnte Nachrichten in der Datenbank. Die Nachricht wird <em>nicht</em> angekommen. Der Absender erhält keinen Eindruck einer zugestellten E-Mail.<br />
+ E-Mails mit einer maximalen Größe von 10 MiB werden gespeichert.";
+$lang['quarantaine']['release'] = "Freigeben";
+$lang['quarantaine']['empty'] = 'Keine Einträge';
+$lang['quarantaine']['toggle_all'] = 'Alle auswählen';
+$lang['quarantaine']['quick_actions'] = 'Aktionen';
+$lang['quarantaine']['remove'] = 'Entfernen';
+$lang['quarantaine']['received'] = "Empfangen";
+$lang['quarantaine']['action'] = "Aktion";
+$lang['quarantaine']['rcpt'] = "Empfänger";
+$lang['quarantaine']['qid'] = "Rspamd QID";
+$lang['quarantaine']['sender'] = "Sender";
+$lang['quarantaine']['show_item'] = "Details";
+$lang['quarantaine']['check_hash'] = "Checksumme auf VirusTotal suchen";
+$lang['quarantaine']['qitem'] = "Quarantäneeintrag";
+$lang['quarantaine']['subj'] = "Betreff";
+$lang['quarantaine']['text_plain_content'] = "Inhalt (text/plain)";
+$lang['quarantaine']['atts'] = "Anhänge";
+
+$lang['header']['quarantaine'] = "Quarantäne";
+$lang['header']['debug'] = "Debugging";
+
+$lang['quarantaine']['release_body'] = "Die ursprüngliche Nachricht wurde als EML-Datei im Anhang hinterlegt.";
+$lang['danger']['release_send_failed'] = "Die Nachricht konnte nicht versendet werden: %s";
+$lang['quarantaine']['release_subject'] = "Potentiell schädliche Nachricht aus Quarantäne: %s";
+
+$lang['mailbox']['bcc_map_type'] = "BCC Typ";
+$lang['mailbox']['bcc_type'] = "BCC Typ";
+$lang['mailbox']['bcc_sender_map'] = "Senderabhängig";
+$lang['mailbox']['bcc_rcpt_map'] = "Empfängerabhängig";
+$lang['mailbox']['bcc_local_dest'] = "Lokales Ziel";
+$lang['mailbox']['bcc_destinations'] = "BCC Ziel(e)";
+
+$lang['mailbox']['bcc'] = "BCC";
+$lang['mailbox']['bcc_maps'] = "BCC-Maps";
+$lang['mailbox']['bcc_to_sender'] = "Map senderabhängig verwenden";
+$lang['mailbox']['bcc_to_rcpt'] = "Map empfängerabhängig verwenden";
+$lang['mailbox']['add_bcc_entry'] = "BCC-Eintrag hinzufügen";
+$lang['mailbox']['bcc_info'] = "Eine empfängerabhängige Map wird verwendet, wenn die BCC-Map Eintragung auf den Eingang einer E-Mail auf das lokale Ziel reagieren soll. Senderabhängige Maps verfahren nach dem gleichen Prinzip.<br/>
+ Das lokale Ziel wird bei Fehlzustellungen an ein BCC-Ziel nicht informiert.";
diff --git a/data/web/lang/lang.en.php b/data/web/lang/lang.en.php
index 6b404862..b68cf5ee 100644
--- a/data/web/lang/lang.en.php
+++ b/data/web/lang/lang.en.php
@@ -5,9 +5,9 @@
$lang['footer']['loading'] = "Please wait...";
$lang['header']['restart_sogo'] = 'Restart SOGo';
-$lang['footer']['restart_sogo'] = 'Restart SOGo';
+$lang['footer']['restart_container'] = 'Restart container';
$lang['footer']['restart_now'] = 'Restart now';
-$lang['footer']['restart_sogo_info'] = 'Some tasks, e.g. adding a domain, require you to restart SOGo to catch changes made in the mailcow UI.<br><br><b>Important:</b> A graceful restart may take a while to complete, please wait for it to finish.';
+$lang['footer']['restart_container_info'] = '<b>Important:</b> A graceful restart may take a while to complete, please wait for it to finish.';
$lang['footer']['confirm_delete'] = 'Confirm deletion';
$lang['footer']['delete_these_items'] = 'Please confirm your changes to the following object id:';
@@ -73,7 +73,7 @@ $lang['danger']['description_invalid'] = 'Resource description is invalid';
$lang['danger']['resource_invalid'] = "Resource name is invalid";
$lang['danger']['mailbox_invalid_suggest'] = 'Mailbox name is invalid, did you mean to type "%s"?';
$lang['danger']['is_alias'] = "%s is already known as an alias address";
-$lang['danger']['is_alias_or_mailbox'] = "%s is already known as an alias or a mailbox";
+$lang['danger']['is_alias_or_mailbox'] = "%s is already known as an alias, a mailbox or an alias address expanded from an alias domain.";
$lang['danger']['is_spam_alias'] = "%s is already known as a spam alias address";
$lang['danger']['quota_not_0_not_numeric'] = "Quota must be numeric and >= 0";
$lang['danger']['domain_not_found'] = 'Domain %s not found';
@@ -121,6 +121,8 @@ $lang['user']['did_you_know'] = '<b>Did you know?</b> You can use tags in your e
$lang['user']['spam_aliases'] = 'Temporary email aliases';
$lang['user']['alias'] = 'Alias';
$lang['user']['aliases'] = 'Aliases';
+$lang['user']['shared_aliases'] = 'Shared alias addresses';
+$lang['user']['direct_aliases'] = 'Direct alias addresses';
$lang['user']['domain_aliases'] = 'Domain alias addresses';
$lang['user']['is_catch_all'] = 'Catch-all for domain/s';
$lang['user']['aliases_also_send_as'] = 'Also allowed to send as user';
@@ -550,7 +552,15 @@ $lang['diagnostics']['dns_records_type'] = 'Type';
$lang['diagnostics']['dns_records_data'] = 'Correct Data';
$lang['diagnostics']['dns_records_status'] = 'Current State';
$lang['admin']['relay_from'] = '"From:" address';
-$lang['admin']['relay_run'] = "Run test";
+$lang['admin']['api_allow_from'] = "Allow API access from these IPs";
+$lang['admin']['api_key'] = "API key";
+$lang['admin']['activate_api'] = "Activate API";
+$lang['admin']['regen_api_key'] = "Regenerate API key";
+
+$lang['admin']['ui_texts'] = "UI labels and texts";
+$lang['admin']['help_text'] = "Override help text below login mask (HTML allowed)";
+$lang['admin']['main_name'] = '"mailcow UI" name';
+$lang['admin']['apps_name'] = '"mailcow Apps" name';
$lang['admin']['customize'] = "Customize";
$lang['admin']['change_logo'] = "Change logo";
@@ -574,3 +584,55 @@ $lang['edit']['delimiter_action'] = "Change delimiter action";
$lang['edit']['syncjobs'] = "Add or change sync jobs";
$lang['edit']['eas_reset'] = "Reset EAS devices";
$lang['edit']['spam_alias'] = "Create or change time limited alias addresses";
+
+$lang['danger']['img_tmp_missing'] = "Cannot validate image file: Temporary file not found";
+$lang['danger']['img_invalid'] = "Cannot validate image file";
+$lang['danger']['invalid_mime_type'] = "Invalid mime type";
+$lang['success']['upload_success'] = "File uploaded successfully";
+$lang['success']['app_links'] = "Saved changes to app links";
+$lang['success']['ui_texts'] = "Saved changes to UI texts";
+$lang['success']['reset_main_logo'] = "Reset to default logo";
+$lang['success']['items_released'] = "Selected items were released";
+$lang['danger']['imagick_exception'] = "Error: Imagick exception while reading image";
+
+$lang['quarantaine']['quarantaine'] = "Quarantaine";
+$lang['quarantaine']['qinfo'] = "The quarantaine system will save rejected mail to the database, while the sender will <em>not</em> be given the impression of a delivered mail.<br />
+ Only mails up to 10 MiB will be saved in the quarantaine.";
+$lang['quarantaine']['release'] = "Release";
+$lang['quarantaine']['empty'] = 'No results';
+$lang['quarantaine']['toggle_all'] = 'Toggle all';
+$lang['quarantaine']['quick_actions'] = 'Actions';
+$lang['quarantaine']['remove'] = 'Remove';
+$lang['quarantaine']['received'] = "Received";
+$lang['quarantaine']['action'] = "Action";
+$lang['quarantaine']['rcpt'] = "Recipient";
+$lang['quarantaine']['qid'] = "Rspamd QID";
+$lang['quarantaine']['sender'] = "Sender";
+$lang['quarantaine']['show_item'] = "Show item";
+$lang['quarantaine']['check_hash'] = "Search file hash @ VT";
+$lang['quarantaine']['qitem'] = "Quarantaine item";
+$lang['quarantaine']['subj'] = "Subject";
+$lang['quarantaine']['text_plain_content'] = "Content (text/plain)";
+$lang['quarantaine']['atts'] = "Attachments";
+
+$lang['header']['quarantaine'] = "Quarantaine";
+$lang['header']['debug'] = "Debug";
+
+$lang['quarantaine']['release_body'] = "We have attached your message as eml file to this message.";
+$lang['danger']['release_send_failed'] = "Message could not be released: %s";
+$lang['quarantaine']['release_subject'] = "Potentially damaging quarantaine item %s";
+
+$lang['mailbox']['bcc_map_type'] = "BCC type";
+$lang['mailbox']['bcc_type'] = "BCC type";
+$lang['mailbox']['bcc_sender_map'] = "Sender map";
+$lang['mailbox']['bcc_rcpt_map'] = "Recipient map";
+$lang['mailbox']['bcc_local_dest'] = "Local destination";
+$lang['mailbox']['bcc_destinations'] = "BCC destination/s";
+
+$lang['mailbox']['bcc'] = "BCC";
+$lang['mailbox']['bcc_maps'] = "BCC maps";
+$lang['mailbox']['bcc_to_sender'] = "Switch to sender map type";
+$lang['mailbox']['bcc_to_rcpt'] = "Switch to recipient map type";
+$lang['mailbox']['add_bcc_entry'] = "Add BCC map";
+$lang['mailbox']['bcc_info'] = "A recipient map type entry is used, when the local destination acts as recipient of a mail. Sender maps conform to the same principle.<br/>
+ The local destination will not be informed about a failed delivery.";
diff --git a/data/web/mailbox.php b/data/web/mailbox.php
index b4b8feec..19ec683e 100644
--- a/data/web/mailbox.php
+++ b/data/web/mailbox.php
@@ -21,7 +21,7 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
</li>
<li role="presentation"><a href="#tab-syncjobs" aria-controls="tab-syncjobs" role="tab" data-toggle="tab"><?=$lang['mailbox']['sync_jobs'];?></a></li>
<li role="presentation"><a href="#tab-filters" aria-controls="tab-filters" role="tab" data-toggle="tab"><?=$lang['mailbox']['filters'];?></a></li>
- <li role="presentation"><a href="#tab-bcc" aria-controls="tab-filters" role="tab" data-toggle="tab">BCC maps</a></li>
+ <li role="presentation"><a href="#tab-bcc" aria-controls="tab-filters" role="tab" data-toggle="tab"><?=$lang['mailbox']['bcc_maps'];?></a></li>
</ul>
<div class="row">
@@ -211,10 +211,9 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
<div role="tabpanel" class="tab-pane" id="tab-bcc">
<div class="panel panel-default">
<div class="panel-heading">
- <h3 class="panel-title">BCC maps</h3>
+ <h3 class="panel-title"><?=$lang['mailbox']['bcc_maps'];?></h3>
</div>
- <p style="margin:10px" class="help-block">A recipient map type entry is used, when the local destination acts as recipient of a mail. Sender maps conform to the same principle.
- The local destination will not be informed about a failed delivery.</p>
+ <p style="margin:10px" class="help-block"><?=$lang['mailbox']['bcc_info'];?></p>
<div class="table-responsive">
<table class="table table-striped" id="bcc_table"></table>
</div>
@@ -226,12 +225,12 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
<li><a id="edit_selected" data-id="bcc" data-api-url='edit/bcc' data-api-attr='{"active":"1"}' href="#"><?=$lang['mailbox']['activate'];?></a></li>
<li><a id="edit_selected" data-id="bcc" data-api-url='edit/bcc' data-api-attr='{"active":"0"}' href="#"><?=$lang['mailbox']['deactivate'];?></a></li>
<li role="separator" class="divider"></li>
- <li><a id="edit_selected" data-id="bcc" data-api-url='edit/bcc' data-api-attr='{"type":"sender"}' href="#">Switch to sender map type</a></li>
- <li><a id="edit_selected" data-id="bcc" data-api-url='edit/bcc' data-api-attr='{"type":"rcpt"}' href="#">Switch to recipient map type</a></li>
+ <li><a id="edit_selected" data-id="bcc" data-api-url='edit/bcc' data-api-attr='{"type":"sender"}' href="#"><?=$lang['mailbox']['bcc_to_sender'];?></a></li>
+ <li><a id="edit_selected" data-id="bcc" data-api-url='edit/bcc' data-api-attr='{"type":"rcpt"}' href="#"><?=$lang['mailbox']['bcc_to_rcpt'];?></a></li>
<li role="separator" class="divider"></li>
<li><a id="delete_selected" data-id="bcc" data-api-url='delete/bcc' href="#"><?=$lang['mailbox']['remove'];?></a></li>
</ul>
- <a class="btn btn-sm btn-success" href="#" data-toggle="modal" data-target="#addBCCModalAdmin"><span class="glyphicon glyphicon-plus"></span> Add BCC map</a>
+ <a class="btn btn-sm btn-success" href="#" data-toggle="modal" data-target="#addBCCModalAdmin"><span class="glyphicon glyphicon-plus"></span> <?=$lang['mailbox']['add_bcc_entry'];?></a>
</div>
</div>
</div>
diff --git a/data/web/modals/admin.php b/data/web/modals/admin.php
index bf17296c..3a387540 100644
--- a/data/web/modals/admin.php
+++ b/data/web/modals/admin.php
@@ -13,7 +13,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
<h3 class="modal-title"><?=$lang['admin']['add_domain_admin'];?></h3>
</div>
<div class="modal-body">
- <form class="form-horizontal" data-id="domain_admin" role="form" method="post">
+ <form class="form-horizontal" data-cached-form="true" data-id="domain_admin" role="form" method="post">
<div class="form-group">
<label class="control-label col-sm-2" for="username"><?=$lang['admin']['username'];?>:</label>
<div class="col-sm-10">
@@ -71,7 +71,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
<h3 class="modal-title"><span class="glyphicon glyphicon-stats"></span> Relayhost</h3>
</div>
<div class="modal-body">
- <form class="form-horizontal" id="test_relayhost_form" role="form" method="post">
+ <form class="form-horizontal" data-cached-form="true" id="test_relayhost_form" role="form" method="post">
<input type="hidden" class="form-control" name="relayhost_id" id="relayhost_id">
<div class="form-group">
<label class="control-label col-sm-2" for="mail_from"><?=$lang['admin']['relay_from'];?></label>
diff --git a/data/web/modals/debug.php b/data/web/modals/debug.php
new file mode 100644
index 00000000..e955a20b
--- /dev/null
+++ b/data/web/modals/debug.php
@@ -0,0 +1,6 @@
+<?php
+if (!isset($_SESSION['mailcow_cc_role'])) {
+ header('Location: /');
+ exit();
+}
+?>
diff --git a/data/web/modals/footer.php b/data/web/modals/footer.php
index 593ff197..e861ab4e 100644
--- a/data/web/modals/footer.php
+++ b/data/web/modals/footer.php
@@ -49,7 +49,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
<input type="password" class="form-control" name="confirm_password" id="confirm_password" placeholder="<?=$lang['user']['password_now'];?>" autocomplete="off" required>
</div>
<hr>
- <p><?=$lang['tfa']['waiting_usb_register'];?></p>
+ <p id="u2f_status_reg"></p>
<div class="alert alert-danger" style="display:none" id="u2f_return_code"></div>
<input type="hidden" name="token" id="u2f_register_data"/>
<input type="hidden" name="tfa_method" value="u2f">
@@ -146,7 +146,7 @@ if (isset($_SESSION['pending_tfa_method'])):
case "u2f":
?>
<form role="form" method="post" id="u2f_auth_form">
- <p><?=$lang['tfa']['waiting_usb_auth'];?></p>
+ <p id="u2f_status_auth"></p>
<div class="alert alert-danger" style="display:none" id="u2f_return_code"></div>
<input type="hidden" name="token" id="u2f_auth_data"/>
<input type="hidden" name="tfa_method" value="u2f">
@@ -183,19 +183,19 @@ if (isset($_SESSION['pending_tfa_method'])):
endif;
if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'admin'):
?>
-<div id="RestartSOGo" class="modal fade" role="dialog">
+<div id="RestartContainer" class="modal fade" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
- <h4 class="modal-title"><?= $lang['footer']['restart_sogo']; ?></h4>
+ <h4 class="modal-title"><?= $lang['footer']['restart_container']; ?> (<code id="containerName"></code>)</h4>
</div>
<div class="modal-body">
- <p><?= $lang['footer']['restart_sogo_info']; ?></p>
+ <p><?= $lang['footer']['restart_container_info']; ?></p>
<hr>
- <button class="btn btn-md btn-primary" id="triggerRestartSogo"><?= $lang['footer']['restart_now']; ?></button>
+ <button class="btn btn-md btn-primary" id="triggerRestartContainer"><?= $lang['footer']['restart_now']; ?></button>
<br><br>
- <div id="statusTriggerRestartSogo"></div>
+ <div id="statusTriggerRestartContainer"></div>
</div>
</div>
</div>
diff --git a/data/web/modals/mailbox.php b/data/web/modals/mailbox.php
index 113b3289..c60ddb45 100644
--- a/data/web/modals/mailbox.php
+++ b/data/web/modals/mailbox.php
@@ -13,7 +13,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
<h3 class="modal-title"><?=$lang['mailbox']['add_mailbox'];?></h3>
</div>
<div class="modal-body">
- <form class="form-horizontal" data-id="add_mailbox" role="form">
+ <form class="form-horizontal" data-cached-form="true" data-id="add_mailbox" role="form">
<div class="form-group">
<label class="control-label col-sm-2" for="local_part"><?=$lang['add']['mailbox_username'];?></label>
<div class="col-sm-10">
@@ -86,7 +86,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
<h3 class="modal-title"><?=$lang['mailbox']['add_domain'];?></h3>
</div>
<div class="modal-body">
- <form class="form-horizontal" data-id="add_domain" role="form">
+ <form class="form-horizontal" data-cached-form="true" data-id="add_domain" role="form">
<div class="form-group">
<label class="control-label col-sm-2" for="domain"><?=$lang['add']['domain'];?>:</label>
<div class="col-sm-10">
@@ -96,7 +96,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
<div class="form-group">
<label class="control-label col-sm-2" for="description"><?=$lang['add']['description'];?></label>
<div class="col-sm-10">
- <input type="text" class="form-control" name="description" id="description">
+ <input type="text" class="form-control" name="description" id="description" required>
</div>
</div>
<div class="form-group">
@@ -161,7 +161,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
<h3 class="modal-title"><?=$lang['mailbox']['add_resource'];?></h3>
</div>
<div class="modal-body">
- <form class="form-horizontal" role="form" data-id="add_resource">
+ <form class="form-horizontal" data-cached-form="true" role="form" data-id="add_resource">
<div class="form-group">
<label class="control-label col-sm-2" for="description"><?=$lang['add']['description'];?></label>
<div class="col-sm-10">
@@ -223,7 +223,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
<h3 class="modal-title"><?=$lang['mailbox']['add_alias'];?></h3>
</div>
<div class="modal-body">
- <form class="form-horizontal" role="form" data-id="add_alias">
+ <form class="form-horizontal" data-cached-form="true" role="form" data-id="add_alias">
<input type="hidden" value="0" name="active">
<div class="form-group">
<label class="control-label col-sm-2" for="address"><?=$lang['add']['alias_address'];?></label>
@@ -268,7 +268,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
<h3 class="modal-title"><?=$lang['mailbox']['add_domain_alias'];?></h3>
</div>
<div class="modal-body">
- <form class="form-horizontal" role="form" data-id="add_alias_domain">
+ <form class="form-horizontal" data-cached-form="true" role="form" data-id="add_alias_domain">
<input type="hidden" value="0" name="active">
<div class="form-group">
<label class="control-label col-sm-2" for="alias_domain"><?=$lang['add']['alias_domain'];?></label>
@@ -316,7 +316,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
</div>
<div class="modal-body">
<p class="help-block"><?=$lang['add']['syncjob_hint'];?></p>
- <form class="form-horizontal" role="form" data-id="add_syncjob">
+ <form class="form-horizontal" data-cached-form="true" role="form" data-id="add_syncjob">
<div class="form-group">
<label class="control-label col-sm-2" for="username"><?=$lang['add']['username'];?>:</label>
<div class="col-sm-10">
@@ -417,13 +417,6 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
</div>
</div>
</div>
- <div class="form-group">
- <div class="col-sm-offset-2 col-sm-10">
- <div class="checkbox">
- <label><input type="checkbox" value="1" name="delete2"> <?=$lang['add']['delete2'];?></label>
- </div>
- </div>
- </div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
@@ -450,7 +443,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
<h3 class="modal-title">Filter</h3>
</div>
<div class="modal-body">
- <form class="form-horizontal" role="form" data-id="add_filter">
+ <form class="form-horizontal" data-cached-form="true" role="form" data-id="add_filter">
<div class="form-group">
<label class="control-label col-sm-2" for="username"><?=$lang['add']['username'];?>:</label>
<div class="col-sm-10">
@@ -515,12 +508,12 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
- <h3 class="modal-title">BCC map</h3>
+ <h3 class="modal-title"><?=$lang['mailbox']['bcc_maps'];?></h3>
</div>
<div class="modal-body">
- <form class="form-horizontal" role="form" data-id="add_bcc">
+ <form class="form-horizontal" data-cached-form="true" role="form" data-id="add_bcc">
<div class="form-group">
- <label class="control-label col-sm-2" for="local_dest">Local destination:</label>
+ <label class="control-label col-sm-2" for="local_dest"><?=$lang['mailbox']['bcc_local_dest'];?>:</label>
<div class="col-sm-10">
<select id="addSelectLocalDest" name="local_dest" id="local_dest" required>
<?php
@@ -549,16 +542,16 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
</div>
</div>
<div class="form-group">
- <label class="control-label col-sm-2" for="type">BCC map type:</label>
+ <label class="control-label col-sm-2" for="type"><?=$lang['mailbox']['bcc_map_type'];?>:</label>
<div class="col-sm-10">
<select id="addFBCCType" name="type" id="type" required>
- <option value="sender">Sender map</option>
- <option value="rcpt">Recipient map</option>
+ <option value="sender"><?=$lang['mailbox']['bcc_sender_map'];?></option>
+ <option value="rcpt"><?=$lang['mailbox']['bcc_rcpt_map'];?></option>
</select>
</div>
</div>
<div class="form-group">
- <label class="control-label col-sm-2" for="bcc_dest">BCC destination/s:</label>
+ <label class="control-label col-sm-2" for="bcc_dest"><?=$lang['mailbox']['bcc_destinations'];?>:</label>
<div class="col-sm-10">
<textarea autocorrect="off" spellcheck="false" autocapitalize="none" class="form-control" rows="20" id="bcc_dest" name="bcc_dest" required></textarea>
</div>
diff --git a/data/web/modals/quarantaine.php b/data/web/modals/quarantaine.php
new file mode 100644
index 00000000..7d8a5152
--- /dev/null
+++ b/data/web/modals/quarantaine.php
@@ -0,0 +1,32 @@
+<?php
+if (!isset($_SESSION['mailcow_cc_role'])) {
+ header('Location: /');
+ exit();
+}
+?>
+<div class="modal fade" id="qidDetailModal" tabindex="-1" role="dialog" aria-hidden="true">
+ <div class="modal-dialog modal-lg">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
+ <h3 class="modal-title"><span class="glyphicon glyphicon-info"></span> <?=$lang['quarantaine']['qitem'];?></h3>
+ </div>
+ <div class="modal-body">
+ <div id="qid_error" style="display:none" class="alert alert-danger"></div>
+ <div class="form-group">
+ <label for="qid_detail_subj"><h4><?=$lang['quarantaine']['subj'];?>:</h4></label>
+ <p id="qid_detail_subj"></p>
+ </div>
+ <div class="form-group">
+ <label for="qid_detail_text"><h4><?=$lang['quarantaine']['text_plain_content'];?>:</h4></label>
+ <pre id="qid_detail_text"></pre>
+ </div>
+ <div class="form-group">
+ <label for="qid_detail_atts"><h4><?=$lang['quarantaine']['atts'];?>:</h4></label>
+ <div id="qid_detail_atts">-</div>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+
diff --git a/data/web/modals/user.php b/data/web/modals/user.php
index a7cc3995..50a6922c 100644
--- a/data/web/modals/user.php
+++ b/data/web/modals/user.php
@@ -14,7 +14,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
</div>
<div class="modal-body">
<p><?=$lang['add']['syncjob_hint'];?></p>
- <form class="form-horizontal" role="form" data-id="add_syncjob">
+ <form class="form-horizontal" data-cached-form="true" role="form" data-id="add_syncjob">
<div class="form-group">
<label class="control-label col-sm-2" for="host1"><?=$lang['add']['hostname'];?></label>
<div class="col-sm-10">
@@ -130,7 +130,7 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-body">
- <form class="form-horizontal" data-id="pwchange" role="form" method="post" autocomplete="off">
+ <form class="form-horizontal" data-cached-form="true" data-id="pwchange" role="form" method="post" autocomplete="off">
<div class="form-group">
<label class="control-label col-sm-3" for="user_new_pass"><?=$lang['user']['new_password'];?></label>
<div class="col-sm-5">
diff --git a/data/web/quarantaine.php b/data/web/quarantaine.php
new file mode 100644
index 00000000..2d436d8d
--- /dev/null
+++ b/data/web/quarantaine.php
@@ -0,0 +1,56 @@
+<?php
+require_once "inc/prerequisites.inc.php";
+
+if (isset($_SESSION['mailcow_cc_role'])) {
+require_once "inc/header.inc.php";
+$_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
+
+?>
+<div class="container">
+ <div class="row">
+ <div class="col-md-12">
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <h3 class="panel-title"><?=$lang['quarantaine']['quarantaine'];?></h3>
+ </div>
+ <p style="margin:10px" class="help-block"><?=$lang['quarantaine']['qinfo'];?></p>
+ <div class="table-responsive">
+ <table id="quarantainetable" class="table table-striped"></table>
+ </div>
+ <div class="mass-actions-quarantaine">
+ <div class="btn-group">
+ <a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="qitems" href="#"><span class="glyphicon glyphicon-check" aria-hidden="true"></span> <?=$lang['quarantaine']['toggle_all'];?></a>
+ <a class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['quarantaine']['quick_actions'];?> <span class="caret"></span></a>
+ <ul class="dropdown-menu">
+ <li><a id="edit_selected" data-id="qitems" data-api-url='edit/qitem' data-api-attr='{"action":"release"}' href="#"><?=$lang['quarantaine']['release'];?></a></li>
+ <li role="separator" class="divider"></li>
+ <li><a id="delete_selected" data-id="qitems" data-api-url='delete/qitem' href="#"><?=$lang['quarantaine']['remove'];?></a></li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ </div> <!-- /col-md-12 -->
+ </div> <!-- /row -->
+</div> <!-- /container -->
+<?php
+require_once $_SERVER['DOCUMENT_ROOT'] . '/modals/quarantaine.php';
+?>
+<script type='text/javascript'>
+<?php
+$lang_mailbox = json_encode($lang['quarantaine']);
+echo "var lang = ". $lang_mailbox . ";\n";
+echo "var csrf_token = '". $_SESSION['CSRF']['TOKEN'] . "';\n";
+$role = ($_SESSION['mailcow_cc_role'] == "admin") ? 'admin' : 'domainadmin';
+echo "var role = '". $role . "';\n";
+echo "var pagination_size = '". $PAGINATION_SIZE . "';\n";
+?>
+</script>
+<script src="js/footable.min.js"></script>
+<script src="js/quarantaine.js"></script>
+<?php
+require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/footer.inc.php';
+} else {
+ header('Location: /');
+ exit();
+}
+?>
diff --git a/data/web/user.php b/data/web/user.php
index 5c5d6720..3e170cfe 100644
--- a/data/web/user.php
+++ b/data/web/user.php
@@ -23,7 +23,7 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'doma
</div>
<hr>
<div class="row">
- <div class="col-md-3 col-xs-5 text-right"><?=$lang['tfa']['tfa'];?></div>
+ <div class="col-sm-3 col-xs-5 text-right"><?=$lang['tfa']['tfa'];?></div>
<div class="col-sm-9 col-xs-7">
<p id="tfa_pretty"><?=$tfa_data['pretty'];?></p>
<div id="tfa_additional">
@@ -40,8 +40,8 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'doma
</div>
</div>
<div class="row">
- <div class="col-md-3 col-xs-5 text-right"><?=$lang['tfa']['set_tfa'];?></div>
- <div class="col-md-9 col-xs-7">
+ <div class="col-sm-3 col-xs-5 text-right"><?=$lang['tfa']['set_tfa'];?></div>
+ <div class="col-sm-9 col-xs-7">
<select id="selectTFA" class="selectpicker" title="<?=$lang['tfa']['select'];?>">
<option value="yubi_otp"><?=$lang['tfa']['yubi_otp'];?></option>
<option value="u2f"><?=$lang['tfa']['u2f'];?></option>
@@ -105,11 +105,18 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
$user_get_alias_details = user_get_alias_details($username);
?>
<div class="row">
- <div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['aliases'];?>:</div>
+ <div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['direct_aliases'];?>:</div>
<div class="col-md-9 col-xs-7">
- <p><?=$user_get_alias_details['aliases'];?></p>
+ <p><?=$user_get_alias_details['direct_aliases'];?></p>
</div>
</div>
+ <div class="row">
+ <div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['shared_aliases'];?>:</div>
+ <div class="col-md-9 col-xs-7">
+ <p><?=$user_get_alias_details['shared_aliases'];?></p>
+ </div>
+ </div>
+ <hr>
<div class="row">
<div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['domain_aliases'];?>:</div>
<div class="col-md-9 col-xs-7">