2016-12-10 07:39:27 +08:00
< ? php
/*
The match section performs AND operation on different matches : for example , if you have from and rcpt in the same rule ,
then the rule matches only when from AND rcpt match . For similar matches , the OR rule applies : if you have multiple rcpt matches ,
then any of these will trigger the rule . If a rule is triggered then no more rules are matched .
*/
header ( 'Content-Type: text/plain' );
require_once " vars.inc.php " ;
2017-01-19 04:26:49 +08:00
2017-07-02 17:25:14 +08:00
ini_set ( 'error_reporting' , 0 );
2017-03-03 11:44:51 +08:00
[Docker API] Use TLS encryption for communication with "on-the-fly" created key paris (non-exposed)
[Docker API] Create pipe to pass Rspamd UI worker password
[Dovecot] Pull Spamassassin ruleset to be read by Rspamd (MANY THANKS to Peer Heinlein!)
[Dovecot] Garbage collector for deleted maildirs (set keep time via MAILDIR_GC_TIME which defaults to 1440 minutes)
[Web] Flush memcached after mailbox item changes, fixes #1808
[Web] Fix duplicate IDs, fixes #1792
[Compose] Use SQL sockets
[PHP-FPM] Update APCu and Redis libs
[Dovecot] Encrypt maildir with global key pair in crypt-vol-1 (BACKUP!), also fixes #1791
[Web] Fix deletion of spam aliases
[Helper] Add "crypt" to backup script
[Helper] Override file for external SQL socket (not supported!)
[Compose] New images for Rspamd, PHP-FPM, SOGo, Dovecot, Docker API, Watchdog, ACME, Postfix
2018-09-30 04:01:23 +08:00
//$dsn = $database_type . ':host=' . $database_host . ';dbname=' . $database_name;
$dsn = $database_type . " :unix_socket= " . $database_sock . " ;dbname= " . $database_name ;
2016-12-10 07:39:27 +08:00
$opt = [
PDO :: ATTR_ERRMODE => PDO :: ERRMODE_EXCEPTION ,
PDO :: ATTR_DEFAULT_FETCH_MODE => PDO :: FETCH_ASSOC ,
PDO :: ATTR_EMULATE_PREPARES => false ,
];
2017-03-04 07:19:10 +08:00
try {
2017-03-04 07:27:57 +08:00
$pdo = new PDO ( $dsn , $database_user , $database_pass , $opt );
2017-12-09 16:08:18 +08:00
$stmt = $pdo -> query ( " SELECT '1' FROM `filterconf` " );
2017-03-04 07:19:10 +08:00
}
catch ( PDOException $e ) {
echo 'settings { }' ;
exit ;
}
2017-03-04 07:27:57 +08:00
2017-07-02 05:14:27 +08:00
function parse_email ( $email ) {
2018-11-12 16:56:54 +08:00
if ( ! filter_var ( $email , FILTER_VALIDATE_EMAIL )) return false ;
2017-07-02 05:14:27 +08:00
$a = strrpos ( $email , '@' );
return array ( 'local' => substr ( $email , 0 , $a ), 'domain' => substr ( $email , $a ));
}
2018-11-12 16:56:54 +08:00
function wl_by_sogo () {
global $pdo ;
$rcpt = array ();
$stmt = $pdo -> query ( " SELECT DISTINCT(`sogo_folder_info`.`c_path2`) AS `user`, GROUP_CONCAT(`sogo_quick_contact`.`c_mail`) AS `contacts` FROM `sogo_folder_info`
INNER JOIN `sogo_quick_contact` ON `sogo_quick_contact` . `c_folder_id` = `sogo_folder_info` . `c_folder_id`
GROUP BY `c_path2` " );
$sogo_contacts = $stmt -> fetchAll ( PDO :: FETCH_ASSOC );
while ( $row = array_shift ( $sogo_contacts )) {
foreach ( explode ( ',' , $row [ 'contacts' ]) as $contact ) {
if ( ! filter_var ( $contact , FILTER_VALIDATE_EMAIL )) {
continue ;
}
$rcpt [ $row [ 'user' ]][] = '/^' . str_replace ( '/' , '\/' , $contact ) . '$/i' ;
}
}
return $rcpt ;
}
2017-07-02 05:14:27 +08:00
function ucl_rcpts ( $object , $type ) {
global $pdo ;
2018-11-12 16:56:54 +08:00
$rcpt = array ();
2017-07-02 05:14:27 +08:00
if ( $type == 'mailbox' ) {
// Standard aliases
$stmt = $pdo -> prepare ( " SELECT `address` FROM `alias`
2018-06-28 17:48:23 +08:00
WHERE `goto` = : object_goto
AND `address` NOT LIKE '@%' " );
2017-07-02 05:14:27 +08:00
$stmt -> execute ( array (
2018-06-28 17:48:23 +08:00
':object_goto' => $object
2017-07-02 05:14:27 +08:00
));
$standard_aliases = $stmt -> fetchAll ( PDO :: FETCH_ASSOC );
while ( $row = array_shift ( $standard_aliases )) {
$local = parse_email ( $row [ 'address' ])[ 'local' ];
$domain = parse_email ( $row [ 'address' ])[ 'domain' ];
if ( ! empty ( $local ) && ! empty ( $domain )) {
2018-07-13 05:18:49 +08:00
$rcpt [] = '/^' . str_replace ( '/' , '\/' , $local ) . '[+].*' . str_replace ( '/' , '\/' , $domain ) . '$/i' ;
2017-07-02 05:14:27 +08:00
}
2018-07-13 05:18:49 +08:00
$rcpt [] = '/^' . str_replace ( '/' , '\/' , $row [ 'address' ]) . '$/i' ;
2017-07-02 05:14:27 +08:00
}
// Aliases by alias domains
$stmt = $pdo -> prepare ( " SELECT CONCAT(`local_part`, '@', `alias_domain`.`alias_domain`) AS `alias` FROM `mailbox`
LEFT OUTER JOIN `alias_domain` ON `mailbox` . `domain` = `alias_domain` . `target_domain`
WHERE `mailbox` . `username` = : object " );
$stmt -> execute ( array (
':object' => $object
));
$by_domain_aliases = $stmt -> fetchAll ( PDO :: FETCH_ASSOC );
array_filter ( $by_domain_aliases );
while ( $row = array_shift ( $by_domain_aliases )) {
if ( ! empty ( $row [ 'alias' ])) {
$local = parse_email ( $row [ 'alias' ])[ 'local' ];
$domain = parse_email ( $row [ 'alias' ])[ 'domain' ];
if ( ! empty ( $local ) && ! empty ( $domain )) {
2018-07-13 05:18:49 +08:00
$rcpt [] = '/^' . str_replace ( '/' , '\/' , $local ) . '[+].*' . str_replace ( '/' , '\/' , $domain ) . '$/i' ;
2017-07-02 05:14:27 +08:00
}
2018-07-13 05:18:49 +08:00
$rcpt [] = '/^' . str_replace ( '/' , '\/' , $row [ 'alias' ]) . '$/i' ;
2017-07-02 05:14:27 +08:00
}
}
}
elseif ( $type == 'domain' ) {
// Domain self
2018-06-24 05:48:06 +08:00
$rcpt [] = '/.*@' . $object . '/i' ;
$stmt = $pdo -> prepare ( " SELECT `alias_domain` FROM `alias_domain`
WHERE `target_domain` = : object " );
$stmt -> execute ( array ( ':object' => $object ));
$alias_domains = $stmt -> fetchAll ( PDO :: FETCH_ASSOC );
array_filter ( $alias_domains );
while ( $row = array_shift ( $alias_domains )) {
2017-08-27 19:45:18 +08:00
$rcpt [] = '/.*@' . $row [ 'alias_domain' ] . '/i' ;
2018-06-24 05:48:06 +08:00
}
2017-07-02 05:14:27 +08:00
}
2018-11-12 16:56:54 +08:00
return $rcpt ;
2017-07-02 05:14:27 +08:00
}
2016-12-10 07:39:27 +08:00
?>
settings {
2018-06-24 05:48:06 +08:00
watchdog {
priority = 10 ;
2019-03-07 07:07:11 +08:00
rcpt_mime = " /null@localhost/i " ;
from_mime = " /watchdog@localhost/i " ;
2018-06-24 05:48:06 +08:00
apply " default " {
actions {
reject = 9999.0 ;
greylist = 9998.0 ;
" add header " = 9997.0 ;
}
}
}
2017-05-07 14:50:28 +08:00
< ? php
2017-05-06 14:09:40 +08:00
/*
// Start custom scores for users
*/
2016-12-10 07:39:27 +08:00
$stmt = $pdo -> query ( " SELECT DISTINCT `object` FROM `filterconf` WHERE `option` = 'highspamlevel' OR `option` = 'lowspamlevel' " );
$rows = $stmt -> fetchAll ( PDO :: FETCH_ASSOC );
while ( $row = array_shift ( $rows )) {
2018-06-24 05:48:06 +08:00
$username_sane = preg_replace ( " /[^a-zA-Z0-9]+/ " , " " , $row [ 'object' ]);
2016-12-10 07:39:27 +08:00
?>
2018-06-24 05:48:06 +08:00
score_ < ? = $username_sane ; ?> {
priority = 4 ;
2017-07-02 05:14:27 +08:00
< ? php
2017-08-27 20:05:38 +08:00
foreach ( ucl_rcpts ( $row [ 'object' ], strpos ( $row [ 'object' ], '@' ) === FALSE ? 'domain' : 'mailbox' ) as $rcpt ) {
2017-07-02 05:14:27 +08:00
?>
2018-06-28 17:48:23 +08:00
rcpt = < ? = json_encode ( $rcpt , JSON_UNESCAPED_SLASHES ); ?> ;
2016-12-10 07:39:27 +08:00
< ? php
2017-07-02 05:14:27 +08:00
}
2018-06-24 05:48:06 +08:00
$stmt = $pdo -> prepare ( " SELECT `option`, `value` FROM `filterconf`
WHERE ( `option` = 'highspamlevel' OR `option` = 'lowspamlevel' )
AND `object` = : object " );
$stmt -> execute ( array ( ':object' => $row [ 'object' ]));
$spamscore = $stmt -> fetchAll ( PDO :: FETCH_COLUMN | PDO :: FETCH_GROUP );
?>
apply " default " {
actions {
reject = < ? = $spamscore [ 'highspamlevel' ][ 0 ]; ?> ;
greylist = < ? = $spamscore [ 'lowspamlevel' ][ 0 ] - 1 ; ?> ;
" add header " = < ? = $spamscore [ 'lowspamlevel' ][ 0 ]; ?> ;
}
}
}
2016-12-10 07:39:27 +08:00
< ? php
}
2016-12-30 04:12:19 +08:00
2018-11-12 16:56:54 +08:00
/*
// Start SOGo contacts whitelist
// Priority 4, lower than a domain whitelist (5) and lower than a mailbox whitelist (6)
*/
foreach ( wl_by_sogo () as $user => $contacts ) {
$username_sane = preg_replace ( " /[^a-zA-Z0-9]+/ " , " " , $user );
?>
whitelist_sogo_ < ? = $username_sane ; ?> {
< ? php
foreach ( $contacts as $contact ) {
?>
from = < ? = json_encode ( $contact , JSON_UNESCAPED_SLASHES ); ?> ;
< ? php
}
?>
priority = 4 ;
< ? php
foreach ( ucl_rcpts ( $user , 'mailbox' ) as $rcpt ) {
?>
rcpt = < ? = json_encode ( $rcpt , JSON_UNESCAPED_SLASHES ); ?> ;
< ? php
}
?>
apply " default " {
2019-02-24 06:46:01 +08:00
SOGO_CONTACT = - 99.0 ;
2018-11-12 16:56:54 +08:00
}
symbols [
" SOGO_CONTACT "
]
}
< ? php
}
2016-12-10 07:39:27 +08:00
/*
// Start whitelist
*/
$stmt = $pdo -> query ( " SELECT DISTINCT `object` FROM `filterconf` WHERE `option` = 'whitelist_from' " );
$rows = $stmt -> fetchAll ( PDO :: FETCH_ASSOC );
while ( $row = array_shift ( $rows )) {
2018-06-24 05:48:06 +08:00
$username_sane = preg_replace ( " /[^a-zA-Z0-9]+/ " , " " , $row [ 'object' ]);
2016-12-10 07:39:27 +08:00
?>
2018-06-24 05:48:06 +08:00
whitelist_ < ? = $username_sane ; ?> {
2016-12-10 07:39:27 +08:00
< ? php
2019-03-07 07:07:11 +08:00
$list_items = array ();
2019-01-08 19:58:15 +08:00
$stmt = $pdo -> prepare ( " SELECT `value` FROM `filterconf`
2018-06-24 05:48:06 +08:00
WHERE `object` = : object
AND `option` = 'whitelist_from' " );
$stmt -> execute ( array ( ':object' => $row [ 'object' ]));
2019-01-08 19:58:15 +08:00
$list_items = $stmt -> fetchAll ( PDO :: FETCH_ASSOC );
2019-03-07 07:07:11 +08:00
foreach ( $list_items as $item ) {
2016-12-10 07:39:27 +08:00
?>
2019-01-08 19:58:15 +08:00
from = " /<?='^' . str_replace(' \ *', '.*', preg_quote( $item['value'] , '/')) . ' $ ' ;?>/i " ;
2016-12-10 07:39:27 +08:00
< ? php
2019-01-08 19:58:15 +08:00
}
2018-06-24 05:48:06 +08:00
if ( ! filter_var ( trim ( $row [ 'object' ]), FILTER_VALIDATE_EMAIL )) {
2016-12-10 07:39:27 +08:00
?>
2018-06-24 05:48:06 +08:00
priority = 5 ;
2016-12-10 07:39:27 +08:00
< ? php
2018-06-24 05:48:06 +08:00
foreach ( ucl_rcpts ( $row [ 'object' ], strpos ( $row [ 'object' ], '@' ) === FALSE ? 'domain' : 'mailbox' ) as $rcpt ) {
2016-12-10 07:39:27 +08:00
?>
2018-06-28 17:48:23 +08:00
rcpt = < ? = json_encode ( $rcpt , JSON_UNESCAPED_SLASHES ); ?> ;
2016-12-10 07:39:27 +08:00
< ? php
2018-06-24 05:48:06 +08:00
}
}
else {
2016-12-10 07:39:27 +08:00
?>
2018-06-24 05:48:06 +08:00
priority = 6 ;
2017-03-04 21:05:06 +08:00
< ? php
2018-06-24 05:48:06 +08:00
foreach ( ucl_rcpts ( $row [ 'object' ], strpos ( $row [ 'object' ], '@' ) === FALSE ? 'domain' : 'mailbox' ) as $rcpt ) {
2017-03-04 21:05:06 +08:00
?>
2018-06-28 17:48:23 +08:00
rcpt = < ? = json_encode ( $rcpt , JSON_UNESCAPED_SLASHES ); ?> ;
2016-12-10 07:39:27 +08:00
< ? php
2018-06-24 05:48:06 +08:00
}
}
2017-08-27 19:49:34 +08:00
?>
2018-06-24 05:48:06 +08:00
apply " default " {
MAILCOW_WHITE = - 999.0 ;
}
symbols [
" MAILCOW_WHITE "
]
}
2019-03-07 07:07:11 +08:00
whitelist_mime_ < ? = $username_sane ; ?> {
2017-08-27 19:49:34 +08:00
< ? php
2019-03-07 07:07:11 +08:00
foreach ( $list_items as $item ) {
2017-08-27 19:49:34 +08:00
?>
2019-03-07 07:07:11 +08:00
from_mime = " /<?='^' . str_replace(' \ *', '.*', preg_quote( $item['value'] , '/')) . ' $ ' ;?>/i " ;
2019-01-08 19:58:15 +08:00
< ? php
}
2018-06-24 05:48:06 +08:00
if ( ! filter_var ( trim ( $row [ 'object' ]), FILTER_VALIDATE_EMAIL )) {
2017-08-27 19:49:34 +08:00
?>
2018-06-24 05:48:06 +08:00
priority = 5 ;
2017-08-27 19:49:34 +08:00
< ? php
2018-06-24 05:48:06 +08:00
foreach ( ucl_rcpts ( $row [ 'object' ], strpos ( $row [ 'object' ], '@' ) === FALSE ? 'domain' : 'mailbox' ) as $rcpt ) {
2017-08-27 19:49:34 +08:00
?>
2018-06-28 17:48:23 +08:00
rcpt = < ? = json_encode ( $rcpt , JSON_UNESCAPED_SLASHES ); ?> ;
2017-08-27 19:49:34 +08:00
< ? php
2018-06-24 05:48:06 +08:00
}
}
else {
2017-08-27 19:49:34 +08:00
?>
2018-06-24 05:48:06 +08:00
priority = 6 ;
2017-08-27 19:49:34 +08:00
< ? php
2018-06-24 05:48:06 +08:00
foreach ( ucl_rcpts ( $row [ 'object' ], strpos ( $row [ 'object' ], '@' ) === FALSE ? 'domain' : 'mailbox' ) as $rcpt ) {
2017-08-27 19:49:34 +08:00
?>
2018-06-28 17:48:23 +08:00
rcpt = < ? = json_encode ( $rcpt , JSON_UNESCAPED_SLASHES ); ?> ;
2017-08-27 19:49:34 +08:00
< ? php
2018-06-24 05:48:06 +08:00
}
}
2016-12-10 07:39:27 +08:00
?>
2018-06-24 05:48:06 +08:00
apply " default " {
MAILCOW_WHITE = - 999.0 ;
}
symbols [
" MAILCOW_WHITE "
]
}
2016-12-10 07:39:27 +08:00
< ? php
}
/*
// Start blacklist
*/
$stmt = $pdo -> query ( " SELECT DISTINCT `object` FROM `filterconf` WHERE `option` = 'blacklist_from' " );
$rows = $stmt -> fetchAll ( PDO :: FETCH_ASSOC );
while ( $row = array_shift ( $rows )) {
2018-06-24 05:48:06 +08:00
$username_sane = preg_replace ( " /[^a-zA-Z0-9]+/ " , " " , $row [ 'object' ]);
2016-12-10 07:39:27 +08:00
?>
2018-06-24 05:48:06 +08:00
blacklist_ < ? = $username_sane ; ?> {
2016-12-10 07:39:27 +08:00
< ? php
2019-03-07 07:07:11 +08:00
$list_items = array ();
2019-01-08 19:58:15 +08:00
$stmt = $pdo -> prepare ( " SELECT `value` FROM `filterconf`
2018-06-24 05:48:06 +08:00
WHERE `object` = : object
AND `option` = 'blacklist_from' " );
$stmt -> execute ( array ( ':object' => $row [ 'object' ]));
2019-01-08 19:58:15 +08:00
$list_items = $stmt -> fetchAll ( PDO :: FETCH_ASSOC );
2019-03-07 07:07:11 +08:00
foreach ( $list_items as $item ) {
2016-12-10 07:39:27 +08:00
?>
2019-01-08 19:58:15 +08:00
from = " /<?='^' . str_replace(' \ *', '.*', preg_quote( $item['value'] , '/')) . ' $ ' ;?>/i " ;
2016-12-10 07:39:27 +08:00
< ? php
2019-01-08 19:58:15 +08:00
}
2018-06-24 05:48:06 +08:00
if ( ! filter_var ( trim ( $row [ 'object' ]), FILTER_VALIDATE_EMAIL )) {
2016-12-10 07:39:27 +08:00
?>
2018-06-24 05:48:06 +08:00
priority = 5 ;
2016-12-10 07:39:27 +08:00
< ? php
2018-06-24 05:48:06 +08:00
foreach ( ucl_rcpts ( $row [ 'object' ], strpos ( $row [ 'object' ], '@' ) === FALSE ? 'domain' : 'mailbox' ) as $rcpt ) {
2016-12-10 07:39:27 +08:00
?>
2018-06-28 17:48:23 +08:00
rcpt = < ? = json_encode ( $rcpt , JSON_UNESCAPED_SLASHES ); ?> ;
2016-12-10 07:39:27 +08:00
< ? php
2018-06-24 05:48:06 +08:00
}
}
else {
2016-12-10 07:39:27 +08:00
?>
2018-06-24 05:48:06 +08:00
priority = 6 ;
2017-03-04 21:05:06 +08:00
< ? php
2018-06-24 05:48:06 +08:00
foreach ( ucl_rcpts ( $row [ 'object' ], strpos ( $row [ 'object' ], '@' ) === FALSE ? 'domain' : 'mailbox' ) as $rcpt ) {
2017-03-04 21:05:06 +08:00
?>
2018-06-28 17:48:23 +08:00
rcpt = < ? = json_encode ( $rcpt , JSON_UNESCAPED_SLASHES ); ?> ;
2017-03-04 21:05:06 +08:00
< ? php
2018-06-24 05:48:06 +08:00
}
}
2017-08-27 19:49:34 +08:00
?>
2018-06-24 05:48:06 +08:00
apply " default " {
MAILCOW_BLACK = 999.0 ;
}
symbols [
" MAILCOW_BLACK "
]
}
blacklist_header_ < ? = $username_sane ; ?> {
2017-08-27 19:49:34 +08:00
< ? php
2019-03-07 07:07:11 +08:00
foreach ( $list_items as $item ) {
2017-08-27 19:49:34 +08:00
?>
2019-03-07 07:07:11 +08:00
from_mime = " /<?='^' . str_replace(' \ *', '.*', preg_quote( $item['value'] , '/')) . ' $ ' ;?>/i " ;
2019-01-08 19:58:15 +08:00
< ? php
}
2018-06-24 05:48:06 +08:00
if ( ! filter_var ( trim ( $row [ 'object' ]), FILTER_VALIDATE_EMAIL )) {
2017-08-27 19:49:34 +08:00
?>
2018-06-24 05:48:06 +08:00
priority = 5 ;
2017-08-27 19:49:34 +08:00
< ? php
2018-06-24 05:48:06 +08:00
foreach ( ucl_rcpts ( $row [ 'object' ], strpos ( $row [ 'object' ], '@' ) === FALSE ? 'domain' : 'mailbox' ) as $rcpt ) {
2017-08-27 19:49:34 +08:00
?>
2018-06-28 17:48:23 +08:00
rcpt = < ? = json_encode ( $rcpt , JSON_UNESCAPED_SLASHES ); ?> ;
2017-08-27 19:49:34 +08:00
< ? php
2018-06-24 05:48:06 +08:00
}
}
else {
2017-08-27 19:49:34 +08:00
?>
2018-06-24 05:48:06 +08:00
priority = 6 ;
2017-08-27 19:49:34 +08:00
< ? php
2018-06-24 05:48:06 +08:00
foreach ( ucl_rcpts ( $row [ 'object' ], strpos ( $row [ 'object' ], '@' ) === FALSE ? 'domain' : 'mailbox' ) as $rcpt ) {
2017-08-27 19:49:34 +08:00
?>
2018-06-28 17:48:23 +08:00
rcpt = < ? = json_encode ( $rcpt , JSON_UNESCAPED_SLASHES ); ?> ;
2017-08-27 19:49:34 +08:00
< ? php
2018-06-24 05:48:06 +08:00
}
}
2016-12-10 07:39:27 +08:00
?>
2018-06-24 05:48:06 +08:00
apply " default " {
MAILCOW_BLACK = 999.0 ;
}
symbols [
" MAILCOW_BLACK "
]
}
< ? php
}
2018-07-29 06:34:36 +08:00
/*
// Start traps
*/
?>
traps {
< ? php
foreach ( ucl_rcpts ( 'spam@localhost' , 'mailbox' ) as $rcpt ) {
?>
rcpt = < ? = json_encode ( $rcpt , JSON_UNESCAPED_SLASHES ); ?> ;
< ? php
}
foreach ( ucl_rcpts ( 'ham@localhost' , 'mailbox' ) as $rcpt ) {
?>
rcpt = < ? = json_encode ( $rcpt , JSON_UNESCAPED_SLASHES ); ?> ;
< ? php
}
?>
priority = 9 ;
want_spam = yes ;
}
< ? php
2018-06-24 05:48:06 +08:00
// Start additional content
$stmt = $pdo -> query ( " SELECT `id`, `content` FROM `settingsmap` WHERE `active` = '1' " );
$rows = $stmt -> fetchAll ( PDO :: FETCH_ASSOC );
while ( $row = array_shift ( $rows )) {
$username_sane = preg_replace ( " /[^a-zA-Z0-9]+/ " , " " , $row [ 'id' ]);
?>
additional_settings_ < ? = intval ( $row [ 'id' ]); ?> {
2016-12-10 07:39:27 +08:00
< ? php
2018-06-24 05:48:06 +08:00
$content = preg_split ( '/\r\n|\r|\n/' , $row [ 'content' ]);
foreach ( $content as $line ) {
echo ' ' . $line . PHP_EOL ;
}
2018-10-19 17:12:58 +08:00
?>
}
< ? php
2016-12-10 07:39:27 +08:00
}
?>
2019-02-24 06:46:01 +08:00
}