Skip to content

Commit 2370828

Browse files
committed
Parse the dovecot/postfix logs to update the last login time for mail_user's. #5374
1 parent 72c4f4f commit 2370828

File tree

1 file changed

+117
-0
lines changed

1 file changed

+117
-0
lines changed
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
<?php
2+
3+
/*
4+
Copyright (c) 2024, Herman van Rink, Initfour websolutions
5+
All rights reserved.
6+
7+
Redistribution and use in source and binary forms, with or without modification,
8+
are permitted provided that the following conditions are met:
9+
10+
* Redistributions of source code must retain the above copyright notice,
11+
this list of conditions and the following disclaimer.
12+
* Redistributions in binary form must reproduce the above copyright notice,
13+
this list of conditions and the following disclaimer in the documentation
14+
and/or other materials provided with the distribution.
15+
* Neither the name of ISPConfig nor the names of its contributors
16+
may be used to endorse or promote products derived from this software without
17+
specific prior written permission.
18+
19+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22+
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
23+
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24+
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
26+
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28+
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29+
*/
30+
31+
class cronjob_mailbox_stats_hourly extends cronjob {
32+
33+
// job schedule
34+
protected $_schedule = '0 * * * *';
35+
protected $mailbox_traffic = array();
36+
protected $mail_boxes = array();
37+
protected $mail_rewrites = array();
38+
39+
/* this function is optional if it contains no custom code */
40+
public function onPrepare() {
41+
global $app;
42+
43+
parent::onPrepare();
44+
}
45+
46+
/* this function is optional if it contains no custom code */
47+
public function onBeforeRun() {
48+
global $app;
49+
50+
return parent::onBeforeRun();
51+
}
52+
53+
public function onRunJob() {
54+
global $app, $conf;
55+
56+
$sql = "SELECT mailuser_id FROM mail_user WHERE server_id = ?";
57+
$records = $app->db->queryAllRecords($sql, $conf['server_id']);
58+
if(count($records) > 0) {
59+
$this->update_last_mail_login();
60+
}
61+
62+
parent::onRunJob();
63+
}
64+
65+
/* this function is optional if it contains no custom code */
66+
public function onAfterRun() {
67+
global $app;
68+
69+
parent::onAfterRun();
70+
}
71+
72+
// Parse the dovecot/postfix logs to update the last login time for mail_user's.
73+
private function update_last_mail_login() {
74+
global $app;
75+
76+
// Command to get all successful dovecot and postfix logins from the last hour.
77+
$journalCmd = "journalctl -u dovecot.service -u postfix@-.service --since='60 minutes ago' --grep '((imap|pop3)-login: Login|sasl_method=PLAIN)'";
78+
79+
$process = popen($journalCmd, 'r');
80+
if ($process === false) {
81+
die("Failed to execute the command");
82+
}
83+
84+
$updatedUsers = [];
85+
86+
// Loop over all lines.
87+
while (!feof($process)) {
88+
$line = fgets($process);
89+
if ($line === false) {
90+
break;
91+
}
92+
93+
$matches = [];
94+
// Match pop3/imap logings, or alternately smtp logins.
95+
if (preg_match('/(.*) dovecot\[.*\]: (imap|pop3)-login: Login: user=\<([\w\.@-]+)\>/', $line, $matches) || preg_match('/(.*) sasl_method=PLAIN, sasl_username=([\w\.@-]+)/', $line, $matches)) {
96+
$user = $matches[3] ?? $matches[2];
97+
$updatedUsers[] = $user;
98+
}
99+
}
100+
101+
pclose($process);
102+
103+
$uniqueUsers = array_unique($updatedUsers);
104+
105+
$app->log('Updating last_access stats for ' . count($uniqueUsers) . ' mail users', LOGLEVEL_DEBUG);
106+
107+
// Date/time rounded to hours.
108+
$now = time() - (time() % (60 * 60));
109+
$nowFormatted = date('Y-m-d H:i:s', $now);
110+
$sqlStatement = "UPDATE mail_user SET last_access=? WHERE email=?";
111+
112+
// Save to master db.
113+
foreach ($uniqueUsers as $user) {
114+
$ret = $app->dbmaster->query($sql, $now, $user);
115+
}
116+
}
117+
}

0 commit comments

Comments
 (0)