blob: 00c11deeccb96a5fb8b578bf1b13b35b77810604 [file] [log] [blame]
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001<?php
2function mailbox($_action, $_type, $_data = null, $_extra = null) {
3 global $pdo;
4 global $redis;
5 global $lang;
6 global $MAILBOX_DEFAULT_ATTRIBUTES;
7 $_data_log = $_data;
8 !isset($_data_log['password']) ?: $_data_log['password'] = '*';
9 !isset($_data_log['password2']) ?: $_data_log['password2'] = '*';
10 switch ($_action) {
11 case 'add':
12 switch ($_type) {
13 case 'time_limited_alias':
14 if (!isset($_SESSION['acl']['spam_alias']) || $_SESSION['acl']['spam_alias'] != "1" ) {
15 $_SESSION['return'][] = array(
16 'type' => 'danger',
17 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
18 'msg' => 'access_denied'
19 );
20 return false;
21 }
22 if (isset($_data['username']) && filter_var($_data['username'], FILTER_VALIDATE_EMAIL)) {
23 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data['username'])) {
24 $_SESSION['return'][] = array(
25 'type' => 'danger',
26 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
27 'msg' => 'access_denied'
28 );
29 return false;
30 }
31 else {
32 $username = $_data['username'];
33 }
34 }
35 else {
36 $username = $_SESSION['mailcow_cc_username'];
37 }
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +020038 if (isset($_data["validity"]) && !filter_var($_data["validity"], FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 87600)))) {
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +010039 $_SESSION['return'][] = array(
40 'type' => 'danger',
41 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
42 'msg' => 'validity_missing'
43 );
44 return false;
45 }
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +020046 else {
47 // Default to 1 yr
48 $_data["validity"] = 8760;
49 }
50 $domain = $_data['domain'];
51 $valid_domains[] = mailbox('get', 'mailbox_details', $username)['domain'];
52 $valid_alias_domains = user_get_alias_details($username)['alias_domains'];
53 if (!empty($valid_alias_domains)) {
54 $valid_domains = array_merge($valid_domains, $valid_alias_domains);
55 }
56 if (!in_array($domain, $valid_domains)) {
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +010057 $_SESSION['return'][] = array(
58 'type' => 'danger',
59 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
60 'msg' => 'domain_invalid'
61 );
62 return false;
63 }
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +020064 $validity = strtotime("+" . $_data["validity"] . " hour");
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +010065 $stmt = $pdo->prepare("INSERT INTO `spamalias` (`address`, `goto`, `validity`) VALUES
66 (:address, :goto, :validity)");
67 $stmt->execute(array(
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +020068 ':address' => readable_random_string(rand(rand(3, 9), rand(3, 9))) . '.' . readable_random_string(rand(rand(3, 9), rand(3, 9))) . '@' . $domain,
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +010069 ':goto' => $username,
70 ':validity' => $validity
71 ));
72 $_SESSION['return'][] = array(
73 'type' => 'success',
74 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
75 'msg' => array('mailbox_modified', $username)
76 );
77 break;
78 case 'global_filter':
79 if ($_SESSION['mailcow_cc_role'] != "admin") {
80 $_SESSION['return'][] = array(
81 'type' => 'danger',
82 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
83 'msg' => 'access_denied'
84 );
85 return false;
86 }
87 $sieve = new Sieve\SieveParser();
88 $script_data = $_data['script_data'];
89 $script_data = str_replace("\r\n", "\n", $script_data); // windows -> unix
90 $script_data = str_replace("\r", "\n", $script_data); // remaining -> unix
91 $filter_type = $_data['filter_type'];
92 try {
93 $sieve->parse($script_data);
94 }
95 catch (Exception $e) {
96 $_SESSION['return'][] = array(
97 'type' => 'danger',
98 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
99 'msg' => array('sieve_error', $e->getMessage())
100 );
101 return false;
102 }
103 if ($filter_type == 'prefilter') {
104 try {
105 if (file_exists('/global_sieve/before')) {
106 $filter_handle = fopen('/global_sieve/before', 'w');
107 if (!$filter_handle) {
108 throw new Exception($lang['danger']['file_open_error']);
109 }
110 fwrite($filter_handle, $script_data);
111 fclose($filter_handle);
112 }
113 $restart_response = json_decode(docker('post', 'dovecot-mailcow', 'restart'), true);
114 if ($restart_response['type'] == "success") {
115 $_SESSION['return'][] = array(
116 'type' => 'success',
117 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
118 'msg' => 'dovecot_restart_success'
119 );
120 }
121 else {
122 $_SESSION['return'][] = array(
123 'type' => 'warning',
124 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
125 'msg' => 'dovecot_restart_failed'
126 );
127 }
128 }
129 catch (Exception $e) {
130 $_SESSION['return'][] = array(
131 'type' => 'danger',
132 'log' => array(__FUNCTION__, $_action, $_data_log),
133 'msg' => array('global_filter_write_error', htmlspecialchars($e->getMessage()))
134 );
135 return false;
136 }
137 }
138 elseif ($filter_type == 'postfilter') {
139 try {
140 if (file_exists('/global_sieve/after')) {
141 $filter_handle = fopen('/global_sieve/after', 'w');
142 if (!$filter_handle) {
143 throw new Exception($lang['danger']['file_open_error']);
144 }
145 fwrite($filter_handle, $script_data);
146 fclose($filter_handle);
147 }
148 $restart_response = json_decode(docker('post', 'dovecot-mailcow', 'restart'), true);
149 if ($restart_response['type'] == "success") {
150 $_SESSION['return'][] = array(
151 'type' => 'success',
152 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
153 'msg' => 'dovecot_restart_success'
154 );
155 }
156 else {
157 $_SESSION['return'][] = array(
158 'type' => 'warning',
159 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
160 'msg' => 'dovecot_restart_failed'
161 );
162 }
163 }
164 catch (Exception $e) {
165 $_SESSION['return'][] = array(
166 'type' => 'danger',
167 'log' => array(__FUNCTION__, $_action, $_data_log),
168 'msg' => array('global_filter_write_error', htmlspecialchars($e->getMessage()))
169 );
170 return false;
171 }
172 }
173 else {
174 $_SESSION['return'][] = array(
175 'type' => 'danger',
176 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
177 'msg' => 'invalid_filter_type'
178 );
179 return false;
180 }
181 $_SESSION['return'][] = array(
182 'type' => 'success',
183 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
184 'msg' => 'global_filter_written'
185 );
186 return true;
187 case 'filter':
188 $sieve = new Sieve\SieveParser();
189 if (!isset($_SESSION['acl']['filters']) || $_SESSION['acl']['filters'] != "1" ) {
190 $_SESSION['return'][] = array(
191 'type' => 'danger',
192 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
193 'msg' => 'access_denied'
194 );
195 return false;
196 }
197 if (isset($_data['username']) && filter_var($_data['username'], FILTER_VALIDATE_EMAIL)) {
198 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data['username'])) {
199 $_SESSION['return'][] = array(
200 'type' => 'danger',
201 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
202 'msg' => 'access_denied'
203 );
204 return false;
205 }
206 else {
207 $username = $_data['username'];
208 }
209 }
210 elseif ($_SESSION['mailcow_cc_role'] == "user") {
211 $username = $_SESSION['mailcow_cc_username'];
212 }
213 else {
214 $_SESSION['return'][] = array(
215 'type' => 'danger',
216 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
217 'msg' => 'no_user_defined'
218 );
219 return false;
220 }
221 $active = intval($_data['active']);
222 $script_data = $_data['script_data'];
223 $script_desc = $_data['script_desc'];
224 $filter_type = $_data['filter_type'];
225 if (empty($script_data)) {
226 $_SESSION['return'][] = array(
227 'type' => 'danger',
228 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
229 'msg' => 'script_empty'
230 );
231 return false;
232 }
233 try {
234 $sieve->parse($script_data);
235 }
236 catch (Exception $e) {
237 $_SESSION['return'][] = array(
238 'type' => 'danger',
239 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
240 'msg' => array('sieve_error', $e->getMessage())
241 );
242 return false;
243 }
244 if (empty($script_data) || empty($script_desc)) {
245 $_SESSION['return'][] = array(
246 'type' => 'danger',
247 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
248 'msg' => 'value_missing'
249 );
250 return false;
251 }
252 if ($filter_type != 'postfilter' && $filter_type != 'prefilter') {
253 $_SESSION['return'][] = array(
254 'type' => 'danger',
255 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
256 'msg' => 'filter_type'
257 );
258 return false;
259 }
260 if (!empty($active)) {
261 $script_name = 'active';
262 $stmt = $pdo->prepare("UPDATE `sieve_filters` SET `script_name` = 'inactive' WHERE `username` = :username AND `filter_type` = :filter_type");
263 $stmt->execute(array(
264 ':username' => $username,
265 ':filter_type' => $filter_type
266 ));
267 }
268 else {
269 $script_name = 'inactive';
270 }
271 $stmt = $pdo->prepare("INSERT INTO `sieve_filters` (`username`, `script_data`, `script_desc`, `script_name`, `filter_type`)
272 VALUES (:username, :script_data, :script_desc, :script_name, :filter_type)");
273 $stmt->execute(array(
274 ':username' => $username,
275 ':script_data' => $script_data,
276 ':script_desc' => $script_desc,
277 ':script_name' => $script_name,
278 ':filter_type' => $filter_type
279 ));
280 $_SESSION['return'][] = array(
281 'type' => 'success',
282 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
283 'msg' => array('mailbox_modified', $username)
284 );
285 break;
286 case 'syncjob':
287 if (!isset($_SESSION['acl']['syncjobs']) || $_SESSION['acl']['syncjobs'] != "1" ) {
288 $_SESSION['return'][] = array(
289 'type' => 'danger',
290 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
291 'msg' => 'access_denied'
292 );
293 return false;
294 }
295 if (isset($_data['username']) && filter_var($_data['username'], FILTER_VALIDATE_EMAIL)) {
296 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data['username'])) {
297 $_SESSION['return'][] = array(
298 'type' => 'danger',
299 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
300 'msg' => 'access_denied'
301 );
302 return false;
303 }
304 else {
305 $username = $_data['username'];
306 }
307 }
308 elseif ($_SESSION['mailcow_cc_role'] == "user") {
309 $username = $_SESSION['mailcow_cc_username'];
310 }
311 else {
312 $_SESSION['return'][] = array(
313 'type' => 'danger',
314 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
315 'msg' => 'no_user_defined'
316 );
317 return false;
318 }
319 $active = intval($_data['active']);
320 $subscribeall = intval($_data['subscribeall']);
321 $delete2duplicates = intval($_data['delete2duplicates']);
322 $delete1 = intval($_data['delete1']);
323 $delete2 = intval($_data['delete2']);
324 $timeout1 = intval($_data['timeout1']);
325 $timeout2 = intval($_data['timeout2']);
326 $skipcrossduplicates = intval($_data['skipcrossduplicates']);
327 $automap = intval($_data['automap']);
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +0100328 $dry = intval($_data['dry']);
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100329 $port1 = $_data['port1'];
330 $host1 = strtolower($_data['host1']);
331 $password1 = $_data['password1'];
332 $exclude = $_data['exclude'];
333 $maxage = $_data['maxage'];
334 $maxbytespersecond = $_data['maxbytespersecond'];
335 $subfolder2 = $_data['subfolder2'];
336 $user1 = $_data['user1'];
337 $mins_interval = $_data['mins_interval'];
338 $enc1 = $_data['enc1'];
339 $custom_params = (empty(trim($_data['custom_params']))) ? '' : trim($_data['custom_params']);
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100340
341 // validate custom params
342 foreach (explode('-', $custom_params) as $param){
343 if(empty($param)) continue;
344
345 // extract option
346 if (str_contains($param, '=')) $param = explode('=', $param)[0];
347 else $param = rtrim($param, ' ');
348 // remove first char if first char is -
349 if ($param[0] == '-') $param = ltrim($param, $param[0]);
350
351 if (str_contains($param, ' ')) {
352 // bad char
353 $_SESSION['return'][] = array(
354 'type' => 'danger',
355 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
356 'msg' => 'bad character SPACE'
357 );
358 return false;
359 }
360
361 // check if param is whitelisted
362 if (!in_array(strtolower($param), $GLOBALS["IMAPSYNC_OPTIONS"]["whitelist"])){
363 // bad option
364 $_SESSION['return'][] = array(
365 'type' => 'danger',
366 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
367 'msg' => 'bad option '. $param
368 );
369 return false;
370 }
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100371 }
372 if (empty($subfolder2)) {
373 $subfolder2 = "";
374 }
375 if (!isset($maxage) || !filter_var($maxage, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 32000)))) {
376 $maxage = "0";
377 }
378 if (!isset($timeout1) || !filter_var($timeout1, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 32000)))) {
379 $timeout1 = "600";
380 }
381 if (!isset($timeout2) || !filter_var($timeout2, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 32000)))) {
382 $timeout2 = "600";
383 }
384 if (!isset($maxbytespersecond) || !filter_var($maxbytespersecond, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 125000000)))) {
385 $maxbytespersecond = "0";
386 }
387 if (!filter_var($port1, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 65535)))) {
388 $_SESSION['return'][] = array(
389 'type' => 'danger',
390 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
391 'msg' => 'access_denied'
392 );
393 return false;
394 }
395 if (!filter_var($mins_interval, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 43800)))) {
396 $_SESSION['return'][] = array(
397 'type' => 'danger',
398 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
399 'msg' => 'access_denied'
400 );
401 return false;
402 }
403 // if (!is_valid_domain_name($host1)) {
404 // $_SESSION['return'][] = array(
405 // 'type' => 'danger',
406 // 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
407 // 'msg' => 'access_denied'
408 // );
409 // return false;
410 // }
411 if ($enc1 != "TLS" && $enc1 != "SSL" && $enc1 != "PLAIN") {
412 $_SESSION['return'][] = array(
413 'type' => 'danger',
414 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
415 'msg' => 'access_denied'
416 );
417 return false;
418 }
419 if (@preg_match("/" . $exclude . "/", null) === false) {
420 $_SESSION['return'][] = array(
421 'type' => 'danger',
422 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
423 'msg' => 'access_denied'
424 );
425 return false;
426 }
427 $stmt = $pdo->prepare("SELECT '1' FROM `imapsync`
428 WHERE `user2` = :user2 AND `user1` = :user1 AND `host1` = :host1");
429 $stmt->execute(array(':user1' => $user1, ':user2' => $username, ':host1' => $host1));
430 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
431 if ($num_results != 0) {
432 $_SESSION['return'][] = array(
433 'type' => 'danger',
434 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
435 'msg' => array('object_exists', htmlspecialchars($host1 . ' / ' . $user1))
436 );
437 return false;
438 }
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +0100439 $stmt = $pdo->prepare("INSERT INTO `imapsync` (`user2`, `exclude`, `delete1`, `delete2`, `timeout1`, `timeout2`, `automap`, `skipcrossduplicates`, `maxbytespersecond`, `subscribeall`, `dry`, `maxage`, `subfolder2`, `host1`, `authmech1`, `user1`, `password1`, `mins_interval`, `port1`, `enc1`, `delete2duplicates`, `custom_params`, `active`)
440 VALUES (:user2, :exclude, :delete1, :delete2, :timeout1, :timeout2, :automap, :skipcrossduplicates, :maxbytespersecond, :subscribeall, :dry, :maxage, :subfolder2, :host1, :authmech1, :user1, :password1, :mins_interval, :port1, :enc1, :delete2duplicates, :custom_params, :active)");
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100441 $stmt->execute(array(
442 ':user2' => $username,
443 ':custom_params' => $custom_params,
444 ':exclude' => $exclude,
445 ':maxage' => $maxage,
446 ':delete1' => $delete1,
447 ':delete2' => $delete2,
448 ':timeout1' => $timeout1,
449 ':timeout2' => $timeout2,
450 ':automap' => $automap,
451 ':skipcrossduplicates' => $skipcrossduplicates,
452 ':maxbytespersecond' => $maxbytespersecond,
453 ':subscribeall' => $subscribeall,
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +0100454 ':dry' => $dry,
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100455 ':subfolder2' => $subfolder2,
456 ':host1' => $host1,
457 ':authmech1' => 'PLAIN',
458 ':user1' => $user1,
459 ':password1' => $password1,
460 ':mins_interval' => $mins_interval,
461 ':port1' => $port1,
462 ':enc1' => $enc1,
463 ':delete2duplicates' => $delete2duplicates,
464 ':active' => $active,
465 ));
466 $_SESSION['return'][] = array(
467 'type' => 'success',
468 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
469 'msg' => array('mailbox_modified', $username)
470 );
471 break;
472 case 'domain':
473 if ($_SESSION['mailcow_cc_role'] != "admin") {
474 $_SESSION['return'][] = array(
475 'type' => 'danger',
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100476 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100477 'msg' => 'access_denied'
478 );
479 return false;
480 }
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +0100481 $DOMAIN_DEFAULT_ATTRIBUTES = null;
482 if ($_data['template']){
483 $DOMAIN_DEFAULT_ATTRIBUTES = mailbox('get', 'domain_templates', $_data['template'])['attributes'];
484 }
485 if (empty($DOMAIN_DEFAULT_ATTRIBUTES)) {
486 $DOMAIN_DEFAULT_ATTRIBUTES = mailbox('get', 'domain_templates')[0]['attributes'];
487 }
488
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +0200489 $domain = idn_to_ascii(strtolower(trim($_data['domain'])), 0, INTL_IDNA_VARIANT_UTS46);
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100490 $description = $_data['description'];
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100491 if (empty($description)) $description = $domain;
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +0100492 $tags = (isset($_data['tags'])) ? (array)$_data['tags'] : $DOMAIN_DEFAULT_ATTRIBUTES['tags'];
493 $aliases = (isset($_data['aliases'])) ? (int)$_data['aliases'] : $DOMAIN_DEFAULT_ATTRIBUTES['max_num_aliases_for_domain'];
494 $mailboxes = (isset($_data['mailboxes'])) ? (int)$_data['mailboxes'] : $DOMAIN_DEFAULT_ATTRIBUTES['max_num_mboxes_for_domain'];
495 $defquota = (isset($_data['defquota'])) ? (int)$_data['defquota'] : $DOMAIN_DEFAULT_ATTRIBUTES['def_quota_for_mbox'] / 1024 ** 2;
496 $maxquota = (isset($_data['maxquota'])) ? (int)$_data['maxquota'] : $DOMAIN_DEFAULT_ATTRIBUTES['max_quota_for_mbox'] / 1024 ** 2;
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +0200497 $restart_sogo = (int)$_data['restart_sogo'];
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +0100498 $quota = (isset($_data['quota'])) ? (int)$_data['quota'] : $DOMAIN_DEFAULT_ATTRIBUTES['max_quota_for_domain'] / 1024 ** 2;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100499 if ($defquota > $maxquota) {
500 $_SESSION['return'][] = array(
501 'type' => 'danger',
502 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
503 'msg' => 'mailbox_defquota_exceeds_mailbox_maxquota'
504 );
505 return false;
506 }
507 if ($maxquota > $quota) {
508 $_SESSION['return'][] = array(
509 'type' => 'danger',
510 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
511 'msg' => 'mailbox_quota_exceeds_domain_quota'
512 );
513 return false;
514 }
515 if ($defquota == "0" || empty($defquota)) {
516 $_SESSION['return'][] = array(
517 'type' => 'danger',
518 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
519 'msg' => 'defquota_empty'
520 );
521 return false;
522 }
523 if ($maxquota == "0" || empty($maxquota)) {
524 $_SESSION['return'][] = array(
525 'type' => 'danger',
526 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
527 'msg' => 'maxquota_empty'
528 );
529 return false;
530 }
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +0100531 $active = (isset($_data['active'])) ? intval($_data['active']) : $DOMAIN_DEFAULT_ATTRIBUTES['active'];
532 $relay_all_recipients = (isset($_data['relay_all_recipients'])) ? intval($_data['relay_all_recipients']) : $DOMAIN_DEFAULT_ATTRIBUTES['relay_all_recipients'];
533 $relay_unknown_only = (isset($_data['relay_unknown_only'])) ? intval($_data['relay_unknown_only']) : $DOMAIN_DEFAULT_ATTRIBUTES['relay_unknown_only'];
534 $backupmx = (isset($_data['backupmx'])) ? intval($_data['backupmx']) : $DOMAIN_DEFAULT_ATTRIBUTES['backupmx'];
535 $gal = (isset($_data['gal'])) ? intval($_data['gal']) : $DOMAIN_DEFAULT_ATTRIBUTES['gal'];
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100536 if ($relay_all_recipients == 1) {
537 $backupmx = '1';
538 }
539 if ($relay_unknown_only == 1) {
540 $backupmx = 1;
541 $relay_all_recipients = 1;
542 }
543 if (!is_valid_domain_name($domain)) {
544 $_SESSION['return'][] = array(
545 'type' => 'danger',
546 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
547 'msg' => 'domain_invalid'
548 );
549 return false;
550 }
551 foreach (array($quota, $maxquota, $mailboxes, $aliases) as $data) {
552 if (!is_numeric($data)) {
553 $_SESSION['return'][] = array(
554 'type' => 'danger',
555 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
556 'msg' => array('object_is_not_numeric', htmlspecialchars($data))
557 );
558 return false;
559 }
560 }
561 $stmt = $pdo->prepare("SELECT `domain` FROM `domain`
562 WHERE `domain` = :domain");
563 $stmt->execute(array(':domain' => $domain));
564 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
565 $stmt = $pdo->prepare("SELECT `alias_domain` FROM `alias_domain`
566 WHERE `alias_domain` = :domain");
567 $stmt->execute(array(':domain' => $domain));
568 $num_results = $num_results + count($stmt->fetchAll(PDO::FETCH_ASSOC));
569 if ($num_results != 0) {
570 $_SESSION['return'][] = array(
571 'type' => 'danger',
572 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
573 'msg' => array('domain_exists', htmlspecialchars($domain))
574 );
575 return false;
576 }
577 if ($domain == getenv('MAILCOW_HOSTNAME')) {
578 $_SESSION['return'][] = array(
579 'type' => 'danger',
580 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
581 'msg' => 'domain_cannot_match_hostname'
582 );
583 return false;
584 }
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100585
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100586 $stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `external` = 1 AND `send_as` LIKE :domain");
587 $stmt->execute(array(
588 ':domain' => '%@' . $domain
589 ));
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100590 // save domain
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100591 $stmt = $pdo->prepare("INSERT INTO `domain` (`domain`, `description`, `aliases`, `mailboxes`, `defquota`, `maxquota`, `quota`, `backupmx`, `gal`, `active`, `relay_unknown_only`, `relay_all_recipients`)
592 VALUES (:domain, :description, :aliases, :mailboxes, :defquota, :maxquota, :quota, :backupmx, :gal, :active, :relay_unknown_only, :relay_all_recipients)");
593 $stmt->execute(array(
594 ':domain' => $domain,
595 ':description' => $description,
596 ':aliases' => $aliases,
597 ':mailboxes' => $mailboxes,
598 ':defquota' => $defquota,
599 ':maxquota' => $maxquota,
600 ':quota' => $quota,
601 ':backupmx' => $backupmx,
602 ':gal' => $gal,
603 ':active' => $active,
604 ':relay_unknown_only' => $relay_unknown_only,
605 ':relay_all_recipients' => $relay_all_recipients
606 ));
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100607 // save tags
608 foreach($tags as $index => $tag){
609 if (empty($tag)) continue;
610 if ($index > $GLOBALS['TAGGING_LIMIT']) {
611 $_SESSION['return'][] = array(
612 'type' => 'warning',
613 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
614 'msg' => array('tag_limit_exceeded', 'limit '.$GLOBALS['TAGGING_LIMIT'])
615 );
616 break;
617 }
618 $stmt = $pdo->prepare("INSERT INTO `tags_domain` (`domain`, `tag_name`) VALUES (:domain, :tag_name)");
619 $stmt->execute(array(
620 ':domain' => $domain,
621 ':tag_name' => $tag,
622 ));
623 }
624
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100625 try {
626 $redis->hSet('DOMAIN_MAP', $domain, 1);
627 }
628 catch (RedisException $e) {
629 $_SESSION['return'][] = array(
630 'type' => 'danger',
631 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
632 'msg' => array('redis_error', $e)
633 );
634 return false;
635 }
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +0100636 $_data['rl_value'] = (isset($_data['rl_value'])) ? intval($_data['rl_value']) : $DOMAIN_DEFAULT_ATTRIBUTES['rl_value'];
637 $_data['rl_frame'] = (isset($_data['rl_frame'])) ? $_data['rl_frame'] : $DOMAIN_DEFAULT_ATTRIBUTES['rl_frame'];
638 if (!empty($_data['rl_value']) && !empty($_data['rl_frame'])){
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100639 ratelimit('edit', 'domain', array('rl_value' => $_data['rl_value'], 'rl_frame' => $_data['rl_frame'], 'object' => $domain));
640 }
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +0100641 $_data['key_size'] = (isset($_data['key_size'])) ? intval($_data['key_size']) : $DOMAIN_DEFAULT_ATTRIBUTES['key_size'];
642 $_data['dkim_selector'] = (isset($_data['dkim_selector'])) ? $_data['dkim_selector'] : $DOMAIN_DEFAULT_ATTRIBUTES['dkim_selector'];
Matthias Andreas Benkardb4b5cc12021-12-28 18:02:04 +0100643 if (!empty($_data['key_size']) && !empty($_data['dkim_selector'])) {
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100644 if (!empty($redis->hGet('DKIM_SELECTORS', $domain))) {
645 $_SESSION['return'][] = array(
646 'type' => 'success',
647 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
648 'msg' => 'domain_add_dkim_available'
649 );
650 }
651 else {
652 dkim('add', array('key_size' => $_data['key_size'], 'dkim_selector' => $_data['dkim_selector'], 'domains' => $domain));
653 }
Matthias Andreas Benkardb4b5cc12021-12-28 18:02:04 +0100654 }
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100655 if (!empty($restart_sogo)) {
656 $restart_response = json_decode(docker('post', 'sogo-mailcow', 'restart'), true);
657 if ($restart_response['type'] == "success") {
658 $_SESSION['return'][] = array(
659 'type' => 'success',
660 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
661 'msg' => array('domain_added', htmlspecialchars($domain))
662 );
663 return true;
664 }
665 else {
666 $_SESSION['return'][] = array(
667 'type' => 'warning',
668 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
669 'msg' => 'domain_added_sogo_failed'
670 );
671 return false;
672 }
673 }
674 $_SESSION['return'][] = array(
675 'type' => 'success',
676 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
677 'msg' => array('domain_added', htmlspecialchars($domain))
678 );
679 return true;
680 break;
681 case 'alias':
682 $addresses = array_map('trim', preg_split( "/( |,|;|\n)/", $_data['address']));
683 $gotos = array_map('trim', preg_split( "/( |,|;|\n)/", $_data['goto']));
684 $active = intval($_data['active']);
685 $sogo_visible = intval($_data['sogo_visible']);
686 $goto_null = intval($_data['goto_null']);
687 $goto_spam = intval($_data['goto_spam']);
688 $goto_ham = intval($_data['goto_ham']);
689 $private_comment = $_data['private_comment'];
690 $public_comment = $_data['public_comment'];
691 if (strlen($private_comment) > 160 | strlen($public_comment) > 160){
692 $_SESSION['return'][] = array(
693 'type' => 'danger',
694 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
695 'msg' => 'comment_too_long'
696 );
697 return false;
698 }
699 if (empty($addresses[0])) {
700 $_SESSION['return'][] = array(
701 'type' => 'danger',
702 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
703 'msg' => 'alias_empty'
704 );
705 return false;
706 }
707 if (empty($gotos[0]) && ($goto_null + $goto_spam + $goto_ham == 0)) {
708 $_SESSION['return'][] = array(
709 'type' => 'danger',
710 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
711 'msg' => 'goto_empty'
712 );
713 return false;
714 }
715 if ($goto_null == "1") {
716 $goto = "null@localhost";
717 }
718 elseif ($goto_spam == "1") {
719 $goto = "spam@localhost";
720 }
721 elseif ($goto_ham == "1") {
722 $goto = "ham@localhost";
723 }
724 else {
725 foreach ($gotos as $i => &$goto) {
726 if (empty($goto)) {
727 continue;
728 }
729 $goto_domain = idn_to_ascii(substr(strstr($goto, '@'), 1), 0, INTL_IDNA_VARIANT_UTS46);
730 $goto_local_part = strstr($goto, '@', true);
731 $goto = $goto_local_part.'@'.$goto_domain;
732 $stmt = $pdo->prepare("SELECT `username` FROM `mailbox`
733 WHERE `kind` REGEXP 'location|thing|group'
734 AND `username`= :goto");
735 $stmt->execute(array(':goto' => $goto));
736 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
737 if ($num_results != 0) {
738 $_SESSION['return'][] = array(
739 'type' => 'danger',
740 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
741 'msg' => array('goto_invalid', htmlspecialchars($goto))
742 );
743 unset($gotos[$i]);
744 continue;
745 }
746 if (!filter_var($goto, FILTER_VALIDATE_EMAIL) === true) {
747 $_SESSION['return'][] = array(
748 'type' => 'danger',
749 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
750 'msg' => array('goto_invalid', htmlspecialchars($goto))
751 );
752 unset($gotos[$i]);
753 continue;
754 }
755 }
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +0200756 $gotos = array_unique($gotos);
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100757 $gotos = array_filter($gotos);
758 if (empty($gotos)) { return false; }
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +0200759 $goto = implode(",", (array)$gotos);
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100760 }
761 foreach ($addresses as $address) {
762 if (empty($address)) {
763 continue;
764 }
765 if (in_array($address, $gotos)) {
766 continue;
767 }
768 $domain = idn_to_ascii(substr(strstr($address, '@'), 1), 0, INTL_IDNA_VARIANT_UTS46);
769 $local_part = strstr($address, '@', true);
770 $address = $local_part.'@'.$domain;
771 $domaindata = mailbox('get', 'domain_details', $domain);
772 if (is_array($domaindata) && $domaindata['aliases_left'] == "0") {
773 $_SESSION['return'][] = array(
774 'type' => 'danger',
775 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
776 'msg' => 'max_alias_exceeded'
777 );
778 return false;
779 }
780 $stmt = $pdo->prepare("SELECT `address` FROM `alias`
781 WHERE `address`= :address OR `address` IN (
782 SELECT `username` FROM `mailbox`, `alias_domain`
783 WHERE (
784 `alias_domain`.`alias_domain` = :address_d
785 AND `mailbox`.`username` = CONCAT(:address_l, '@', alias_domain.target_domain)))");
786 $stmt->execute(array(
787 ':address' => $address,
788 ':address_l' => $local_part,
789 ':address_d' => $domain
790 ));
791 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
792 if ($num_results != 0) {
793 $_SESSION['return'][] = array(
794 'type' => 'danger',
795 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
796 'msg' => array('is_alias_or_mailbox', htmlspecialchars($address))
797 );
798 continue;
799 }
800 $stmt = $pdo->prepare("SELECT `domain` FROM `domain`
801 WHERE `domain`= :domain1 OR `domain` = (SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :domain2)");
802 $stmt->execute(array(':domain1' => $domain, ':domain2' => $domain));
803 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
804 if ($num_results == 0) {
805 $_SESSION['return'][] = array(
806 'type' => 'danger',
807 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
808 'msg' => array('domain_not_found', htmlspecialchars($domain))
809 );
810 continue;
811 }
812 $stmt = $pdo->prepare("SELECT `address` FROM `spamalias`
813 WHERE `address`= :address");
814 $stmt->execute(array(':address' => $address));
815 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
816 if ($num_results != 0) {
817 $_SESSION['return'][] = array(
818 'type' => 'danger',
819 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
820 'msg' => array('is_spam_alias', htmlspecialchars($address))
821 );
822 continue;
823 }
824 if ((!filter_var($address, FILTER_VALIDATE_EMAIL) === true) && !empty($local_part)) {
825 $_SESSION['return'][] = array(
826 'type' => 'danger',
827 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
828 'msg' => array('alias_invalid', $address)
829 );
830 continue;
831 }
832 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
833 $_SESSION['return'][] = array(
834 'type' => 'danger',
835 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
836 'msg' => 'access_denied'
837 );
838 continue;
839 }
840 $stmt = $pdo->prepare("INSERT INTO `alias` (`address`, `public_comment`, `private_comment`, `goto`, `domain`, `sogo_visible`, `active`)
841 VALUES (:address, :public_comment, :private_comment, :goto, :domain, :sogo_visible, :active)");
842 if (!filter_var($address, FILTER_VALIDATE_EMAIL) === true) {
843 $stmt->execute(array(
844 ':address' => '@'.$domain,
845 ':public_comment' => $public_comment,
846 ':private_comment' => $private_comment,
847 ':address' => '@'.$domain,
848 ':goto' => $goto,
849 ':domain' => $domain,
850 ':sogo_visible' => $sogo_visible,
851 ':active' => $active
852 ));
853 }
854 else {
855 $stmt->execute(array(
856 ':address' => $address,
857 ':public_comment' => $public_comment,
858 ':private_comment' => $private_comment,
859 ':goto' => $goto,
860 ':domain' => $domain,
861 ':sogo_visible' => $sogo_visible,
862 ':active' => $active
863 ));
864 }
865 $id = $pdo->lastInsertId();
866 $_SESSION['return'][] = array(
867 'type' => 'success',
868 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
869 'msg' => array('alias_added', $address, $id)
870 );
871 }
872 break;
873 case 'alias_domain':
874 $active = intval($_data['active']);
875 $alias_domains = array_map('trim', preg_split( "/( |,|;|\n)/", $_data['alias_domain']));
876 $alias_domains = array_filter($alias_domains);
877 $target_domain = idn_to_ascii(strtolower(trim($_data['target_domain'])), 0, INTL_IDNA_VARIANT_UTS46);
878 if (!isset($_SESSION['acl']['alias_domains']) || $_SESSION['acl']['alias_domains'] != "1" ) {
879 $_SESSION['return'][] = array(
880 'type' => 'danger',
881 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
882 'msg' => 'access_denied'
883 );
884 return false;
885 }
886 if (!is_valid_domain_name($target_domain)) {
887 $_SESSION['return'][] = array(
888 'type' => 'danger',
889 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
890 'msg' => 'target_domain_invalid'
891 );
892 return false;
893 }
894 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $target_domain)) {
895 $_SESSION['return'][] = array(
896 'type' => 'danger',
897 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
898 'msg' => 'access_denied'
899 );
900 return false;
901 }
902 foreach ($alias_domains as $i => $alias_domain) {
903 $alias_domain = idn_to_ascii(strtolower(trim($alias_domain)), 0, INTL_IDNA_VARIANT_UTS46);
904 if (!is_valid_domain_name($alias_domain)) {
905 $_SESSION['return'][] = array(
906 'type' => 'danger',
907 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
908 'msg' => array('alias_domain_invalid', htmlspecialchars(alias_domain))
909 );
910 continue;
911 }
912 if ($alias_domain == $target_domain) {
913 $_SESSION['return'][] = array(
914 'type' => 'danger',
915 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
916 'msg' => array('aliasd_targetd_identical', htmlspecialchars($target_domain))
917 );
918 continue;
919 }
920 $stmt = $pdo->prepare("SELECT `domain` FROM `domain`
921 WHERE `domain`= :target_domain");
922 $stmt->execute(array(':target_domain' => $target_domain));
923 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
924 if ($num_results == 0) {
925 $_SESSION['return'][] = array(
926 'type' => 'danger',
927 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
928 'msg' => array('targetd_not_found', htmlspecialchars($target_domain))
929 );
930 continue;
931 }
932 $stmt = $pdo->prepare("SELECT `domain` FROM `domain`
933 WHERE `domain`= :target_domain AND `backupmx` = '1'");
934 $stmt->execute(array(':target_domain' => $target_domain));
935 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
936 if ($num_results == 1) {
937 $_SESSION['return'][] = array(
938 'type' => 'danger',
939 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
940 'msg' => array('targetd_relay_domain', htmlspecialchars($target_domain))
941 );
942 continue;
943 }
944 $stmt = $pdo->prepare("SELECT `alias_domain` FROM `alias_domain` WHERE `alias_domain`= :alias_domain
945 UNION
946 SELECT `domain` FROM `domain` WHERE `domain`= :alias_domain_in_domain");
947 $stmt->execute(array(':alias_domain' => $alias_domain, ':alias_domain_in_domain' => $alias_domain));
948 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
949 if ($num_results != 0) {
950 $_SESSION['return'][] = array(
951 'type' => 'danger',
952 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
953 'msg' => array('alias_domain_invalid', $alias_domain)
954 );
955 continue;
956 }
957 $stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `external` = 1 AND `send_as` LIKE :domain");
958 $stmt->execute(array(
959 ':domain' => '%@' . $domain
960 ));
961 $stmt = $pdo->prepare("INSERT INTO `alias_domain` (`alias_domain`, `target_domain`, `active`)
962 VALUES (:alias_domain, :target_domain, :active)");
963 $stmt->execute(array(
964 ':alias_domain' => $alias_domain,
965 ':target_domain' => $target_domain,
966 ':active' => $active
967 ));
968 try {
969 $redis->hSet('DOMAIN_MAP', $alias_domain, 1);
970 }
971 catch (RedisException $e) {
972 $_SESSION['return'][] = array(
973 'type' => 'danger',
974 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
975 'msg' => array('redis_error', $e)
976 );
977 return false;
978 }
979 if (!empty(intval($_data['rl_value']))) {
980 ratelimit('edit', 'domain', array('rl_value' => $_data['rl_value'], 'rl_frame' => $_data['rl_frame'], 'object' => $alias_domain));
981 }
Matthias Andreas Benkardb4b5cc12021-12-28 18:02:04 +0100982 if (!empty($_data['key_size']) && !empty($_data['dkim_selector'])) {
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +0100983 if (!empty($redis->hGet('DKIM_SELECTORS', $alias_domain))) {
984 $_SESSION['return'][] = array(
985 'type' => 'success',
986 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
987 'msg' => 'domain_add_dkim_available'
988 );
989 }
990 else {
991 dkim('add', array('key_size' => $_data['key_size'], 'dkim_selector' => $_data['dkim_selector'], 'domains' => $alias_domain));
992 }
Matthias Andreas Benkardb4b5cc12021-12-28 18:02:04 +0100993 }
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +0100994 $_SESSION['return'][] = array(
995 'type' => 'success',
996 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
997 'msg' => array('aliasd_added', htmlspecialchars($alias_domain))
998 );
999 }
1000 break;
1001 case 'mailbox':
1002 $local_part = strtolower(trim($_data['local_part']));
1003 $domain = idn_to_ascii(strtolower(trim($_data['domain'])), 0, INTL_IDNA_VARIANT_UTS46);
1004 $username = $local_part . '@' . $domain;
1005 if (!filter_var($username, FILTER_VALIDATE_EMAIL)) {
1006 $_SESSION['return'][] = array(
1007 'type' => 'danger',
1008 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1009 'msg' => 'mailbox_invalid'
1010 );
1011 return false;
1012 }
1013 if (empty($_data['local_part'])) {
1014 $_SESSION['return'][] = array(
1015 'type' => 'danger',
1016 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1017 'msg' => 'mailbox_invalid'
1018 );
1019 return false;
1020 }
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01001021 if (empty($name)) {
1022 $name = $local_part;
1023 }
1024 $template_attr = null;
1025 if ($_data['template']){
1026 $template_attr = mailbox('get', 'mailbox_templates', $_data['template'])['attributes'];
1027 }
1028 if (empty($template_attr)) {
1029 $template_attr = mailbox('get', 'mailbox_templates')[0]['attributes'];
1030 }
1031 $MAILBOX_DEFAULT_ATTRIBUTES = array_merge($MAILBOX_DEFAULT_ATTRIBUTES, $template_attr);
1032
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001033 $password = $_data['password'];
1034 $password2 = $_data['password2'];
1035 $name = ltrim(rtrim($_data['name'], '>'), '<');
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01001036 $tags = (isset($_data['tags'])) ? $_data['tags'] : $MAILBOX_DEFAULT_ATTRIBUTES['tags'];
1037 $quota_m = (isset($_data['quota'])) ? intval($_data['quota']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['quota']) / 1024 ** 2;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001038 if ((!isset($_SESSION['acl']['unlimited_quota']) || $_SESSION['acl']['unlimited_quota'] != "1") && $quota_m === 0) {
1039 $_SESSION['return'][] = array(
1040 'type' => 'danger',
1041 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1042 'msg' => 'unlimited_quota_acl'
1043 );
1044 return false;
1045 }
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01001046
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001047 if (isset($_data['protocol_access'])) {
1048 $_data['protocol_access'] = (array)$_data['protocol_access'];
1049 $_data['imap_access'] = (in_array('imap', $_data['protocol_access'])) ? 1 : 0;
1050 $_data['pop3_access'] = (in_array('pop3', $_data['protocol_access'])) ? 1 : 0;
1051 $_data['smtp_access'] = (in_array('smtp', $_data['protocol_access'])) ? 1 : 0;
1052 $_data['sieve_access'] = (in_array('sieve', $_data['protocol_access'])) ? 1 : 0;
1053 }
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01001054 $active = (isset($_data['active'])) ? intval($_data['active']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['active']);
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001055 $force_pw_update = (isset($_data['force_pw_update'])) ? intval($_data['force_pw_update']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['force_pw_update']);
1056 $tls_enforce_in = (isset($_data['tls_enforce_in'])) ? intval($_data['tls_enforce_in']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_in']);
1057 $tls_enforce_out = (isset($_data['tls_enforce_out'])) ? intval($_data['tls_enforce_out']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_out']);
1058 $sogo_access = (isset($_data['sogo_access'])) ? intval($_data['sogo_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['sogo_access']);
1059 $imap_access = (isset($_data['imap_access'])) ? intval($_data['imap_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['imap_access']);
1060 $pop3_access = (isset($_data['pop3_access'])) ? intval($_data['pop3_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['pop3_access']);
1061 $smtp_access = (isset($_data['smtp_access'])) ? intval($_data['smtp_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['smtp_access']);
Matthias Andreas Benkardb4b5cc12021-12-28 18:02:04 +01001062 $sieve_access = (isset($_data['sieve_access'])) ? intval($_data['sieve_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['sieve_access']);
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02001063 $relayhost = (isset($_data['relayhost'])) ? intval($_data['relayhost']) : 0;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001064 $quarantine_notification = (isset($_data['quarantine_notification'])) ? strval($_data['quarantine_notification']) : strval($MAILBOX_DEFAULT_ATTRIBUTES['quarantine_notification']);
1065 $quarantine_category = (isset($_data['quarantine_category'])) ? strval($_data['quarantine_category']) : strval($MAILBOX_DEFAULT_ATTRIBUTES['quarantine_category']);
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02001066 $quota_b = ($quota_m * 1048576);
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001067 $mailbox_attrs = json_encode(
1068 array(
1069 'force_pw_update' => strval($force_pw_update),
1070 'tls_enforce_in' => strval($tls_enforce_in),
1071 'tls_enforce_out' => strval($tls_enforce_out),
1072 'sogo_access' => strval($sogo_access),
1073 'imap_access' => strval($imap_access),
1074 'pop3_access' => strval($pop3_access),
1075 'smtp_access' => strval($smtp_access),
Matthias Andreas Benkardb4b5cc12021-12-28 18:02:04 +01001076 'sieve_access' => strval($sieve_access),
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02001077 'relayhost' => strval($relayhost),
1078 'passwd_update' => time(),
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001079 'mailbox_format' => strval($MAILBOX_DEFAULT_ATTRIBUTES['mailbox_format']),
1080 'quarantine_notification' => strval($quarantine_notification),
1081 'quarantine_category' => strval($quarantine_category)
1082 )
1083 );
1084 if (!is_valid_domain_name($domain)) {
1085 $_SESSION['return'][] = array(
1086 'type' => 'danger',
1087 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1088 'msg' => 'domain_invalid'
1089 );
1090 return false;
1091 }
1092 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
1093 $_SESSION['return'][] = array(
1094 'type' => 'danger',
1095 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1096 'msg' => 'access_denied'
1097 );
1098 return false;
1099 }
1100 $stmt = $pdo->prepare("SELECT `mailboxes`, `maxquota`, `quota` FROM `domain`
1101 WHERE `domain` = :domain");
1102 $stmt->execute(array(':domain' => $domain));
1103 $DomainData = $stmt->fetch(PDO::FETCH_ASSOC);
1104 $stmt = $pdo->prepare("SELECT
1105 COUNT(*) as count,
1106 COALESCE(ROUND(SUM(`quota`)/1048576), 0) as `quota`
1107 FROM `mailbox`
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02001108 WHERE (`kind` = '' OR `kind` = NULL)
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001109 AND `domain` = :domain");
1110 $stmt->execute(array(':domain' => $domain));
1111 $MailboxData = $stmt->fetch(PDO::FETCH_ASSOC);
1112 $stmt = $pdo->prepare("SELECT `local_part` FROM `mailbox` WHERE `local_part` = :local_part and `domain`= :domain");
1113 $stmt->execute(array(':local_part' => $local_part, ':domain' => $domain));
1114 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
1115 if ($num_results != 0) {
1116 $_SESSION['return'][] = array(
1117 'type' => 'danger',
1118 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1119 'msg' => array('object_exists', htmlspecialchars($username))
1120 );
1121 return false;
1122 }
1123 $stmt = $pdo->prepare("SELECT `address` FROM `alias` WHERE address= :username");
1124 $stmt->execute(array(':username' => $username));
1125 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
1126 if ($num_results != 0) {
1127 $_SESSION['return'][] = array(
1128 'type' => 'danger',
1129 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1130 'msg' => array('is_alias', htmlspecialchars($username))
1131 );
1132 return false;
1133 }
1134 $stmt = $pdo->prepare("SELECT `address` FROM `spamalias` WHERE `address`= :username");
1135 $stmt->execute(array(':username' => $username));
1136 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
1137 if ($num_results != 0) {
1138 $_SESSION['return'][] = array(
1139 'type' => 'danger',
1140 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1141 'msg' => array('is_spam_alias', htmlspecialchars($username))
1142 );
1143 return false;
1144 }
1145 $stmt = $pdo->prepare("SELECT `domain` FROM `domain` WHERE `domain`= :domain");
1146 $stmt->execute(array(':domain' => $domain));
1147 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
1148 if ($num_results == 0) {
1149 $_SESSION['return'][] = array(
1150 'type' => 'danger',
1151 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1152 'msg' => array('domain_not_found', htmlspecialchars($domain))
1153 );
1154 return false;
1155 }
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02001156 if (password_check($password, $password2) !== true) {
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001157 return false;
1158 }
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02001159 $password_hashed = hash_password($password);
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001160 if ($MailboxData['count'] >= $DomainData['mailboxes']) {
1161 $_SESSION['return'][] = array(
1162 'type' => 'danger',
1163 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1164 'msg' => array('max_mailbox_exceeded', $MailboxData['count'], $DomainData['mailboxes'])
1165 );
1166 return false;
1167 }
1168 if ($quota_m > $DomainData['maxquota']) {
1169 $_SESSION['return'][] = array(
1170 'type' => 'danger',
1171 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1172 'msg' => array('mailbox_quota_exceeded', $DomainData['maxquota'])
1173 );
1174 return false;
1175 }
1176 if (($MailboxData['quota'] + $quota_m) > $DomainData['quota']) {
1177 $quota_left_m = ($DomainData['quota'] - $MailboxData['quota']);
1178 $_SESSION['return'][] = array(
1179 'type' => 'danger',
1180 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1181 'msg' => array('mailbox_quota_left_exceeded', $quota_left_m)
1182 );
1183 return false;
1184 }
1185 $stmt = $pdo->prepare("INSERT INTO `mailbox` (`username`, `password`, `name`, `quota`, `local_part`, `domain`, `attributes`, `active`)
1186 VALUES (:username, :password_hashed, :name, :quota_b, :local_part, :domain, :mailbox_attrs, :active)");
1187 $stmt->execute(array(
1188 ':username' => $username,
1189 ':password_hashed' => $password_hashed,
1190 ':name' => $name,
1191 ':quota_b' => $quota_b,
1192 ':local_part' => $local_part,
1193 ':domain' => $domain,
1194 ':mailbox_attrs' => $mailbox_attrs,
1195 ':active' => $active
1196 ));
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02001197 $stmt = $pdo->prepare("UPDATE `mailbox` SET
1198 `attributes` = JSON_SET(`attributes`, '$.passwd_update', NOW())
1199 WHERE `username` = :username");
1200 $stmt->execute(array(
1201 ':username' => $username
1202 ));
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001203 // save tags
1204 foreach($tags as $index => $tag){
1205 if (empty($tag)) continue;
1206 if ($index > $GLOBALS['TAGGING_LIMIT']) {
1207 $_SESSION['return'][] = array(
1208 'type' => 'warning',
1209 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1210 'msg' => array('tag_limit_exceeded', 'limit '.$GLOBALS['TAGGING_LIMIT'])
1211 );
1212 break;
1213 }
1214 $stmt = $pdo->prepare("INSERT INTO `tags_mailbox` (`username`, `tag_name`) VALUES (:username, :tag_name)");
1215 $stmt->execute(array(
1216 ':username' => $username,
1217 ':tag_name' => $tag,
1218 ));
1219 }
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001220 $stmt = $pdo->prepare("INSERT INTO `quota2` (`username`, `bytes`, `messages`)
1221 VALUES (:username, '0', '0') ON DUPLICATE KEY UPDATE `bytes` = '0', `messages` = '0';");
1222 $stmt->execute(array(':username' => $username));
1223 $stmt = $pdo->prepare("INSERT INTO `quota2replica` (`username`, `bytes`, `messages`)
1224 VALUES (:username, '0', '0') ON DUPLICATE KEY UPDATE `bytes` = '0', `messages` = '0';");
1225 $stmt->execute(array(':username' => $username));
1226 $stmt = $pdo->prepare("INSERT INTO `alias` (`address`, `goto`, `domain`, `active`)
1227 VALUES (:username1, :username2, :domain, :active)");
1228 $stmt->execute(array(
1229 ':username1' => $username,
1230 ':username2' => $username,
1231 ':domain' => $domain,
1232 ':active' => $active
1233 ));
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001234
1235
1236 if (isset($_data['acl'])) {
1237 $_data['acl'] = (array)$_data['acl'];
1238 $_data['spam_alias'] = (in_array('spam_alias', $_data['acl'])) ? 1 : 0;
1239 $_data['tls_policy'] = (in_array('tls_policy', $_data['acl'])) ? 1 : 0;
1240 $_data['spam_score'] = (in_array('spam_score', $_data['acl'])) ? 1 : 0;
1241 $_data['spam_policy'] = (in_array('spam_policy', $_data['acl'])) ? 1 : 0;
1242 $_data['delimiter_action'] = (in_array('delimiter_action', $_data['acl'])) ? 1 : 0;
1243 $_data['syncjobs'] = (in_array('syncjobs', $_data['acl'])) ? 1 : 0;
1244 $_data['eas_reset'] = (in_array('eas_reset', $_data['acl'])) ? 1 : 0;
1245 $_data['sogo_profile_reset'] = (in_array('sogo_profile_reset', $_data['acl'])) ? 1 : 0;
1246 $_data['pushover'] = (in_array('pushover', $_data['acl'])) ? 1 : 0;
1247 $_data['quarantine'] = (in_array('quarantine', $_data['acl'])) ? 1 : 0;
1248 $_data['quarantine_attachments'] = (in_array('quarantine_attachments', $_data['acl'])) ? 1 : 0;
1249 $_data['quarantine_notification'] = (in_array('quarantine_notification', $_data['acl'])) ? 1 : 0;
1250 $_data['quarantine_category'] = (in_array('quarantine_category', $_data['acl'])) ? 1 : 0;
1251 $_data['app_passwds'] = (in_array('app_passwds', $_data['acl'])) ? 1 : 0;
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01001252 } else {
1253 $_data['spam_alias'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_spam_alias']);
1254 $_data['tls_policy'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_tls_policy']);
1255 $_data['spam_score'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_spam_score']);
1256 $_data['spam_policy'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_spam_policy']);
1257 $_data['delimiter_action'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_delimiter_action']);
1258 $_data['syncjobs'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_syncjobs']);
1259 $_data['eas_reset'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_eas_reset']);
1260 $_data['sogo_profile_reset'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_sogo_profile_reset']);
1261 $_data['pushover'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_pushover']);
1262 $_data['quarantine'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_quarantine']);
1263 $_data['quarantine_attachments'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_quarantine_attachments']);
1264 $_data['quarantine_notification'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_quarantine_notification']);
1265 $_data['quarantine_category'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_quarantine_category']);
1266 $_data['app_passwds'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_app_passwds']);
1267 }
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001268
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01001269 try {
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001270 $stmt = $pdo->prepare("INSERT INTO `user_acl`
1271 (`username`, `spam_alias`, `tls_policy`, `spam_score`, `spam_policy`, `delimiter_action`, `syncjobs`, `eas_reset`, `sogo_profile_reset`,
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01001272 `pushover`, `quarantine`, `quarantine_attachments`, `quarantine_notification`, `quarantine_category`, `app_passwds`)
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001273 VALUES (:username, :spam_alias, :tls_policy, :spam_score, :spam_policy, :delimiter_action, :syncjobs, :eas_reset, :sogo_profile_reset,
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01001274 :pushover, :quarantine, :quarantine_attachments, :quarantine_notification, :quarantine_category, :app_passwds) ");
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001275 $stmt->execute(array(
1276 ':username' => $username,
1277 ':spam_alias' => $_data['spam_alias'],
1278 ':tls_policy' => $_data['tls_policy'],
1279 ':spam_score' => $_data['spam_score'],
1280 ':spam_policy' => $_data['spam_policy'],
1281 ':delimiter_action' => $_data['delimiter_action'],
1282 ':syncjobs' => $_data['syncjobs'],
1283 ':eas_reset' => $_data['eas_reset'],
1284 ':sogo_profile_reset' => $_data['sogo_profile_reset'],
1285 ':pushover' => $_data['pushover'],
1286 ':quarantine' => $_data['quarantine'],
1287 ':quarantine_attachments' => $_data['quarantine_attachments'],
1288 ':quarantine_notification' => $_data['quarantine_notification'],
1289 ':quarantine_category' => $_data['quarantine_category'],
1290 ':app_passwds' => $_data['app_passwds']
1291 ));
1292 }
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01001293 catch (PDOException $e) {
1294 $_SESSION['return'][] = array(
1295 'type' => 'danger',
1296 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1297 'msg' => $e->getMessage()
1298 );
1299 return false;
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001300 }
1301
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01001302 $_data['rl_frame'] = (isset($_data['rl_frame'])) ? $_data['rl_frame'] : $MAILBOX_DEFAULT_ATTRIBUTES['rl_frame'];
1303 $_data['rl_value'] = (isset($_data['rl_value'])) ? $_data['rl_value'] : $MAILBOX_DEFAULT_ATTRIBUTES['rl_value'];
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001304 if (isset($_data['rl_frame']) && isset($_data['rl_value'])){
1305 ratelimit('edit', 'mailbox', array(
1306 'object' => $username,
1307 'rl_frame' => $_data['rl_frame'],
1308 'rl_value' => $_data['rl_value']
1309 ));
1310 }
1311
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01001312 update_sogo_static_view($username);
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001313 $_SESSION['return'][] = array(
1314 'type' => 'success',
1315 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1316 'msg' => array('mailbox_added', htmlspecialchars($username))
1317 );
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01001318 return true;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001319 break;
1320 case 'resource':
1321 $domain = idn_to_ascii(strtolower(trim($_data['domain'])), 0, INTL_IDNA_VARIANT_UTS46);
1322 $description = $_data['description'];
1323 $local_part = preg_replace('/[^\da-z]/i', '', preg_quote($description, '/'));
1324 $name = $local_part . '@' . $domain;
1325 $kind = $_data['kind'];
1326 $multiple_bookings = intval($_data['multiple_bookings']);
1327 $active = intval($_data['active']);
1328 if (!filter_var($name, FILTER_VALIDATE_EMAIL)) {
1329 $_SESSION['return'][] = array(
1330 'type' => 'danger',
1331 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1332 'msg' => 'resource_invalid'
1333 );
1334 return false;
1335 }
1336 if (empty($description)) {
1337 $_SESSION['return'][] = array(
1338 'type' => 'danger',
1339 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1340 'msg' => 'description_invalid'
1341 );
1342 return false;
1343 }
1344 if (!isset($multiple_bookings) || $multiple_bookings < -1) {
1345 $multiple_bookings = -1;
1346 }
1347 if ($kind != 'location' && $kind != 'group' && $kind != 'thing') {
1348 $_SESSION['return'][] = array(
1349 'type' => 'danger',
1350 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1351 'msg' => 'resource_invalid'
1352 );
1353 return false;
1354 }
1355 if (!is_valid_domain_name($domain)) {
1356 $_SESSION['return'][] = array(
1357 'type' => 'danger',
1358 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1359 'msg' => 'domain_invalid'
1360 );
1361 return false;
1362 }
1363 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
1364 $_SESSION['return'][] = array(
1365 'type' => 'danger',
1366 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1367 'msg' => 'access_denied'
1368 );
1369 return false;
1370 }
1371 $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `username` = :name");
1372 $stmt->execute(array(':name' => $name));
1373 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
1374 if ($num_results != 0) {
1375 $_SESSION['return'][] = array(
1376 'type' => 'danger',
1377 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1378 'msg' => array('object_exists', htmlspecialchars($name))
1379 );
1380 return false;
1381 }
1382 $stmt = $pdo->prepare("SELECT `address` FROM `alias` WHERE address= :name");
1383 $stmt->execute(array(':name' => $name));
1384 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
1385 if ($num_results != 0) {
1386 $_SESSION['return'][] = array(
1387 'type' => 'danger',
1388 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1389 'msg' => array('is_alias', htmlspecialchars($name))
1390 );
1391 return false;
1392 }
1393 $stmt = $pdo->prepare("SELECT `address` FROM `spamalias` WHERE `address`= :name");
1394 $stmt->execute(array(':name' => $name));
1395 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
1396 if ($num_results != 0) {
1397 $_SESSION['return'][] = array(
1398 'type' => 'danger',
1399 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1400 'msg' => array('is_spam_alias', htmlspecialchars($name))
1401 );
1402 return false;
1403 }
1404 $stmt = $pdo->prepare("SELECT `domain` FROM `domain` WHERE `domain`= :domain");
1405 $stmt->execute(array(':domain' => $domain));
1406 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
1407 if ($num_results == 0) {
1408 $_SESSION['return'][] = array(
1409 'type' => 'danger',
1410 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1411 'msg' => array('domain_not_found', htmlspecialchars($domain))
1412 );
1413 return false;
1414 }
1415 $stmt = $pdo->prepare("INSERT INTO `mailbox` (`username`, `password`, `name`, `quota`, `local_part`, `domain`, `active`, `multiple_bookings`, `kind`)
1416 VALUES (:name, 'RESOURCE', :description, 0, :local_part, :domain, :active, :multiple_bookings, :kind)");
1417 $stmt->execute(array(
1418 ':name' => $name,
1419 ':description' => $description,
1420 ':local_part' => $local_part,
1421 ':domain' => $domain,
1422 ':active' => $active,
1423 ':kind' => $kind,
1424 ':multiple_bookings' => $multiple_bookings
1425 ));
1426 $_SESSION['return'][] = array(
1427 'type' => 'success',
1428 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1429 'msg' => array('resource_added', htmlspecialchars($name))
1430 );
1431 break;
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001432 case 'domain_templates':
1433 if ($_SESSION['mailcow_cc_role'] != "admin") {
1434 $_SESSION['return'][] = array(
1435 'type' => 'danger',
1436 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
1437 'msg' => 'access_denied'
1438 );
1439 return false;
1440 }
1441 if (empty($_data["template"])){
1442 $_SESSION['return'][] = array(
1443 'type' => 'danger',
1444 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
1445 'msg' => 'template_name_invalid'
1446 );
1447 return false;
1448 }
1449
1450 // check if template name exists, return false
1451 $stmt = $pdo->prepare("SELECT id FROM `templates` WHERE `type` = :type AND `template` = :template");
1452 $stmt->execute(array(
1453 ":type" => "domain",
1454 ":template" => $_data["template"]
1455 ));
1456 $row = $stmt->fetch(PDO::FETCH_ASSOC);
1457
1458 if (!empty($row)){
1459 $_SESSION['return'][] = array(
1460 'type' => 'danger',
1461 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
1462 'msg' => array('template_exists', $_data["template"])
1463 );
1464 return false;
1465 }
1466
1467 // check attributes
1468 $attr = array();
1469 $attr['tags'] = (isset($_data['tags'])) ? $_data['tags'] : array();
1470 $attr['max_num_aliases_for_domain'] = (!empty($_data['max_num_aliases_for_domain'])) ? intval($_data['max_num_aliases_for_domain']) : 400;
1471 $attr['max_num_mboxes_for_domain'] = (!empty($_data['max_num_mboxes_for_domain'])) ? intval($_data['max_num_mboxes_for_domain']) : 10;
1472 $attr['def_quota_for_mbox'] = (!empty($_data['def_quota_for_mbox'])) ? intval($_data['def_quota_for_mbox']) * 1048576 : 3072 * 1048576;
1473 $attr['max_quota_for_mbox'] = (!empty($_data['max_quota_for_mbox'])) ? intval($_data['max_quota_for_mbox']) * 1048576 : 10240 * 1048576;
1474 $attr['max_quota_for_domain'] = (!empty($_data['max_quota_for_domain'])) ? intval($_data['max_quota_for_domain']) * 1048576 : 10240 * 1048576;
1475 $attr['rl_frame'] = (!empty($_data['rl_frame'])) ? $_data['rl_frame'] : "s";
1476 $attr['rl_value'] = (!empty($_data['rl_value'])) ? $_data['rl_value'] : "";
1477 $attr['active'] = isset($_data['active']) ? intval($_data['active']) : 1;
1478 $attr['gal'] = (isset($_data['gal'])) ? intval($_data['gal']) : 1;
1479 $attr['backupmx'] = (isset($_data['backupmx'])) ? intval($_data['backupmx']) : 0;
1480 $attr['relay_all_recipients'] = (isset($_data['relay_all_recipients'])) ? intval($_data['relay_all_recipients']) : 0;
1481 $attr['relay_unknown_only'] = (isset($_data['relay_unknown_only'])) ? intval($_data['relay_unknown_only']) : 0;
1482 $attr['dkim_selector'] = (isset($_data['dkim_selector'])) ? $_data['dkim_selector'] : "dkim";
1483 $attr['key_size'] = isset($_data['key_size']) ? intval($_data['key_size']) : 2048;
1484
1485 // save template
1486 $stmt = $pdo->prepare("INSERT INTO `templates` (`type`, `template`, `attributes`)
1487 VALUES (:type, :template, :attributes)");
1488 $stmt->execute(array(
1489 ":type" => "domain",
1490 ":template" => $_data["template"],
1491 ":attributes" => json_encode($attr)
1492 ));
1493
1494 // success
1495 $_SESSION['return'][] = array(
1496 'type' => 'success',
1497 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1498 'msg' => array('template_added', $_data["template"])
1499 );
1500 return true;
1501 break;
1502 case 'mailbox_templates':
1503 if ($_SESSION['mailcow_cc_role'] != "admin") {
1504 $_SESSION['return'][] = array(
1505 'type' => 'danger',
1506 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
1507 'msg' => 'access_denied'
1508 );
1509 return false;
1510 }
1511 if (empty($_data["template"])){
1512 $_SESSION['return'][] = array(
1513 'type' => 'danger',
1514 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
1515 'msg' => 'template_name_invalid'
1516 );
1517 return false;
1518 }
1519
1520 // check if template name exists, return false
1521 $stmt = $pdo->prepare("SELECT id FROM `templates` WHERE `type` = :type AND `template` = :template");
1522 $stmt->execute(array(
1523 ":type" => "mailbox",
1524 ":template" => $_data["template"]
1525 ));
1526 $row = $stmt->fetch(PDO::FETCH_ASSOC);
1527 if (!empty($row)){
1528 $_SESSION['return'][] = array(
1529 'type' => 'danger',
1530 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
1531 'msg' => array('template_exists', $_data["template"])
1532 );
1533 return false;
1534 }
1535
1536
1537 // check attributes
1538 $attr = array();
1539 $attr["quota"] = isset($_data['quota']) ? intval($_data['quota']) * 1048576 : 0;
1540 $attr['tags'] = (isset($_data['tags'])) ? $_data['tags'] : array();
1541 $attr["quarantine_notification"] = (!empty($_data['quarantine_notification'])) ? $_data['quarantine_notification'] : strval($MAILBOX_DEFAULT_ATTRIBUTES['quarantine_notification']);
1542 $attr["quarantine_category"] = (!empty($_data['quarantine_category'])) ? $_data['quarantine_category'] : strval($MAILBOX_DEFAULT_ATTRIBUTES['quarantine_category']);
1543 $attr["rl_frame"] = (!empty($_data['rl_frame'])) ? $_data['rl_frame'] : "s";
1544 $attr["rl_value"] = (!empty($_data['rl_value'])) ? $_data['rl_value'] : "";
1545 $attr["force_pw_update"] = isset($_data['force_pw_update']) ? intval($_data['force_pw_update']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['force_pw_update']);
1546 $attr["sogo_access"] = isset($_data['sogo_access']) ? intval($_data['sogo_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['sogo_access']);
1547 $attr["active"] = isset($_data['active']) ? intval($_data['active']) : 1;
1548 $attr["tls_enforce_in"] = isset($_data['tls_enforce_in']) ? intval($_data['tls_enforce_in']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_in']);
1549 $attr["tls_enforce_out"] = isset($_data['tls_enforce_out']) ? intval($_data['tls_enforce_out']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_out']);
1550 if (isset($_data['protocol_access'])) {
1551 $_data['protocol_access'] = (array)$_data['protocol_access'];
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01001552 $attr['imap_access'] = (in_array('imap', $_data['protocol_access'])) ? 1 : 0;
1553 $attr['pop3_access'] = (in_array('pop3', $_data['protocol_access'])) ? 1 : 0;
1554 $attr['smtp_access'] = (in_array('smtp', $_data['protocol_access'])) ? 1 : 0;
1555 $attr['sieve_access'] = (in_array('sieve', $_data['protocol_access'])) ? 1 : 0;
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001556 }
1557 else {
1558 $attr['imap_access'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['imap_access']);
1559 $attr['pop3_access'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['pop3_access']);
1560 $attr['smtp_access'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['smtp_access']);
1561 $attr['sieve_access'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['sieve_access']);
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01001562 }
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001563 if (isset($_data['acl'])) {
1564 $_data['acl'] = (array)$_data['acl'];
1565 $attr['acl_spam_alias'] = (in_array('spam_alias', $_data['acl'])) ? 1 : 0;
1566 $attr['acl_tls_policy'] = (in_array('tls_policy', $_data['acl'])) ? 1 : 0;
1567 $attr['acl_spam_score'] = (in_array('spam_score', $_data['acl'])) ? 1 : 0;
1568 $attr['acl_spam_policy'] = (in_array('spam_policy', $_data['acl'])) ? 1 : 0;
1569 $attr['acl_delimiter_action'] = (in_array('delimiter_action', $_data['acl'])) ? 1 : 0;
1570 $attr['acl_syncjobs'] = (in_array('syncjobs', $_data['acl'])) ? 1 : 0;
1571 $attr['acl_eas_reset'] = (in_array('eas_reset', $_data['acl'])) ? 1 : 0;
1572 $attr['acl_sogo_profile_reset'] = (in_array('sogo_profile_reset', $_data['acl'])) ? 1 : 0;
1573 $attr['acl_pushover'] = (in_array('pushover', $_data['acl'])) ? 1 : 0;
1574 $attr['acl_quarantine'] = (in_array('quarantine', $_data['acl'])) ? 1 : 0;
1575 $attr['acl_quarantine_attachments'] = (in_array('quarantine_attachments', $_data['acl'])) ? 1 : 0;
1576 $attr['acl_quarantine_notification'] = (in_array('quarantine_notification', $_data['acl'])) ? 1 : 0;
1577 $attr['acl_quarantine_category'] = (in_array('quarantine_category', $_data['acl'])) ? 1 : 0;
1578 $attr['acl_app_passwds'] = (in_array('app_passwds', $_data['acl'])) ? 1 : 0;
1579 } else {
1580 $_data['acl'] = (array)$_data['acl'];
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01001581 $attr['acl_spam_alias'] = 0;
1582 $attr['acl_tls_policy'] = 0;
1583 $attr['acl_spam_score'] = 0;
1584 $attr['acl_spam_policy'] = 0;
1585 $attr['acl_delimiter_action'] = 0;
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001586 $attr['acl_syncjobs'] = 0;
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01001587 $attr['acl_eas_reset'] = 0;
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001588 $attr['acl_sogo_profile_reset'] = 0;
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01001589 $attr['acl_pushover'] = 0;
1590 $attr['acl_quarantine'] = 0;
1591 $attr['acl_quarantine_attachments'] = 0;
1592 $attr['acl_quarantine_notification'] = 0;
1593 $attr['acl_quarantine_category'] = 0;
1594 $attr['acl_app_passwds'] = 0;
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01001595 }
1596
1597
1598
1599 // save template
1600 $stmt = $pdo->prepare("INSERT INTO `templates` (`type`, `template`, `attributes`)
1601 VALUES (:type, :template, :attributes)");
1602 $stmt->execute(array(
1603 ":type" => "mailbox",
1604 ":template" => $_data["template"],
1605 ":attributes" => json_encode($attr)
1606 ));
1607
1608 // success
1609 $_SESSION['return'][] = array(
1610 'type' => 'success',
1611 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1612 'msg' => array('template_added', $_data["template"])
1613 );
1614 return true;
1615 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001616 }
1617 break;
1618 case 'edit':
1619 switch ($_type) {
1620 case 'alias_domain':
1621 $alias_domains = (array)$_data['alias_domain'];
1622 foreach ($alias_domains as $alias_domain) {
1623 $alias_domain = idn_to_ascii(strtolower(trim($alias_domain)), 0, INTL_IDNA_VARIANT_UTS46);
1624 $is_now = mailbox('get', 'alias_domain_details', $alias_domain);
1625 if (!empty($is_now)) {
1626 $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
1627 $target_domain = (!empty($_data['target_domain'])) ? idn_to_ascii(strtolower(trim($_data['target_domain'])), 0, INTL_IDNA_VARIANT_UTS46) : $is_now['target_domain'];
1628 }
1629 else {
1630 $_SESSION['return'][] = array(
1631 'type' => 'danger',
1632 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1633 'msg' => array('alias_domain_invalid', htmlspecialchars($alias_domain))
1634 );
1635 continue;
1636 }
1637 if (!is_valid_domain_name($target_domain)) {
1638 $_SESSION['return'][] = array(
1639 'type' => 'danger',
1640 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1641 'msg' => array('target_domain_invalid', htmlspecialchars($target_domain))
1642 );
1643 continue;
1644 }
1645 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $target_domain)) {
1646 $_SESSION['return'][] = array(
1647 'type' => 'danger',
1648 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1649 'msg' => 'access_denied'
1650 );
1651 continue;
1652 }
1653 if (empty(mailbox('get', 'domain_details', $target_domain)) || !empty(mailbox('get', 'alias_domain_details', $target_domain))) {
1654 $_SESSION['return'][] = array(
1655 'type' => 'danger',
1656 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1657 'msg' => array('target_domain_invalid', htmlspecialchars($target_domain))
1658 );
1659 continue;
1660 }
1661 $stmt = $pdo->prepare("UPDATE `alias_domain` SET
1662 `target_domain` = :target_domain,
1663 `active` = :active
1664 WHERE `alias_domain` = :alias_domain");
1665 $stmt->execute(array(
1666 ':alias_domain' => $alias_domain,
1667 ':target_domain' => $target_domain,
1668 ':active' => $active
1669 ));
1670 $_SESSION['return'][] = array(
1671 'type' => 'success',
1672 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1673 'msg' => array('aliasd_modified', htmlspecialchars($alias_domain))
1674 );
1675 }
1676 break;
1677 case 'tls_policy':
1678 if (!is_array($_data['username'])) {
1679 $usernames = array();
1680 $usernames[] = $_data['username'];
1681 }
1682 else {
1683 $usernames = $_data['username'];
1684 }
1685 if (!isset($_SESSION['acl']['tls_policy']) || $_SESSION['acl']['tls_policy'] != "1" ) {
1686 $_SESSION['return'][] = array(
1687 'type' => 'danger',
1688 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1689 'msg' => 'access_denied'
1690 );
1691 return false;
1692 }
1693 foreach ($usernames as $username) {
1694 if (!filter_var($username, FILTER_VALIDATE_EMAIL) || !hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
1695 $_SESSION['return'][] = array(
1696 'type' => 'danger',
1697 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1698 'msg' => 'access_denied'
1699 );
1700 continue;
1701 }
1702 $is_now = mailbox('get', 'tls_policy', $username);
1703 if (!empty($is_now)) {
1704 $tls_enforce_in = (isset($_data['tls_enforce_in'])) ? intval($_data['tls_enforce_in']) : $is_now['tls_enforce_in'];
1705 $tls_enforce_out = (isset($_data['tls_enforce_out'])) ? intval($_data['tls_enforce_out']) : $is_now['tls_enforce_out'];
1706 }
1707 else {
1708 $_SESSION['return'][] = array(
1709 'type' => 'danger',
1710 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1711 'msg' => 'access_denied'
1712 );
1713 continue;
1714 }
1715 $stmt = $pdo->prepare("UPDATE `mailbox`
1716 SET `attributes` = JSON_SET(`attributes`, '$.tls_enforce_out', :tls_out),
1717 `attributes` = JSON_SET(`attributes`, '$.tls_enforce_in', :tls_in)
1718 WHERE `username` = :username");
1719 $stmt->execute(array(
1720 ':tls_out' => intval($tls_enforce_out),
1721 ':tls_in' => intval($tls_enforce_in),
1722 ':username' => $username
1723 ));
1724 $_SESSION['return'][] = array(
1725 'type' => 'success',
1726 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1727 'msg' => array('mailbox_modified', $username)
1728 );
1729 }
1730 break;
1731 case 'quarantine_notification':
1732 if (!is_array($_data['username'])) {
1733 $usernames = array();
1734 $usernames[] = $_data['username'];
1735 }
1736 else {
1737 $usernames = $_data['username'];
1738 }
1739 if (!isset($_SESSION['acl']['quarantine_notification']) || $_SESSION['acl']['quarantine_notification'] != "1" ) {
1740 $_SESSION['return'][] = array(
1741 'type' => 'danger',
1742 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1743 'msg' => 'access_denied'
1744 );
1745 return false;
1746 }
1747 foreach ($usernames as $username) {
1748 if (!filter_var($username, FILTER_VALIDATE_EMAIL) || !hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
1749 $_SESSION['return'][] = array(
1750 'type' => 'danger',
1751 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1752 'msg' => 'access_denied'
1753 );
1754 continue;
1755 }
1756 $is_now = mailbox('get', 'quarantine_notification', $username);
1757 if (!empty($is_now)) {
1758 $quarantine_notification = (isset($_data['quarantine_notification'])) ? $_data['quarantine_notification'] : $is_now['quarantine_notification'];
1759 }
1760 else {
1761 $_SESSION['return'][] = array(
1762 'type' => 'danger',
1763 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1764 'msg' => 'access_denied'
1765 );
1766 continue;
1767 }
1768 if (!in_array($quarantine_notification, array('never', 'hourly', 'daily', 'weekly'))) {
1769 $_SESSION['return'][] = array(
1770 'type' => 'danger',
1771 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1772 'msg' => 'access_denied'
1773 );
1774 continue;
1775 }
1776 $stmt = $pdo->prepare("UPDATE `mailbox`
1777 SET `attributes` = JSON_SET(`attributes`, '$.quarantine_notification', :quarantine_notification)
1778 WHERE `username` = :username");
1779 $stmt->execute(array(
1780 ':quarantine_notification' => $quarantine_notification,
1781 ':username' => $username
1782 ));
1783 $_SESSION['return'][] = array(
1784 'type' => 'success',
1785 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1786 'msg' => array('mailbox_modified', $username)
1787 );
1788 }
1789 break;
1790 case 'quarantine_category':
1791 if (!is_array($_data['username'])) {
1792 $usernames = array();
1793 $usernames[] = $_data['username'];
1794 }
1795 else {
1796 $usernames = $_data['username'];
1797 }
1798 if (!isset($_SESSION['acl']['quarantine_category']) || $_SESSION['acl']['quarantine_category'] != "1" ) {
1799 $_SESSION['return'][] = array(
1800 'type' => 'danger',
1801 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1802 'msg' => 'access_denied'
1803 );
1804 return false;
1805 }
1806 foreach ($usernames as $username) {
1807 if (!filter_var($username, FILTER_VALIDATE_EMAIL) || !hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
1808 $_SESSION['return'][] = array(
1809 'type' => 'danger',
1810 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1811 'msg' => 'access_denied'
1812 );
1813 continue;
1814 }
1815 $is_now = mailbox('get', 'quarantine_category', $username);
1816 if (!empty($is_now)) {
1817 $quarantine_category = (isset($_data['quarantine_category'])) ? $_data['quarantine_category'] : $is_now['quarantine_category'];
1818 }
1819 else {
1820 $_SESSION['return'][] = array(
1821 'type' => 'danger',
1822 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1823 'msg' => 'access_denied'
1824 );
1825 continue;
1826 }
1827 if (!in_array($quarantine_category, array('add_header', 'reject', 'all'))) {
1828 $_SESSION['return'][] = array(
1829 'type' => 'danger',
1830 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1831 'msg' => 'access_denied'
1832 );
1833 continue;
1834 }
1835 $stmt = $pdo->prepare("UPDATE `mailbox`
1836 SET `attributes` = JSON_SET(`attributes`, '$.quarantine_category', :quarantine_category)
1837 WHERE `username` = :username");
1838 $stmt->execute(array(
1839 ':quarantine_category' => $quarantine_category,
1840 ':username' => $username
1841 ));
1842 $_SESSION['return'][] = array(
1843 'type' => 'success',
1844 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1845 'msg' => array('mailbox_modified', $username)
1846 );
1847 }
1848 break;
1849 case 'spam_score':
1850 if (!is_array($_data['username'])) {
1851 $usernames = array();
1852 $usernames[] = $_data['username'];
1853 }
1854 else {
1855 $usernames = $_data['username'];
1856 }
1857 if (!isset($_SESSION['acl']['spam_score']) || $_SESSION['acl']['spam_score'] != "1" ) {
1858 $_SESSION['return'][] = array(
1859 'type' => 'danger',
1860 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1861 'msg' => 'access_denied'
1862 );
1863 return false;
1864 }
1865 foreach ($usernames as $username) {
1866 if ($_data['spam_score'] == "default") {
1867 $stmt = $pdo->prepare("DELETE FROM `filterconf` WHERE `object` = :username
1868 AND (`option` = 'lowspamlevel' OR `option` = 'highspamlevel')");
1869 $stmt->execute(array(
1870 ':username' => $username
1871 ));
1872 $_SESSION['return'][] = array(
1873 'type' => 'success',
1874 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1875 'msg' => array('mailbox_modified', $username)
1876 );
1877 continue;
1878 }
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02001879 $lowspamlevel = explode(',', $_data['spam_score'])[0];
1880 $highspamlevel = explode(',', $_data['spam_score'])[1];
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001881 if (!is_numeric($lowspamlevel) || !is_numeric($highspamlevel)) {
1882 $_SESSION['return'][] = array(
1883 'type' => 'danger',
1884 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1885 'msg' => 'Invalid spam score, format must be "1,2" where first is low and second is high spam value.'
1886 );
1887 continue;
1888 }
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02001889 if ($lowspamlevel == $highspamlevel) {
1890 $highspamlevel = $highspamlevel + 0.1;
1891 }
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001892 $stmt = $pdo->prepare("DELETE FROM `filterconf` WHERE `object` = :username
1893 AND (`option` = 'lowspamlevel' OR `option` = 'highspamlevel')");
1894 $stmt->execute(array(
1895 ':username' => $username
1896 ));
1897 $stmt = $pdo->prepare("INSERT INTO `filterconf` (`object`, `option`, `value`)
1898 VALUES (:username, 'highspamlevel', :highspamlevel)");
1899 $stmt->execute(array(
1900 ':username' => $username,
1901 ':highspamlevel' => $highspamlevel
1902 ));
1903 $stmt = $pdo->prepare("INSERT INTO `filterconf` (`object`, `option`, `value`)
1904 VALUES (:username, 'lowspamlevel', :lowspamlevel)");
1905 $stmt->execute(array(
1906 ':username' => $username,
1907 ':lowspamlevel' => $lowspamlevel
1908 ));
1909 $_SESSION['return'][] = array(
1910 'type' => 'success',
1911 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1912 'msg' => array('mailbox_modified', $username)
1913 );
1914 }
1915 break;
1916 case 'time_limited_alias':
1917 if (!isset($_SESSION['acl']['spam_alias']) || $_SESSION['acl']['spam_alias'] != "1" ) {
1918 $_SESSION['return'][] = array(
1919 'type' => 'danger',
1920 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1921 'msg' => 'access_denied'
1922 );
1923 return false;
1924 }
1925 if (!is_array($_data['address'])) {
1926 $addresses = array();
1927 $addresses[] = $_data['address'];
1928 }
1929 else {
1930 $addresses = $_data['address'];
1931 }
1932 foreach ($addresses as $address) {
1933 $stmt = $pdo->prepare("SELECT `goto` FROM `spamalias` WHERE `address` = :address");
1934 $stmt->execute(array(':address' => $address));
1935 $goto = $stmt->fetch(PDO::FETCH_ASSOC)['goto'];
1936 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $goto)) {
1937 $_SESSION['return'][] = array(
1938 'type' => 'danger',
1939 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1940 'msg' => 'access_denied'
1941 );
1942 continue;
1943 }
1944 if (empty($_data['validity'])) {
1945 continue;
1946 }
1947 $validity = round((int)time() + ($_data['validity'] * 3600));
1948 $stmt = $pdo->prepare("UPDATE `spamalias` SET `validity` = :validity WHERE
1949 `address` = :address");
1950 $stmt->execute(array(
1951 ':address' => $address,
1952 ':validity' => $validity
1953 ));
1954 $_SESSION['return'][] = array(
1955 'type' => 'success',
1956 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02001957 'msg' => array('mailbox_modified', htmlspecialchars(implode(', ', (array)$usernames)))
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01001958 );
1959 }
1960 break;
1961 case 'delimiter_action':
1962 if (!is_array($_data['username'])) {
1963 $usernames = array();
1964 $usernames[] = $_data['username'];
1965 }
1966 else {
1967 $usernames = $_data['username'];
1968 }
1969 if (!isset($_SESSION['acl']['delimiter_action']) || $_SESSION['acl']['delimiter_action'] != "1" ) {
1970 $_SESSION['return'][] = array(
1971 'type' => 'danger',
1972 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1973 'msg' => 'access_denied'
1974 );
1975 return false;
1976 }
1977 foreach ($usernames as $username) {
1978 if (!filter_var($username, FILTER_VALIDATE_EMAIL) || !hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
1979 $_SESSION['return'][] = array(
1980 'type' => 'danger',
1981 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1982 'msg' => 'access_denied'
1983 );
1984 continue;
1985 }
1986 if (isset($_data['tagged_mail_handler']) && $_data['tagged_mail_handler'] == "subject") {
1987 try {
1988 $redis->hSet('RCPT_WANTS_SUBJECT_TAG', $username, 1);
1989 $redis->hDel('RCPT_WANTS_SUBFOLDER_TAG', $username);
1990 }
1991 catch (RedisException $e) {
1992 $_SESSION['return'][] = array(
1993 'type' => 'danger',
1994 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1995 'msg' => array('redis_error', $e)
1996 );
1997 continue;
1998 }
1999 }
2000 else if (isset($_data['tagged_mail_handler']) && $_data['tagged_mail_handler'] == "subfolder") {
2001 try {
2002 $redis->hSet('RCPT_WANTS_SUBFOLDER_TAG', $username, 1);
2003 $redis->hDel('RCPT_WANTS_SUBJECT_TAG', $username);
2004 }
2005 catch (RedisException $e) {
2006 $_SESSION['return'][] = array(
2007 'type' => 'danger',
2008 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2009 'msg' => array('redis_error', $e)
2010 );
2011 continue;
2012 }
2013 }
2014 else {
2015 try {
2016 $redis->hDel('RCPT_WANTS_SUBJECT_TAG', $username);
2017 $redis->hDel('RCPT_WANTS_SUBFOLDER_TAG', $username);
2018 }
2019 catch (RedisException $e) {
2020 $_SESSION['return'][] = array(
2021 'type' => 'danger',
2022 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2023 'msg' => array('redis_error', $e)
2024 );
2025 continue;
2026 }
2027 }
2028 $_SESSION['return'][] = array(
2029 'type' => 'success',
2030 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2031 'msg' => array('mailbox_modified', $username)
2032 );
2033 }
2034 break;
2035 case 'syncjob':
2036 if (!is_array($_data['id'])) {
2037 $ids = array();
2038 $ids[] = $_data['id'];
2039 }
2040 else {
2041 $ids = $_data['id'];
2042 }
2043 if (!isset($_SESSION['acl']['syncjobs']) || $_SESSION['acl']['syncjobs'] != "1" ) {
2044 $_SESSION['return'][] = array(
2045 'type' => 'danger',
2046 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2047 'msg' => 'access_denied'
2048 );
2049 return false;
2050 }
2051 foreach ($ids as $id) {
2052 $is_now = mailbox('get', 'syncjob_details', $id, array('with_password'));
2053 if (!empty($is_now)) {
2054 $username = $is_now['user2'];
2055 $user1 = (!empty($_data['user1'])) ? $_data['user1'] : $is_now['user1'];
2056 $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
2057 $last_run = (isset($_data['last_run'])) ? NULL : $is_now['last_run'];
Matthias Andreas Benkardb4b5cc12021-12-28 18:02:04 +01002058 $success = (isset($_data['success'])) ? NULL : $is_now['success'];
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002059 $delete2duplicates = (isset($_data['delete2duplicates'])) ? intval($_data['delete2duplicates']) : $is_now['delete2duplicates'];
2060 $subscribeall = (isset($_data['subscribeall'])) ? intval($_data['subscribeall']) : $is_now['subscribeall'];
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01002061 $dry = (isset($_data['dry'])) ? intval($_data['dry']) : $is_now['dry'];
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002062 $delete1 = (isset($_data['delete1'])) ? intval($_data['delete1']) : $is_now['delete1'];
2063 $delete2 = (isset($_data['delete2'])) ? intval($_data['delete2']) : $is_now['delete2'];
2064 $automap = (isset($_data['automap'])) ? intval($_data['automap']) : $is_now['automap'];
2065 $skipcrossduplicates = (isset($_data['skipcrossduplicates'])) ? intval($_data['skipcrossduplicates']) : $is_now['skipcrossduplicates'];
2066 $port1 = (!empty($_data['port1'])) ? $_data['port1'] : $is_now['port1'];
2067 $password1 = (!empty($_data['password1'])) ? $_data['password1'] : $is_now['password1'];
2068 $host1 = (!empty($_data['host1'])) ? $_data['host1'] : $is_now['host1'];
2069 $subfolder2 = (isset($_data['subfolder2'])) ? $_data['subfolder2'] : $is_now['subfolder2'];
2070 $enc1 = (!empty($_data['enc1'])) ? $_data['enc1'] : $is_now['enc1'];
2071 $mins_interval = (!empty($_data['mins_interval'])) ? $_data['mins_interval'] : $is_now['mins_interval'];
2072 $exclude = (isset($_data['exclude'])) ? $_data['exclude'] : $is_now['exclude'];
2073 $custom_params = (isset($_data['custom_params'])) ? $_data['custom_params'] : $is_now['custom_params'];
2074 $maxage = (isset($_data['maxage']) && $_data['maxage'] != "") ? intval($_data['maxage']) : $is_now['maxage'];
2075 $maxbytespersecond = (isset($_data['maxbytespersecond']) && $_data['maxbytespersecond'] != "") ? intval($_data['maxbytespersecond']) : $is_now['maxbytespersecond'];
2076 $timeout1 = (isset($_data['timeout1']) && $_data['timeout1'] != "") ? intval($_data['timeout1']) : $is_now['timeout1'];
2077 $timeout2 = (isset($_data['timeout2']) && $_data['timeout2'] != "") ? intval($_data['timeout2']) : $is_now['timeout2'];
2078 }
2079 else {
2080 $_SESSION['return'][] = array(
2081 'type' => 'danger',
2082 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2083 'msg' => 'access_denied'
2084 );
2085 continue;
2086 }
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01002087
2088 // validate custom params
2089 foreach (explode('-', $custom_params) as $param){
2090 if(empty($param)) continue;
2091
2092 // extract option
2093 if (str_contains($param, '=')) $param = explode('=', $param)[0];
2094 else $param = rtrim($param, ' ');
2095 // remove first char if first char is -
2096 if ($param[0] == '-') $param = ltrim($param, $param[0]);
2097
2098 if (str_contains($param, ' ')) {
2099 // bad char
2100 $_SESSION['return'][] = array(
2101 'type' => 'danger',
2102 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2103 'msg' => 'bad character SPACE'
2104 );
2105 return false;
2106 }
2107
2108 // check if param is whitelisted
2109 if (!in_array(strtolower($param), $GLOBALS["IMAPSYNC_OPTIONS"]["whitelist"])){
2110 // bad option
2111 $_SESSION['return'][] = array(
2112 'type' => 'danger',
2113 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2114 'msg' => 'bad option '. $param
2115 );
2116 return false;
2117 }
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002118 }
2119 if (empty($subfolder2)) {
2120 $subfolder2 = "";
2121 }
2122 if (!isset($maxage) || !filter_var($maxage, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 32000)))) {
2123 $maxage = "0";
2124 }
2125 if (!isset($timeout1) || !filter_var($timeout1, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 32000)))) {
2126 $timeout1 = "600";
2127 }
2128 if (!isset($timeout2) || !filter_var($timeout2, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 32000)))) {
2129 $timeout2 = "600";
2130 }
2131 if (!isset($maxbytespersecond) || !filter_var($maxbytespersecond, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 125000000)))) {
2132 $maxbytespersecond = "0";
2133 }
2134 if (!filter_var($port1, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 65535)))) {
2135 $_SESSION['return'][] = array(
2136 'type' => 'danger',
2137 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2138 'msg' => 'access_denied'
2139 );
2140 continue;
2141 }
2142 if (!filter_var($mins_interval, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 43800)))) {
2143 $_SESSION['return'][] = array(
2144 'type' => 'danger',
2145 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2146 'msg' => 'access_denied'
2147 );
2148 continue;
2149 }
2150 if (!is_valid_domain_name($host1)) {
2151 $_SESSION['return'][] = array(
2152 'type' => 'danger',
2153 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2154 'msg' => 'access_denied'
2155 );
2156 continue;
2157 }
2158 if ($enc1 != "TLS" && $enc1 != "SSL" && $enc1 != "PLAIN") {
2159 $_SESSION['return'][] = array(
2160 'type' => 'danger',
2161 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2162 'msg' => 'access_denied'
2163 );
2164 continue;
2165 }
2166 if (@preg_match("/" . $exclude . "/", null) === false) {
2167 $_SESSION['return'][] = array(
2168 'type' => 'danger',
2169 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2170 'msg' => 'access_denied'
2171 );
2172 continue;
2173 }
2174 $stmt = $pdo->prepare("UPDATE `imapsync` SET `delete1` = :delete1,
2175 `delete2` = :delete2,
2176 `automap` = :automap,
2177 `skipcrossduplicates` = :skipcrossduplicates,
2178 `maxage` = :maxage,
2179 `maxbytespersecond` = :maxbytespersecond,
2180 `subfolder2` = :subfolder2,
2181 `exclude` = :exclude,
2182 `host1` = :host1,
2183 `last_run` = :last_run,
Matthias Andreas Benkardb4b5cc12021-12-28 18:02:04 +01002184 `success` = :success,
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002185 `user1` = :user1,
2186 `password1` = :password1,
2187 `mins_interval` = :mins_interval,
2188 `port1` = :port1,
2189 `enc1` = :enc1,
2190 `delete2duplicates` = :delete2duplicates,
2191 `custom_params` = :custom_params,
2192 `timeout1` = :timeout1,
2193 `timeout2` = :timeout2,
2194 `subscribeall` = :subscribeall,
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01002195 `dry` = :dry,
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002196 `active` = :active
2197 WHERE `id` = :id");
2198 $stmt->execute(array(
2199 ':delete1' => $delete1,
2200 ':delete2' => $delete2,
2201 ':automap' => $automap,
2202 ':skipcrossduplicates' => $skipcrossduplicates,
2203 ':id' => $id,
2204 ':exclude' => $exclude,
2205 ':maxage' => $maxage,
2206 ':maxbytespersecond' => $maxbytespersecond,
2207 ':subfolder2' => $subfolder2,
2208 ':host1' => $host1,
2209 ':user1' => $user1,
2210 ':password1' => $password1,
2211 ':last_run' => $last_run,
Matthias Andreas Benkardb4b5cc12021-12-28 18:02:04 +01002212 ':success' => $success,
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002213 ':mins_interval' => $mins_interval,
2214 ':port1' => $port1,
2215 ':enc1' => $enc1,
2216 ':delete2duplicates' => $delete2duplicates,
2217 ':custom_params' => $custom_params,
2218 ':timeout1' => $timeout1,
2219 ':timeout2' => $timeout2,
2220 ':subscribeall' => $subscribeall,
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01002221 ':dry' => $dry,
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002222 ':active' => $active,
2223 ));
2224 $_SESSION['return'][] = array(
2225 'type' => 'success',
2226 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2227 'msg' => array('mailbox_modified', $username)
2228 );
2229 }
2230 break;
2231 case 'filter':
2232 if (!isset($_SESSION['acl']['filters']) || $_SESSION['acl']['filters'] != "1" ) {
2233 $_SESSION['return'][] = array(
2234 'type' => 'danger',
2235 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2236 'msg' => 'access_denied'
2237 );
2238 return false;
2239 }
2240 $sieve = new Sieve\SieveParser();
2241 if (!is_array($_data['id'])) {
2242 $ids = array();
2243 $ids[] = $_data['id'];
2244 }
2245 else {
2246 $ids = $_data['id'];
2247 }
2248 foreach ($ids as $id) {
2249 $is_now = mailbox('get', 'filter_details', $id);
2250 if (!empty($is_now)) {
2251 $username = $is_now['username'];
2252 $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
2253 $script_desc = (!empty($_data['script_desc'])) ? $_data['script_desc'] : $is_now['script_desc'];
2254 $script_data = (!empty($_data['script_data'])) ? $_data['script_data'] : $is_now['script_data'];
2255 $filter_type = (!empty($_data['filter_type'])) ? $_data['filter_type'] : $is_now['filter_type'];
2256 }
2257 else {
2258 $_SESSION['return'][] = array(
2259 'type' => 'danger',
2260 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2261 'msg' => 'access_denied'
2262 );
2263 continue;
2264 }
2265 try {
2266 $sieve->parse($script_data);
2267 }
2268 catch (Exception $e) {
2269 $_SESSION['return'][] = array(
2270 'type' => 'danger',
2271 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2272 'msg' => array('sieve_error', $e->getMessage())
2273 );
2274 continue;
2275 }
2276 if ($filter_type != 'postfilter' && $filter_type != 'prefilter') {
2277 $_SESSION['return'][] = array(
2278 'type' => 'danger',
2279 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2280 'msg' => 'filter_type'
2281 );
2282 continue;
2283 }
2284 if ($active == '1') {
2285 $script_name = 'active';
2286 $stmt = $pdo->prepare("UPDATE `sieve_filters`
2287 SET `script_name` = 'inactive'
2288 WHERE `username` = :username
2289 AND `filter_type` = :filter_type");
2290 $stmt->execute(array(
2291 ':username' => $username,
2292 ':filter_type' => $filter_type
2293 ));
2294 }
2295 else {
2296 $script_name = 'inactive';
2297 }
2298 $stmt = $pdo->prepare("UPDATE `sieve_filters` SET `script_desc` = :script_desc, `script_data` = :script_data, `script_name` = :script_name, `filter_type` = :filter_type
2299 WHERE `id` = :id");
2300 $stmt->execute(array(
2301 ':script_desc' => $script_desc,
2302 ':script_data' => $script_data,
2303 ':script_name' => $script_name,
2304 ':filter_type' => $filter_type,
2305 ':id' => $id
2306 ));
2307 $_SESSION['return'][] = array(
2308 'type' => 'success',
2309 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2310 'msg' => array('mailbox_modified', $username)
2311 );
2312 }
2313 break;
2314 case 'alias':
2315 if (!is_array($_data['id'])) {
2316 $ids = array();
2317 $ids[] = $_data['id'];
2318 }
2319 else {
2320 $ids = $_data['id'];
2321 }
2322 foreach ($ids as $id) {
2323 $is_now = mailbox('get', 'alias_details', $id);
2324 if (!empty($is_now)) {
2325 $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
2326 $sogo_visible = (isset($_data['sogo_visible'])) ? intval($_data['sogo_visible']) : $is_now['sogo_visible'];
2327 $goto_null = (isset($_data['goto_null'])) ? intval($_data['goto_null']) : 0;
2328 $goto_spam = (isset($_data['goto_spam'])) ? intval($_data['goto_spam']) : 0;
2329 $goto_ham = (isset($_data['goto_ham'])) ? intval($_data['goto_ham']) : 0;
2330 $public_comment = (isset($_data['public_comment'])) ? $_data['public_comment'] : $is_now['public_comment'];
2331 $private_comment = (isset($_data['private_comment'])) ? $_data['private_comment'] : $is_now['private_comment'];
2332 $goto = (!empty($_data['goto'])) ? $_data['goto'] : $is_now['goto'];
2333 $address = (!empty($_data['address'])) ? $_data['address'] : $is_now['address'];
2334 }
2335 else {
2336 $_SESSION['return'][] = array(
2337 'type' => 'danger',
2338 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2339 'msg' => array('alias_invalid', $address)
2340 );
2341 continue;
2342 }
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02002343 if ($_data['expand_alias'] === true || $_data['expand_alias'] == 1) {
2344 $stmt = $pdo->prepare("SELECT `address` FROM `alias`
2345 WHERE `address` = :address
2346 AND `domain` NOT IN (
2347 SELECT `alias_domain` FROM `alias_domain`
2348 )");
2349 $stmt->execute(array(
2350 ':address' => $address,
2351 ));
2352 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
2353 if ($num_results == 0) {
2354 $_SESSION['return'][] = array(
2355 'type' => 'warning',
2356 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2357 'msg' => array('is_not_primary_alias', htmlspecialchars($address))
2358 );
2359 continue;
2360 }
2361 $stmt = $pdo->prepare("SELECT `goto`, GROUP_CONCAT(CONCAT(SUBSTRING(`alias`.`address`, 1, LOCATE('@', `alias`.`address`) - 1), '@', `alias_domain`.`alias_domain`)) AS `missing_alias`
2362 FROM `alias` JOIN `alias_domain` ON `alias_domain`.`target_domain` = `alias`.`domain`
2363 WHERE CONCAT(SUBSTRING(`alias`.`address`, 1, LOCATE('@', `alias`.`address`) - 1), '@', `alias_domain`.`alias_domain`) NOT IN (
2364 SELECT `address` FROM `alias` WHERE `address` != `goto`
2365 )
2366 AND `alias`.`address` NOT IN (
2367 SELECT `address` FROM `alias` WHERE `address` = `goto`
2368 )
2369 AND `address` = :address ;");
2370 $stmt->execute(array(
2371 ':address' => $address
2372 ));
2373 $missing_aliases = $stmt->fetch(PDO::FETCH_ASSOC);
2374 if (!empty($missing_aliases['missing_alias'])) {
2375 mailbox('add', 'alias', array(
2376 'address' => $missing_aliases['missing_alias'],
2377 'goto' => $missing_aliases['goto'],
2378 'sogo_visible' => 1,
2379 'active' => 1
2380 ));
2381 }
2382 $_SESSION['return'][] = array(
2383 'type' => 'success',
2384 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2385 'msg' => array('alias_modified', htmlspecialchars($address))
2386 );
2387 continue;
2388 }
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002389 $domain = idn_to_ascii(substr(strstr($address, '@'), 1), 0, INTL_IDNA_VARIANT_UTS46);
2390 if ($is_now['address'] != $address) {
2391 $local_part = strstr($address, '@', true);
2392 $address = $local_part.'@'.$domain;
2393 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
2394 $_SESSION['return'][] = array(
2395 'type' => 'danger',
2396 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2397 'msg' => 'access_denied'
2398 );
2399 continue;
2400 }
2401 if ((!filter_var($address, FILTER_VALIDATE_EMAIL) === true) && !empty($local_part)) {
2402 $_SESSION['return'][] = array(
2403 'type' => 'danger',
2404 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2405 'msg' => array('alias_invalid', $address)
2406 );
2407 continue;
2408 }
2409 if (strtolower($is_now['address']) != strtolower($address)) {
2410 $stmt = $pdo->prepare("SELECT `address` FROM `alias`
2411 WHERE `address`= :address OR `address` IN (
2412 SELECT `username` FROM `mailbox`, `alias_domain`
2413 WHERE (
2414 `alias_domain`.`alias_domain` = :address_d
2415 AND `mailbox`.`username` = CONCAT(:address_l, '@', alias_domain.target_domain)))");
2416 $stmt->execute(array(
2417 ':address' => $address,
2418 ':address_l' => $local_part,
2419 ':address_d' => $domain
2420 ));
2421 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
2422 if ($num_results != 0) {
2423 $_SESSION['return'][] = array(
2424 'type' => 'danger',
2425 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2426 'msg' => array('is_alias_or_mailbox', htmlspecialchars($address))
2427 );
2428 continue;
2429 }
2430 }
2431 $stmt = $pdo->prepare("SELECT `domain` FROM `domain`
2432 WHERE `domain`= :domain1 OR `domain` = (SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :domain2)");
2433 $stmt->execute(array(':domain1' => $domain, ':domain2' => $domain));
2434 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
2435 if ($num_results == 0) {
2436 $_SESSION['return'][] = array(
2437 'type' => 'danger',
2438 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2439 'msg' => array('domain_not_found', htmlspecialchars($domain))
2440 );
2441 continue;
2442 }
2443 $stmt = $pdo->prepare("SELECT `address` FROM `spamalias`
2444 WHERE `address`= :address");
2445 $stmt->execute(array(':address' => $address));
2446 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
2447 if ($num_results != 0) {
2448 $_SESSION['return'][] = array(
2449 'type' => 'danger',
2450 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2451 'msg' => array('is_spam_alias', htmlspecialchars($address))
2452 );
2453 continue;
2454 }
2455 }
2456 if ($goto_null == "1") {
2457 $goto = "null@localhost";
2458 }
2459 elseif ($goto_spam == "1") {
2460 $goto = "spam@localhost";
2461 }
2462 elseif ($goto_ham == "1") {
2463 $goto = "ham@localhost";
2464 }
2465 else {
2466 $gotos = array_map('trim', preg_split( "/( |,|;|\n)/", $goto));
2467 foreach ($gotos as $i => &$goto) {
2468 if (empty($goto)) {
2469 continue;
2470 }
2471 if (!filter_var($goto, FILTER_VALIDATE_EMAIL)) {
2472 $_SESSION['return'][] = array(
2473 'type' => 'danger',
2474 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2475 'msg' => array('goto_invalid', $goto)
2476 );
2477 unset($gotos[$i]);
2478 continue;
2479 }
2480 if ($goto == $address) {
2481 $_SESSION['return'][] = array(
2482 'type' => 'danger',
2483 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2484 'msg' => 'alias_goto_identical'
2485 );
2486 unset($gotos[$i]);
2487 continue;
2488 }
2489 // Delete from sender_acl to prevent duplicates
2490 $stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE
2491 `logged_in_as` = :goto AND
2492 `send_as` = :address");
2493 $stmt->execute(array(
2494 ':goto' => $goto,
2495 ':address' => $address
2496 ));
2497 }
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02002498 $gotos = array_unique($gotos);
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002499 $gotos = array_filter($gotos);
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02002500 $goto = implode(",", (array)$gotos);
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002501 }
2502 if (!empty($goto)) {
2503 $stmt = $pdo->prepare("UPDATE `alias` SET
2504 `address` = :address,
2505 `public_comment` = :public_comment,
2506 `private_comment` = :private_comment,
2507 `domain` = :domain,
2508 `goto` = :goto,
2509 `sogo_visible`= :sogo_visible,
2510 `active`= :active
2511 WHERE `id` = :id");
2512 $stmt->execute(array(
2513 ':address' => $address,
2514 ':public_comment' => $public_comment,
2515 ':private_comment' => $private_comment,
2516 ':domain' => $domain,
2517 ':goto' => $goto,
2518 ':sogo_visible' => $sogo_visible,
2519 ':active' => $active,
2520 ':id' => $is_now['id']
2521 ));
2522 }
2523 $_SESSION['return'][] = array(
2524 'type' => 'success',
2525 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2526 'msg' => array('alias_modified', htmlspecialchars($address))
2527 );
2528 }
2529 break;
2530 case 'domain':
2531 if (!is_array($_data['domain'])) {
2532 $domains = array();
2533 $domains[] = $_data['domain'];
2534 }
2535 else {
2536 $domains = $_data['domain'];
2537 }
2538 foreach ($domains as $domain) {
2539 $domain = idn_to_ascii($domain, 0, INTL_IDNA_VARIANT_UTS46);
2540 if (!is_valid_domain_name($domain)) {
2541 $_SESSION['return'][] = array(
2542 'type' => 'danger',
2543 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2544 'msg' => 'domain_invalid'
2545 );
2546 continue;
2547 }
2548 if ($_SESSION['mailcow_cc_role'] == "domainadmin" &&
2549 hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
2550 $is_now = mailbox('get', 'domain_details', $domain);
2551 if (!empty($is_now)) {
2552 $gal = (isset($_data['gal'])) ? intval($_data['gal']) : $is_now['gal'];
2553 $description = (!empty($_data['description']) && isset($_SESSION['acl']['domain_desc']) && $_SESSION['acl']['domain_desc'] == "1") ? $_data['description'] : $is_now['description'];
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02002554 (int)$relayhost = (isset($_data['relayhost']) && isset($_SESSION['acl']['domain_relayhost']) && $_SESSION['acl']['domain_relayhost'] == "1") ? intval($_data['relayhost']) : intval($is_now['relayhost']);
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01002555 $tags = (is_array($_data['tags']) ? $_data['tags'] : array());
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002556 }
2557 else {
2558 $_SESSION['return'][] = array(
2559 'type' => 'danger',
2560 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2561 'msg' => 'domain_invalid'
2562 );
2563 continue;
2564 }
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01002565
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002566 $stmt = $pdo->prepare("UPDATE `domain` SET
2567 `description` = :description,
2568 `gal` = :gal
2569 WHERE `domain` = :domain");
2570 $stmt->execute(array(
2571 ':description' => $description,
2572 ':gal' => $gal,
2573 ':domain' => $domain
2574 ));
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01002575 // save tags
2576 foreach($tags as $index => $tag){
2577 if (empty($tag)) continue;
2578 if ($index > $GLOBALS['TAGGING_LIMIT']) {
2579 $_SESSION['return'][] = array(
2580 'type' => 'warning',
2581 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2582 'msg' => array('tag_limit_exceeded', 'limit '.$GLOBALS['TAGGING_LIMIT'])
2583 );
2584 break;
2585 }
2586 $stmt = $pdo->prepare("INSERT INTO `tags_domain` (`domain`, `tag_name`) VALUES (:domain, :tag_name)");
2587 $stmt->execute(array(
2588 ':domain' => $domain,
2589 ':tag_name' => $tag,
2590 ));
2591 }
2592
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002593 $_SESSION['return'][] = array(
2594 'type' => 'success',
2595 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2596 'msg' => array('domain_modified', htmlspecialchars($domain))
2597 );
2598 }
2599 elseif ($_SESSION['mailcow_cc_role'] == "admin") {
2600 $is_now = mailbox('get', 'domain_details', $domain);
2601 if (!empty($is_now)) {
2602 $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
2603 $backupmx = (isset($_data['backupmx'])) ? intval($_data['backupmx']) : $is_now['backupmx'];
2604 $gal = (isset($_data['gal'])) ? intval($_data['gal']) : $is_now['gal'];
2605 $relay_all_recipients = (isset($_data['relay_all_recipients'])) ? intval($_data['relay_all_recipients']) : $is_now['relay_all_recipients'];
2606 $relay_unknown_only = (isset($_data['relay_unknown_only'])) ? intval($_data['relay_unknown_only']) : $is_now['relay_unknown_only'];
2607 $relayhost = (isset($_data['relayhost'])) ? intval($_data['relayhost']) : $is_now['relayhost'];
2608 $aliases = (!empty($_data['aliases'])) ? $_data['aliases'] : $is_now['max_num_aliases_for_domain'];
2609 $mailboxes = (isset($_data['mailboxes']) && $_data['mailboxes'] != '') ? intval($_data['mailboxes']) : $is_now['max_num_mboxes_for_domain'];
2610 $defquota = (isset($_data['defquota']) && $_data['defquota'] != '') ? intval($_data['defquota']) : ($is_now['def_quota_for_mbox'] / 1048576);
2611 $maxquota = (!empty($_data['maxquota'])) ? $_data['maxquota'] : ($is_now['max_quota_for_mbox'] / 1048576);
2612 $quota = (!empty($_data['quota'])) ? $_data['quota'] : ($is_now['max_quota_for_domain'] / 1048576);
2613 $description = (!empty($_data['description'])) ? $_data['description'] : $is_now['description'];
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01002614 $tags = (is_array($_data['tags']) ? $_data['tags'] : array());
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002615 if ($relay_all_recipients == '1') {
2616 $backupmx = '1';
2617 }
2618 if ($relay_unknown_only == '1') {
2619 $backupmx = '1';
2620 $relay_all_recipients = '1';
2621 }
2622 }
2623 else {
2624 $_SESSION['return'][] = array(
2625 'type' => 'danger',
2626 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2627 'msg' => 'domain_invalid'
2628 );
2629 continue;
2630 }
2631 // todo: should be using api here
2632 $stmt = $pdo->prepare("SELECT
2633 COUNT(*) AS count,
2634 MAX(COALESCE(ROUND(`quota`/1048576), 0)) AS `biggest_mailbox`,
2635 COALESCE(ROUND(SUM(`quota`)/1048576), 0) AS `quota_all`
2636 FROM `mailbox`
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02002637 WHERE (`kind` = '' OR `kind` = NULL)
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002638 AND domain = :domain");
2639 $stmt->execute(array(':domain' => $domain));
2640 $MailboxData = $stmt->fetch(PDO::FETCH_ASSOC);
2641 // todo: should be using api here
2642 $stmt = $pdo->prepare("SELECT COUNT(*) AS `count` FROM `alias`
2643 WHERE domain = :domain
2644 AND address NOT IN (
2645 SELECT `username` FROM `mailbox`
2646 )");
2647 $stmt->execute(array(':domain' => $domain));
2648 $AliasData = $stmt->fetch(PDO::FETCH_ASSOC);
2649 if ($defquota > $maxquota) {
2650 $_SESSION['return'][] = array(
2651 'type' => 'danger',
2652 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2653 'msg' => 'mailbox_defquota_exceeds_mailbox_maxquota'
2654 );
2655 continue;
2656 }
2657 if ($defquota == "0" || empty($defquota)) {
2658 $_SESSION['return'][] = array(
2659 'type' => 'danger',
2660 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2661 'msg' => 'defquota_empty'
2662 );
2663 continue;
2664 }
2665 if ($maxquota > $quota) {
2666 $_SESSION['return'][] = array(
2667 'type' => 'danger',
2668 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2669 'msg' => 'mailbox_quota_exceeds_domain_quota'
2670 );
2671 continue;
2672 }
2673 if ($maxquota == "0" || empty($maxquota)) {
2674 $_SESSION['return'][] = array(
2675 'type' => 'danger',
2676 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2677 'msg' => 'maxquota_empty'
2678 );
2679 continue;
2680 }
2681 if ($MailboxData['biggest_mailbox'] > $maxquota) {
2682 $_SESSION['return'][] = array(
2683 'type' => 'danger',
2684 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2685 'msg' => array('max_quota_in_use', $MailboxData['biggest_mailbox'])
2686 );
2687 continue;
2688 }
2689 if ($MailboxData['quota_all'] > $quota) {
2690 $_SESSION['return'][] = array(
2691 'type' => 'danger',
2692 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2693 'msg' => array('domain_quota_m_in_use', $MailboxData['quota_all'])
2694 );
2695 continue;
2696 }
2697 if ($MailboxData['count'] > $mailboxes) {
2698 $_SESSION['return'][] = array(
2699 'type' => 'danger',
2700 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2701 'msg' => array('mailboxes_in_use', $MailboxData['count'])
2702 );
2703 continue;
2704 }
2705 if ($AliasData['count'] > $aliases) {
2706 $_SESSION['return'][] = array(
2707 'type' => 'danger',
2708 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2709 'msg' => array('aliases_in_use', $AliasData['count'])
2710 );
2711 continue;
2712 }
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01002713
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002714 $stmt = $pdo->prepare("UPDATE `domain` SET
2715 `relay_all_recipients` = :relay_all_recipients,
2716 `relay_unknown_only` = :relay_unknown_only,
2717 `backupmx` = :backupmx,
2718 `gal` = :gal,
2719 `active` = :active,
2720 `quota` = :quota,
2721 `defquota` = :defquota,
2722 `maxquota` = :maxquota,
2723 `relayhost` = :relayhost,
2724 `mailboxes` = :mailboxes,
2725 `aliases` = :aliases,
2726 `description` = :description
2727 WHERE `domain` = :domain");
2728 $stmt->execute(array(
2729 ':relay_all_recipients' => $relay_all_recipients,
2730 ':relay_unknown_only' => $relay_unknown_only,
2731 ':backupmx' => $backupmx,
2732 ':gal' => $gal,
2733 ':active' => $active,
2734 ':quota' => $quota,
2735 ':defquota' => $defquota,
2736 ':maxquota' => $maxquota,
2737 ':relayhost' => $relayhost,
2738 ':mailboxes' => $mailboxes,
2739 ':aliases' => $aliases,
2740 ':description' => $description,
2741 ':domain' => $domain
2742 ));
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01002743 // save tags
2744 foreach($tags as $index => $tag){
2745 if (empty($tag)) continue;
2746 if ($index > $GLOBALS['TAGGING_LIMIT']) {
2747 $_SESSION['return'][] = array(
2748 'type' => 'warning',
2749 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2750 'msg' => array('tag_limit_exceeded', 'limit '.$GLOBALS['TAGGING_LIMIT'])
2751 );
2752 break;
2753 }
2754 $stmt = $pdo->prepare("INSERT INTO `tags_domain` (`domain`, `tag_name`) VALUES (:domain, :tag_name)");
2755 $stmt->execute(array(
2756 ':domain' => $domain,
2757 ':tag_name' => $tag,
2758 ));
2759 }
2760
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002761 $_SESSION['return'][] = array(
2762 'type' => 'success',
2763 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2764 'msg' => array('domain_modified', htmlspecialchars($domain))
2765 );
2766 }
2767 }
2768 break;
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01002769 case 'domain_templates':
2770 if ($_SESSION['mailcow_cc_role'] != "admin") {
2771 $_SESSION['return'][] = array(
2772 'type' => 'danger',
2773 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
2774 'msg' => 'access_denied'
2775 );
2776 return false;
2777 }
2778 if (!is_array($_data['ids'])) {
2779 $ids = array();
2780 $ids[] = $_data['ids'];
2781 }
2782 else {
2783 $ids = $_data['ids'];
2784 }
2785 foreach ($ids as $id) {
2786 $is_now = mailbox("get", "domain_templates", $id);
2787 if (empty($is_now) ||
2788 $is_now["type"] != "domain"){
2789 $_SESSION['return'][] = array(
2790 'type' => 'danger',
2791 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
2792 'msg' => 'template_id_invalid'
2793 );
2794 continue;
2795 }
2796
2797 // check name
2798 if ($is_now["template"] == "Default" && $is_now["template"] != $_data["template"]){
2799 // keep template name of Default template
2800 $_data["template"] = $is_now["template"];
2801 }
2802 else {
2803 $_data["template"] = (isset($_data["template"])) ? $_data["template"] : $is_now["template"];
2804 }
2805 // check attributes
2806 $attr = array();
2807 $attr['tags'] = (isset($_data['tags'])) ? $_data['tags'] : array();
2808 $attr['max_num_aliases_for_domain'] = (isset($_data['max_num_aliases_for_domain'])) ? intval($_data['max_num_aliases_for_domain']) : 0;
2809 $attr['max_num_mboxes_for_domain'] = (isset($_data['max_num_mboxes_for_domain'])) ? intval($_data['max_num_mboxes_for_domain']) : 0;
2810 $attr['def_quota_for_mbox'] = (isset($_data['def_quota_for_mbox'])) ? intval($_data['def_quota_for_mbox']) * 1048576 : 0;
2811 $attr['max_quota_for_mbox'] = (isset($_data['max_quota_for_mbox'])) ? intval($_data['max_quota_for_mbox']) * 1048576 : 0;
2812 $attr['max_quota_for_domain'] = (isset($_data['max_quota_for_domain'])) ? intval($_data['max_quota_for_domain']) * 1048576 : 0;
2813 $attr['rl_frame'] = (!empty($_data['rl_frame'])) ? $_data['rl_frame'] : "s";
2814 $attr['rl_value'] = (!empty($_data['rl_value'])) ? $_data['rl_value'] : "";
2815 $attr['active'] = isset($_data['active']) ? intval($_data['active']) : 1;
2816 $attr['gal'] = (isset($_data['gal'])) ? intval($_data['gal']) : 1;
2817 $attr['backupmx'] = (isset($_data['backupmx'])) ? intval($_data['backupmx']) : 0;
2818 $attr['relay_all_recipients'] = (isset($_data['relay_all_recipients'])) ? intval($_data['relay_all_recipients']) : 0;
2819 $attr['relay_unknown_only'] = (isset($_data['relay_unknown_only'])) ? intval($_data['relay_unknown_only']) : 0;
2820 $attr['dkim_selector'] = (isset($_data['dkim_selector'])) ? $_data['dkim_selector'] : "dkim";
2821 $attr['key_size'] = isset($_data['key_size']) ? intval($_data['key_size']) : 2048;
2822
2823 // update template
2824 $stmt = $pdo->prepare("UPDATE `templates`
2825 SET `template` = :template, `attributes` = :attributes
2826 WHERE id = :id");
2827 $stmt->execute(array(
2828 ":id" => $id ,
2829 ":template" => $_data["template"] ,
2830 ":attributes" => json_encode($attr)
2831 ));
2832 }
2833
2834
2835 $_SESSION['return'][] = array(
2836 'type' => 'success',
2837 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2838 'msg' => array('template_modified', $_data["template"])
2839 );
2840 return true;
2841 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002842 case 'mailbox':
2843 if (!is_array($_data['username'])) {
2844 $usernames = array();
2845 $usernames[] = $_data['username'];
2846 }
2847 else {
2848 $usernames = $_data['username'];
2849 }
2850 foreach ($usernames as $username) {
2851 if (!filter_var($username, FILTER_VALIDATE_EMAIL)) {
2852 $_SESSION['return'][] = array(
2853 'type' => 'danger',
2854 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2855 'msg' => array('username_invalid', $username)
2856 );
2857 continue;
2858 }
2859 $is_now = mailbox('get', 'mailbox_details', $username);
2860 if (isset($_data['protocol_access'])) {
Matthias Andreas Benkardb4b5cc12021-12-28 18:02:04 +01002861 $_data['protocol_access'] = (array)$_data['protocol_access'];
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002862 $_data['imap_access'] = (in_array('imap', $_data['protocol_access'])) ? 1 : 0;
2863 $_data['pop3_access'] = (in_array('pop3', $_data['protocol_access'])) ? 1 : 0;
2864 $_data['smtp_access'] = (in_array('smtp', $_data['protocol_access'])) ? 1 : 0;
Matthias Andreas Benkardb4b5cc12021-12-28 18:02:04 +01002865 $_data['sieve_access'] = (in_array('sieve', $_data['protocol_access'])) ? 1 : 0;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002866 }
2867 if (!empty($is_now)) {
2868 $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
2869 (int)$force_pw_update = (isset($_data['force_pw_update'])) ? intval($_data['force_pw_update']) : intval($is_now['attributes']['force_pw_update']);
Matthias Andreas Benkardb4b5cc12021-12-28 18:02:04 +01002870 (int)$sogo_access = (isset($_data['sogo_access']) && isset($_SESSION['acl']['sogo_access']) && $_SESSION['acl']['sogo_access'] == "1") ? intval($_data['sogo_access']) : intval($is_now['attributes']['sogo_access']);
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002871 (int)$imap_access = (isset($_data['imap_access']) && isset($_SESSION['acl']['protocol_access']) && $_SESSION['acl']['protocol_access'] == "1") ? intval($_data['imap_access']) : intval($is_now['attributes']['imap_access']);
2872 (int)$pop3_access = (isset($_data['pop3_access']) && isset($_SESSION['acl']['protocol_access']) && $_SESSION['acl']['protocol_access'] == "1") ? intval($_data['pop3_access']) : intval($is_now['attributes']['pop3_access']);
2873 (int)$smtp_access = (isset($_data['smtp_access']) && isset($_SESSION['acl']['protocol_access']) && $_SESSION['acl']['protocol_access'] == "1") ? intval($_data['smtp_access']) : intval($is_now['attributes']['smtp_access']);
Matthias Andreas Benkardb4b5cc12021-12-28 18:02:04 +01002874 (int)$sieve_access = (isset($_data['sieve_access']) && isset($_SESSION['acl']['protocol_access']) && $_SESSION['acl']['protocol_access'] == "1") ? intval($_data['sieve_access']) : intval($is_now['attributes']['sieve_access']);
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02002875 (int)$relayhost = (isset($_data['relayhost']) && isset($_SESSION['acl']['mailbox_relayhost']) && $_SESSION['acl']['mailbox_relayhost'] == "1") ? intval($_data['relayhost']) : intval($is_now['attributes']['relayhost']);
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002876 (int)$quota_m = (isset_has_content($_data['quota'])) ? intval($_data['quota']) : ($is_now['quota'] / 1048576);
2877 $name = (!empty($_data['name'])) ? ltrim(rtrim($_data['name'], '>'), '<') : $is_now['name'];
2878 $domain = $is_now['domain'];
2879 $quota_b = $quota_m * 1048576;
2880 $password = (!empty($_data['password'])) ? $_data['password'] : null;
2881 $password2 = (!empty($_data['password2'])) ? $_data['password2'] : null;
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01002882 $tags = (is_array($_data['tags']) ? $_data['tags'] : array());
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002883 }
2884 else {
2885 $_SESSION['return'][] = array(
2886 'type' => 'danger',
2887 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2888 'msg' => 'access_denied'
2889 );
2890 continue;
2891 }
2892 // if already 0 == ok
2893 if ((!isset($_SESSION['acl']['unlimited_quota']) || $_SESSION['acl']['unlimited_quota'] != "1") && ($quota_m == 0 && $is_now['quota'] != 0)) {
2894 $_SESSION['return'][] = array(
2895 'type' => 'danger',
2896 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2897 'msg' => 'unlimited_quota_acl'
2898 );
2899 return false;
2900 }
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002901 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
2902 $_SESSION['return'][] = array(
2903 'type' => 'danger',
2904 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2905 'msg' => 'access_denied'
2906 );
2907 continue;
2908 }
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02002909 $DomainData = mailbox('get', 'domain_details', $domain);
2910 if ($quota_m > ($is_now['max_new_quota'] / 1048576)) {
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002911 $_SESSION['return'][] = array(
2912 'type' => 'danger',
2913 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2914 'msg' => array('mailbox_quota_left_exceeded', ($is_now['max_new_quota'] / 1048576))
2915 );
2916 continue;
2917 }
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02002918 if ($quota_m > $DomainData['max_quota_for_mbox']) {
2919 $_SESSION['return'][] = array(
2920 'type' => 'danger',
2921 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2922 'msg' => array('mailbox_quota_exceeded', $DomainData['max_quota_for_mbox'])
2923 );
2924 continue;
2925 }
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002926 $extra_acls = array();
2927 if (isset($_data['extended_sender_acl'])) {
2928 if (!isset($_SESSION['acl']['extend_sender_acl']) || $_SESSION['acl']['extend_sender_acl'] != "1" ) {
2929 $_SESSION['return'][] = array(
2930 'type' => 'danger',
2931 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01002932 'msg' => 'extended_sender_acl_denied'
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002933 );
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002934 }
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01002935 else {
2936 $extra_acls = array_map('trim', preg_split( "/( |,|;|\n)/", $_data['extended_sender_acl']));
2937 foreach ($extra_acls as $i => &$extra_acl) {
2938 if (empty($extra_acl)) {
2939 continue;
2940 }
2941 if (substr($extra_acl, 0, 1) === "@") {
2942 $extra_acl = ltrim($extra_acl, '@');
2943 }
2944 if (!filter_var($extra_acl, FILTER_VALIDATE_EMAIL) && !is_valid_domain_name($extra_acl)) {
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002945 $_SESSION['return'][] = array(
2946 'type' => 'danger',
2947 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01002948 'msg' => array('extra_acl_invalid', htmlspecialchars($extra_acl))
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002949 );
2950 unset($extra_acls[$i]);
2951 continue;
2952 }
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01002953 $domains = array_merge(mailbox('get', 'domains'), mailbox('get', 'alias_domains'));
2954 if (filter_var($extra_acl, FILTER_VALIDATE_EMAIL)) {
2955 $extra_acl_domain = idn_to_ascii(substr(strstr($extra_acl, '@'), 1), 0, INTL_IDNA_VARIANT_UTS46);
2956 if (in_array($extra_acl_domain, $domains)) {
2957 $_SESSION['return'][] = array(
2958 'type' => 'danger',
2959 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2960 'msg' => array('extra_acl_invalid_domain', $extra_acl_domain)
2961 );
2962 unset($extra_acls[$i]);
2963 continue;
2964 }
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002965 }
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01002966 else {
2967 if (in_array($extra_acl, $domains)) {
2968 $_SESSION['return'][] = array(
2969 'type' => 'danger',
2970 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2971 'msg' => array('extra_acl_invalid_domain', $extra_acl_domain)
2972 );
2973 unset($extra_acls[$i]);
2974 continue;
2975 }
2976 $extra_acl = '@' . $extra_acl;
2977 }
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002978 }
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01002979 $extra_acls = array_filter($extra_acls);
2980 $extra_acls = array_values($extra_acls);
2981 $extra_acls = array_unique($extra_acls);
2982 $stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `external` = 1 AND `logged_in_as` = :username");
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002983 $stmt->execute(array(
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002984 ':username' => $username
2985 ));
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01002986 foreach ($extra_acls as $sender_acl_external) {
2987 $stmt = $pdo->prepare("INSERT INTO `sender_acl` (`send_as`, `logged_in_as`, `external`)
2988 VALUES (:sender_acl, :username, 1)");
2989 $stmt->execute(array(
2990 ':sender_acl' => $sender_acl_external,
2991 ':username' => $username
2992 ));
2993 }
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01002994 }
2995 }
2996 if (isset($_data['sender_acl'])) {
2997 // Get sender_acl items set by admin
2998 $sender_acl_admin = array_merge(
2999 mailbox('get', 'sender_acl_handles', $username)['sender_acl_domains']['ro'],
3000 mailbox('get', 'sender_acl_handles', $username)['sender_acl_addresses']['ro']
3001 );
3002 // Get sender_acl items from POST array
3003 // Set sender_acl_domain_admin to empty array if sender_acl contains "default" to trigger a reset
3004 // Delete records from sender_acl if sender_acl contains "*" and set to array("*")
3005 $_data['sender_acl'] = (array)$_data['sender_acl'];
3006 if (in_array("*", $_data['sender_acl'])) {
3007 $sender_acl_domain_admin = array('*');
3008 }
3009 elseif (array("default") === $_data['sender_acl']) {
3010 $sender_acl_domain_admin = array();
3011 }
3012 else {
3013 if (array_search('default', $_data['sender_acl']) !== false){
3014 unset($_data['sender_acl'][array_search('default', $_data['sender_acl'])]);
3015 }
3016 $sender_acl_domain_admin = $_data['sender_acl'];
3017 }
3018 if (!empty($sender_acl_domain_admin) || !empty($sender_acl_admin)) {
3019 // Check items in POST array and skip invalid
3020 foreach ($sender_acl_domain_admin as $key => $val) {
3021 // Check for invalid domain or email format or not *
3022 if (!filter_var($val, FILTER_VALIDATE_EMAIL) && !is_valid_domain_name(ltrim($val, '@')) && $val != '*') {
3023 $_SESSION['return'][] = array(
3024 'type' => 'danger',
3025 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3026 'msg' => array('sender_acl_invalid', $sender_acl_domain_admin[$key])
3027 );
3028 unset($sender_acl_domain_admin[$key]);
3029 continue;
3030 }
3031 // Check if user has domain access (if object is domain)
3032 $domain = ltrim($sender_acl_domain_admin[$key], '@');
3033 if (is_valid_domain_name($domain)) {
3034 // Check for- and skip non-mailcow domains
3035 $domains = array_merge(mailbox('get', 'domains'), mailbox('get', 'alias_domains'));
3036 if (!empty($domains)) {
3037 if (!in_array($domain, $domains)) {
3038 $_SESSION['return'][] = array(
3039 'type' => 'danger',
3040 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3041 'msg' => array('sender_acl_invalid', $sender_acl_domain_admin[$key])
3042 );
3043 unset($sender_acl_domain_admin[$key]);
3044 continue;
3045 }
3046 }
3047 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
3048 $_SESSION['return'][] = array(
3049 'type' => 'danger',
3050 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3051 'msg' => array('sender_acl_invalid', $sender_acl_domain_admin[$key])
3052 );
3053 unset($sender_acl_domain_admin[$key]);
3054 continue;
3055 }
3056 }
3057 // Wildcard can only be used if role == admin
3058 if ($val == '*' && $_SESSION['mailcow_cc_role'] != 'admin') {
3059 $_SESSION['return'][] = array(
3060 'type' => 'danger',
3061 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3062 'msg' => array('sender_acl_invalid', $sender_acl_domain_admin[$key])
3063 );
3064 unset($sender_acl_domain_admin[$key]);
3065 continue;
3066 }
3067 // Check if user has alias access (if object is email)
3068 if (filter_var($val, FILTER_VALIDATE_EMAIL)) {
3069 if (!hasAliasObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $val)) {
3070 $_SESSION['return'][] = array(
3071 'type' => 'danger',
3072 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3073 'msg' => array('sender_acl_invalid', $sender_acl_domain_admin[$key])
3074 );
3075 unset($sender_acl_domain_admin[$key]);
3076 continue;
3077 }
3078 }
3079 }
3080 // Merge both arrays
3081 $sender_acl_merged = array_merge($sender_acl_domain_admin, $sender_acl_admin);
3082 // If merged array still contains "*", set it as only value
3083 !in_array('*', $sender_acl_merged) ?: $sender_acl_merged = array('*');
3084 $stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `external` = 0 AND `logged_in_as` = :username");
3085 $stmt->execute(array(
3086 ':username' => $username
3087 ));
3088 $fixed_sender_aliases = mailbox('get', 'sender_acl_handles', $username)['fixed_sender_aliases'];
3089 foreach ($sender_acl_merged as $sender_acl) {
3090 $domain = ltrim($sender_acl, '@');
3091 if (is_valid_domain_name($domain)) {
3092 $sender_acl = '@' . $domain;
3093 }
3094 // Don't add if allowed by alias
3095 if (in_array($sender_acl, $fixed_sender_aliases)) {
3096 continue;
3097 }
3098 $stmt = $pdo->prepare("INSERT INTO `sender_acl` (`send_as`, `logged_in_as`)
3099 VALUES (:sender_acl, :username)");
3100 $stmt->execute(array(
3101 ':sender_acl' => $sender_acl,
3102 ':username' => $username
3103 ));
3104 }
3105 }
3106 else {
3107 $stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `external` = 0 AND `logged_in_as` = :username");
3108 $stmt->execute(array(
3109 ':username' => $username
3110 ));
3111 }
3112 }
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02003113 if (!empty($password)) {
3114 if (password_check($password, $password2) !== true) {
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01003115 continue;
3116 }
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02003117 $password_hashed = hash_password($password);
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01003118 $stmt = $pdo->prepare("UPDATE `mailbox` SET
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02003119 `password` = :password_hashed,
3120 `attributes` = JSON_SET(`attributes`, '$.passwd_update', NOW())
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01003121 WHERE `username` = :username");
3122 $stmt->execute(array(
3123 ':password_hashed' => $password_hashed,
3124 ':username' => $username
3125 ));
3126 }
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02003127 // We could either set alias = 1 if alias = 2 or tune the Postfix alias table (that's what we did, TODO: do it the other way)
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01003128 $stmt = $pdo->prepare("UPDATE `alias` SET
3129 `active` = :active
3130 WHERE `address` = :address");
3131 $stmt->execute(array(
3132 ':address' => $username,
3133 ':active' => $active
3134 ));
3135 $stmt = $pdo->prepare("UPDATE `mailbox` SET
3136 `active` = :active,
3137 `name`= :name,
3138 `quota` = :quota_b,
3139 `attributes` = JSON_SET(`attributes`, '$.force_pw_update', :force_pw_update),
3140 `attributes` = JSON_SET(`attributes`, '$.sogo_access', :sogo_access),
3141 `attributes` = JSON_SET(`attributes`, '$.imap_access', :imap_access),
Matthias Andreas Benkardb4b5cc12021-12-28 18:02:04 +01003142 `attributes` = JSON_SET(`attributes`, '$.sieve_access', :sieve_access),
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01003143 `attributes` = JSON_SET(`attributes`, '$.pop3_access', :pop3_access),
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02003144 `attributes` = JSON_SET(`attributes`, '$.relayhost', :relayhost),
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01003145 `attributes` = JSON_SET(`attributes`, '$.smtp_access', :smtp_access)
3146 WHERE `username` = :username");
3147 $stmt->execute(array(
3148 ':active' => $active,
3149 ':name' => $name,
3150 ':quota_b' => $quota_b,
3151 ':force_pw_update' => $force_pw_update,
3152 ':sogo_access' => $sogo_access,
3153 ':imap_access' => $imap_access,
3154 ':pop3_access' => $pop3_access,
Matthias Andreas Benkardb4b5cc12021-12-28 18:02:04 +01003155 ':sieve_access' => $sieve_access,
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01003156 ':smtp_access' => $smtp_access,
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02003157 ':relayhost' => $relayhost,
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01003158 ':username' => $username
3159 ));
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01003160 // save tags
3161 foreach($tags as $index => $tag){
3162 if (empty($tag)) continue;
3163 if ($index > $GLOBALS['TAGGING_LIMIT']) {
3164 $_SESSION['return'][] = array(
3165 'type' => 'warning',
3166 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3167 'msg' => array('tag_limit_exceeded', 'limit '.$GLOBALS['TAGGING_LIMIT'])
3168 );
3169 break;
3170 }
3171 $stmt = $pdo->prepare("INSERT INTO `tags_mailbox` (`username`, `tag_name`) VALUES (:username, :tag_name)");
3172 $stmt->execute(array(
3173 ':username' => $username,
3174 ':tag_name' => $tag,
3175 ));
3176 }
3177
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01003178 $_SESSION['return'][] = array(
3179 'type' => 'success',
3180 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3181 'msg' => array('mailbox_modified', $username)
3182 );
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01003183
3184 update_sogo_static_view($username);
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01003185 }
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01003186 return true;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01003187 break;
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01003188 case 'mailbox_templates':
3189 if ($_SESSION['mailcow_cc_role'] != "admin") {
3190 $_SESSION['return'][] = array(
3191 'type' => 'danger',
3192 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
3193 'msg' => 'access_denied'
3194 );
3195 return false;
3196 }
3197 if (!is_array($_data['ids'])) {
3198 $ids = array();
3199 $ids[] = $_data['ids'];
3200 }
3201 else {
3202 $ids = $_data['ids'];
3203 }
3204 foreach ($ids as $id) {
3205 $is_now = mailbox("get", "mailbox_templates", $id);
3206 if (empty($is_now) ||
3207 $is_now["type"] != "mailbox"){
3208 $_SESSION['return'][] = array(
3209 'type' => 'danger',
3210 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
3211 'msg' => 'template_id_invalid'
3212 );
3213 continue;
3214 }
3215
3216
3217 // check name
3218 if ($is_now["template"] == "Default" && $is_now["template"] != $_data["template"]){
3219 // keep template name of Default template
3220 $_data["template"] = $is_now["template"];
3221 }
3222 else {
3223 $_data["template"] = (isset($_data["template"])) ? $_data["template"] : $is_now["template"];
3224 }
3225 // check attributes
3226 $attr = array();
3227 $attr["quota"] = isset($_data['quota']) ? intval($_data['quota']) * 1048576 : 0;
3228 $attr['tags'] = (isset($_data['tags'])) ? $_data['tags'] : $is_now['tags'];
3229 $attr["quarantine_notification"] = (!empty($_data['quarantine_notification'])) ? $_data['quarantine_notification'] : $is_now['quarantine_notification'];
3230 $attr["quarantine_category"] = (!empty($_data['quarantine_category'])) ? $_data['quarantine_category'] : $is_now['quarantine_category'];
3231 $attr["rl_frame"] = (!empty($_data['rl_frame'])) ? $_data['rl_frame'] : $is_now['rl_frame'];
3232 $attr["rl_value"] = (!empty($_data['rl_value'])) ? $_data['rl_value'] : $is_now['rl_value'];
3233 $attr["force_pw_update"] = isset($_data['force_pw_update']) ? intval($_data['force_pw_update']) : $is_now['force_pw_update'];
3234 $attr["sogo_access"] = isset($_data['sogo_access']) ? intval($_data['sogo_access']) : $is_now['sogo_access'];
3235 $attr["active"] = isset($_data['active']) ? intval($_data['active']) : $is_now['active'];
3236 $attr["tls_enforce_in"] = isset($_data['tls_enforce_in']) ? intval($_data['tls_enforce_in']) : $is_now['tls_enforce_in'];
3237 $attr["tls_enforce_out"] = isset($_data['tls_enforce_out']) ? intval($_data['tls_enforce_out']) : $is_now['tls_enforce_out'];
3238 if (isset($_data['protocol_access'])) {
3239 $_data['protocol_access'] = (array)$_data['protocol_access'];
3240 $attr['imap_access'] = (in_array('imap', $_data['protocol_access'])) ? 1 : 0;
3241 $attr['pop3_access'] = (in_array('pop3', $_data['protocol_access'])) ? 1 : 0;
3242 $attr['smtp_access'] = (in_array('smtp', $_data['protocol_access'])) ? 1 : 0;
3243 $attr['sieve_access'] = (in_array('sieve', $_data['protocol_access'])) ? 1 : 0;
3244 }
3245 else {
3246 foreach ($is_now as $key => $value){
3247 $attr[$key] = $is_now[$key];
3248 }
3249 }
3250 if (isset($_data['acl'])) {
3251 $_data['acl'] = (array)$_data['acl'];
3252 $attr['acl_spam_alias'] = (in_array('spam_alias', $_data['acl'])) ? 1 : 0;
3253 $attr['acl_tls_policy'] = (in_array('tls_policy', $_data['acl'])) ? 1 : 0;
3254 $attr['acl_spam_score'] = (in_array('spam_score', $_data['acl'])) ? 1 : 0;
3255 $attr['acl_spam_policy'] = (in_array('spam_policy', $_data['acl'])) ? 1 : 0;
3256 $attr['acl_delimiter_action'] = (in_array('delimiter_action', $_data['acl'])) ? 1 : 0;
3257 $attr['acl_syncjobs'] = (in_array('syncjobs', $_data['acl'])) ? 1 : 0;
3258 $attr['acl_eas_reset'] = (in_array('eas_reset', $_data['acl'])) ? 1 : 0;
3259 $attr['acl_sogo_profile_reset'] = (in_array('sogo_profile_reset', $_data['acl'])) ? 1 : 0;
3260 $attr['acl_pushover'] = (in_array('pushover', $_data['acl'])) ? 1 : 0;
3261 $attr['acl_quarantine'] = (in_array('quarantine', $_data['acl'])) ? 1 : 0;
3262 $attr['acl_quarantine_attachments'] = (in_array('quarantine_attachments', $_data['acl'])) ? 1 : 0;
3263 $attr['acl_quarantine_notification'] = (in_array('quarantine_notification', $_data['acl'])) ? 1 : 0;
3264 $attr['acl_quarantine_category'] = (in_array('quarantine_category', $_data['acl'])) ? 1 : 0;
3265 $attr['acl_app_passwds'] = (in_array('app_passwds', $_data['acl'])) ? 1 : 0;
3266 } else {
3267 foreach ($is_now as $key => $value){
3268 $attr[$key] = $is_now[$key];
3269 }
3270 }
3271
3272
3273 // update template
3274 $stmt = $pdo->prepare("UPDATE `templates`
3275 SET `template` = :template, `attributes` = :attributes
3276 WHERE id = :id");
3277 $stmt->execute(array(
3278 ":id" => $id ,
3279 ":template" => $_data["template"] ,
3280 ":attributes" => json_encode($attr)
3281 ));
3282 }
3283
3284
3285 $_SESSION['return'][] = array(
3286 'type' => 'success',
3287 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3288 'msg' => array('template_modified', $_data["template"])
3289 );
3290 return true;
3291 break;
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01003292 case 'mailbox_custom_attribute':
3293 $_data['attribute'] = isset($_data['attribute']) ? $_data['attribute'] : array();
3294 $_data['attribute'] = is_array($_data['attribute']) ? $_data['attribute'] : array($_data['attribute']);
3295 $_data['attribute'] = array_map(function($value) { return str_replace(' ', '', $value); }, $_data['attribute']);
3296 $_data['value'] = isset($_data['value']) ? $_data['value'] : array();
3297 $_data['value'] = is_array($_data['value']) ? $_data['value'] : array($_data['value']);
3298 $attributes = (object)array_combine($_data['attribute'], $_data['value']);
3299 $mailboxes = is_array($_data['mailboxes']) ? $_data['mailboxes'] : array($_data['mailboxes']);
3300
3301 foreach ($mailboxes as $mailbox) {
3302 if (!filter_var($mailbox, FILTER_VALIDATE_EMAIL)) {
3303 $_SESSION['return'][] = array(
3304 'type' => 'danger',
3305 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3306 'msg' => array('username_invalid', $mailbox)
3307 );
3308 continue;
3309 }
3310 $is_now = mailbox('get', 'mailbox_details', $mailbox);
3311 if(!empty($is_now)){
3312 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $is_now['domain'])) {
3313 $_SESSION['return'][] = array(
3314 'type' => 'danger',
3315 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3316 'msg' => 'access_denied'
3317 );
3318 continue;
3319 }
3320 }
3321 else {
3322 $_SESSION['return'][] = array(
3323 'type' => 'danger',
3324 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3325 'msg' => 'access_denied'
3326 );
3327 continue;
3328 }
3329
3330
3331 $stmt = $pdo->prepare("UPDATE `mailbox`
3332 SET `custom_attributes` = :custom_attributes
3333 WHERE username = :username");
3334 $stmt->execute(array(
3335 ":username" => $mailbox,
3336 ":custom_attributes" => json_encode($attributes)
3337 ));
3338
3339 $_SESSION['return'][] = array(
3340 'type' => 'success',
3341 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3342 'msg' => array('mailbox_modified', $mailbox)
3343 );
3344 }
3345
3346 return true;
3347 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01003348 case 'resource':
3349 if (!is_array($_data['name'])) {
3350 $names = array();
3351 $names[] = $_data['name'];
3352 }
3353 else {
3354 $names = $_data['name'];
3355 }
3356 foreach ($names as $name) {
3357 $is_now = mailbox('get', 'resource_details', $name);
3358 if (!empty($is_now)) {
3359 $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
3360 $multiple_bookings = (isset($_data['multiple_bookings'])) ? intval($_data['multiple_bookings']) : $is_now['multiple_bookings'];
3361 $description = (!empty($_data['description'])) ? $_data['description'] : $is_now['description'];
3362 $kind = (!empty($_data['kind'])) ? $_data['kind'] : $is_now['kind'];
3363 }
3364 else {
3365 $_SESSION['return'][] = array(
3366 'type' => 'danger',
3367 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3368 'msg' => array('resource_invalid', htmlspecialchars($name))
3369 );
3370 continue;
3371 }
3372 if (!filter_var($name, FILTER_VALIDATE_EMAIL)) {
3373 $_SESSION['return'][] = array(
3374 'type' => 'danger',
3375 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3376 'msg' => array('resource_invalid', htmlspecialchars($name))
3377 );
3378 continue;
3379 }
3380 if (!isset($multiple_bookings) || $multiple_bookings < -1) {
3381 $multiple_bookings = -1;
3382 }
3383 if (empty($description)) {
3384 $_SESSION['return'][] = array(
3385 'type' => 'danger',
3386 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3387 'msg' => array('description_invalid', htmlspecialchars($name))
3388 );
3389 continue;
3390 }
3391 if ($kind != 'location' && $kind != 'group' && $kind != 'thing') {
3392 $_SESSION['return'][] = array(
3393 'type' => 'danger',
3394 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3395 'msg' => array('resource_invalid', htmlspecialchars($name))
3396 );
3397 continue;
3398 }
3399 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $name)) {
3400 $_SESSION['return'][] = array(
3401 'type' => 'danger',
3402 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3403 'msg' => 'access_denied'
3404 );
3405 continue;
3406 }
3407 $stmt = $pdo->prepare("UPDATE `mailbox` SET
3408 `active` = :active,
3409 `name`= :description,
3410 `kind`= :kind,
3411 `multiple_bookings`= :multiple_bookings
3412 WHERE `username` = :name");
3413 $stmt->execute(array(
3414 ':active' => $active,
3415 ':description' => $description,
3416 ':multiple_bookings' => $multiple_bookings,
3417 ':kind' => $kind,
3418 ':name' => $name
3419 ));
3420 $_SESSION['return'][] = array(
3421 'type' => 'success',
3422 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3423 'msg' => array('resource_modified', htmlspecialchars($name))
3424 );
3425 }
3426 break;
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01003427 case 'domain_wide_footer':
3428 if (!is_array($_data['domains'])) {
3429 $domains = array();
3430 $domains[] = $_data['domains'];
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01003431 }
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01003432 else {
3433 $domains = $_data['domains'];
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01003434 }
3435
3436 $footers = array();
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01003437 $footers['html'] = isset($_data['html']) ? $_data['html'] : '';
3438 $footers['plain'] = isset($_data['plain']) ? $_data['plain'] : '';
3439 $footers['skip_replies'] = isset($_data['skip_replies']) ? (int)$_data['skip_replies'] : 0;
3440 $footers['mbox_exclude'] = array();
3441 $footers['alias_domain_exclude'] = array();
3442 if (isset($_data["exclude"])){
3443 if (!is_array($_data["exclude"])) {
3444 $_data["exclude"] = array($_data["exclude"]);
3445 }
3446 foreach ($_data["exclude"] as $exclude) {
3447 if (filter_var($exclude, FILTER_VALIDATE_EMAIL)) {
3448 $stmt = $pdo->prepare("SELECT `address` FROM `alias` WHERE `address` = :address
3449 UNION
3450 SELECT `username` FROM `mailbox` WHERE `username` = :username");
3451 $stmt->execute(array(
3452 ':address' => $exclude,
3453 ':username' => $exclude,
3454 ));
3455 $row = $stmt->fetch(PDO::FETCH_ASSOC);
3456 if(!$row){
3457 $_SESSION['return'][] = array(
3458 'type' => 'danger',
3459 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3460 'msg' => array('username_invalid', $exclude)
3461 );
3462 continue;
3463 }
3464 array_push($footers['mbox_exclude'], $exclude);
3465 }
3466 elseif (is_valid_domain_name($exclude)) {
3467 $stmt = $pdo->prepare("SELECT `alias_domain` FROM `alias_domain` WHERE `alias_domain` = :alias_domain");
3468 $stmt->execute(array(
3469 ':alias_domain' => $exclude,
3470 ));
3471 $row = $stmt->fetch(PDO::FETCH_ASSOC);
3472 if(!$row){
3473 $_SESSION['return'][] = array(
3474 'type' => 'danger',
3475 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3476 'msg' => array('username_invalid', $exclude)
3477 );
3478 continue;
3479 }
3480 array_push($footers['alias_domain_exclude'], $exclude);
3481 }
3482 else {
3483 $_SESSION['return'][] = array(
3484 'type' => 'danger',
3485 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3486 'msg' => array('username_invalid', $exclude)
3487 );
3488 }
3489 }
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01003490 }
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01003491 foreach ($domains as $domain) {
3492 $domain = idn_to_ascii(strtolower(trim($domain)), 0, INTL_IDNA_VARIANT_UTS46);
3493 if (!is_valid_domain_name($domain)) {
3494 $_SESSION['return'][] = array(
3495 'type' => 'danger',
3496 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3497 'msg' => 'domain_invalid'
3498 );
3499 return false;
3500 }
3501 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
3502 $_SESSION['return'][] = array(
3503 'type' => 'danger',
3504 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3505 'msg' => 'access_denied'
3506 );
3507 return false;
3508 }
3509
3510 try {
3511 $stmt = $pdo->prepare("DELETE FROM `domain_wide_footer` WHERE `domain`= :domain");
3512 $stmt->execute(array(':domain' => $domain));
3513 $stmt = $pdo->prepare("INSERT INTO `domain_wide_footer` (`domain`, `html`, `plain`, `mbox_exclude`, `alias_domain_exclude`, `skip_replies`) VALUES (:domain, :html, :plain, :mbox_exclude, :alias_domain_exclude, :skip_replies)");
3514 $stmt->execute(array(
3515 ':domain' => $domain,
3516 ':html' => $footers['html'],
3517 ':plain' => $footers['plain'],
3518 ':mbox_exclude' => json_encode($footers['mbox_exclude']),
3519 ':alias_domain_exclude' => json_encode($footers['alias_domain_exclude']),
3520 ':skip_replies' => $footers['skip_replies'],
3521 ));
3522 }
3523 catch (PDOException $e) {
3524 $_SESSION['return'][] = array(
3525 'type' => 'danger',
3526 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3527 'msg' => $e->getMessage()
3528 );
3529 return false;
3530 }
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01003531 $_SESSION['return'][] = array(
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01003532 'type' => 'success',
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01003533 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01003534 'msg' => array('domain_footer_modified', htmlspecialchars($domain))
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01003535 );
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01003536 }
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01003537 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01003538 }
3539 break;
3540 case 'get':
3541 switch ($_type) {
3542 case 'sender_acl_handles':
3543 if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") {
3544 return false;
3545 }
3546 $data['sender_acl_domains']['ro'] = array();
3547 $data['sender_acl_domains']['rw'] = array();
3548 $data['sender_acl_domains']['selectable'] = array();
3549 $data['sender_acl_addresses']['ro'] = array();
3550 $data['sender_acl_addresses']['rw'] = array();
3551 $data['sender_acl_addresses']['selectable'] = array();
3552 $data['fixed_sender_aliases'] = array();
3553 $data['external_sender_aliases'] = array();
3554 // Fixed addresses
3555 $stmt = $pdo->prepare("SELECT `address` FROM `alias` WHERE `goto` REGEXP :goto AND `address` NOT LIKE '@%'");
3556 $stmt->execute(array(':goto' => '(^|,)'.$_data.'($|,)'));
3557 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
3558 while ($row = array_shift($rows)) {
3559 $data['fixed_sender_aliases'][] = $row['address'];
3560 }
3561 $stmt = $pdo->prepare("SELECT CONCAT(`local_part`, '@', `alias_domain`.`alias_domain`) AS `alias_domain_alias` FROM `mailbox`, `alias_domain`
3562 WHERE `alias_domain`.`target_domain` = `mailbox`.`domain`
3563 AND `mailbox`.`username` = :username");
3564 $stmt->execute(array(':username' => $_data));
3565 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
3566 while ($row = array_shift($rows)) {
3567 if (!empty($row['alias_domain_alias'])) {
3568 $data['fixed_sender_aliases'][] = $row['alias_domain_alias'];
3569 }
3570 }
3571 // External addresses
3572 $stmt = $pdo->prepare("SELECT `send_as` as `send_as_external` FROM `sender_acl` WHERE `logged_in_as` = :logged_in_as AND `external` = '1'");
3573 $stmt->execute(array(':logged_in_as' => $_data));
3574 $exernal_rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
3575 while ($row = array_shift($exernal_rows)) {
3576 if (!empty($row['send_as_external'])) {
3577 $data['external_sender_aliases'][] = $row['send_as_external'];
3578 }
3579 }
3580 // Return array $data['sender_acl_domains/addresses']['ro'] with read-only objects
3581 // Return array $data['sender_acl_domains/addresses']['rw'] with read-write objects (can be deleted)
3582 $stmt = $pdo->prepare("SELECT REPLACE(`send_as`, '@', '') AS `send_as` FROM `sender_acl` WHERE `logged_in_as` = :logged_in_as AND `external` = '0' AND (`send_as` LIKE '@%' OR `send_as` = '*')");
3583 $stmt->execute(array(':logged_in_as' => $_data));
3584 $domain_rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
3585 while ($domain_row = array_shift($domain_rows)) {
3586 if (is_valid_domain_name($domain_row['send_as']) && !hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain_row['send_as'])) {
3587 $data['sender_acl_domains']['ro'][] = $domain_row['send_as'];
3588 continue;
3589 }
3590 if (is_valid_domain_name($domain_row['send_as']) && hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain_row['send_as'])) {
3591 $data['sender_acl_domains']['rw'][] = $domain_row['send_as'];
3592 continue;
3593 }
3594 if ($domain_row['send_as'] == '*' && $_SESSION['mailcow_cc_role'] != 'admin') {
3595 $data['sender_acl_domains']['ro'][] = $domain_row['send_as'];
3596 }
3597 if ($domain_row['send_as'] == '*' && $_SESSION['mailcow_cc_role'] == 'admin') {
3598 $data['sender_acl_domains']['rw'][] = $domain_row['send_as'];
3599 }
3600 }
3601 $stmt = $pdo->prepare("SELECT `send_as` FROM `sender_acl` WHERE `logged_in_as` = :logged_in_as AND `external` = '0' AND (`send_as` NOT LIKE '@%' AND `send_as` != '*')");
3602 $stmt->execute(array(':logged_in_as' => $_data));
3603 $address_rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
3604 while ($address_row = array_shift($address_rows)) {
3605 if (filter_var($address_row['send_as'], FILTER_VALIDATE_EMAIL) && !hasAliasObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $address_row['send_as'])) {
3606 $data['sender_acl_addresses']['ro'][] = $address_row['send_as'];
3607 continue;
3608 }
3609 if (filter_var($address_row['send_as'], FILTER_VALIDATE_EMAIL) && hasAliasObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $address_row['send_as'])) {
3610 $data['sender_acl_addresses']['rw'][] = $address_row['send_as'];
3611 continue;
3612 }
3613 }
3614 $stmt = $pdo->prepare("SELECT `domain` FROM `domain`
3615 WHERE `domain` NOT IN (
3616 SELECT REPLACE(`send_as`, '@', '') FROM `sender_acl`
3617 WHERE `logged_in_as` = :logged_in_as1
3618 AND `external` = '0'
3619 AND `send_as` LIKE '@%')
3620 UNION
3621 SELECT '*' FROM `domain`
3622 WHERE '*' NOT IN (
3623 SELECT `send_as` FROM `sender_acl`
3624 WHERE `logged_in_as` = :logged_in_as2
3625 AND `external` = '0'
3626 )");
3627 $stmt->execute(array(
3628 ':logged_in_as1' => $_data,
3629 ':logged_in_as2' => $_data
3630 ));
3631 $rows_domain = $stmt->fetchAll(PDO::FETCH_ASSOC);
3632 while ($row_domain = array_shift($rows_domain)) {
3633 if (is_valid_domain_name($row_domain['domain']) && hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $row_domain['domain'])) {
3634 $data['sender_acl_domains']['selectable'][] = $row_domain['domain'];
3635 continue;
3636 }
3637 if ($row_domain['domain'] == '*' && $_SESSION['mailcow_cc_role'] == 'admin') {
3638 $data['sender_acl_domains']['selectable'][] = $row_domain['domain'];
3639 continue;
3640 }
3641 }
3642 $stmt = $pdo->prepare("SELECT `address` FROM `alias`
3643 WHERE `goto` != :goto
3644 AND `address` NOT IN (
3645 SELECT `send_as` FROM `sender_acl`
3646 WHERE `logged_in_as` = :logged_in_as
3647 AND `external` = '0'
3648 AND `send_as` NOT LIKE '@%')");
3649 $stmt->execute(array(
3650 ':logged_in_as' => $_data,
3651 ':goto' => $_data
3652 ));
3653 $rows_mbox = $stmt->fetchAll(PDO::FETCH_ASSOC);
3654 while ($row = array_shift($rows_mbox)) {
3655 // Aliases are not selectable
3656 if (in_array($row['address'], $data['fixed_sender_aliases'])) {
3657 continue;
3658 }
3659 if (filter_var($row['address'], FILTER_VALIDATE_EMAIL) && hasAliasObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $row['address'])) {
3660 $data['sender_acl_addresses']['selectable'][] = $row['address'];
3661 }
3662 }
3663 return $data;
3664 break;
3665 case 'mailboxes':
3666 $mailboxes = array();
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01003667 if (isset($_extra) && is_array($_extra) && isset($_data)) {
3668 // get by domain and tags
3669 $tags = is_array($_extra) ? $_extra : array();
3670
3671 $sql = "";
3672 foreach ($tags as $key => $tag) {
3673 $sql = $sql."SELECT DISTINCT `username` FROM `tags_mailbox` WHERE `username` LIKE ? AND `tag_name` LIKE ?"; // distinct, avoid duplicates
3674 if ($key === array_key_last($tags)) break;
3675 $sql = $sql.' UNION DISTINCT '; // combine querys with union - distinct, avoid duplicates
3676 }
3677
3678 // prepend domain to array
3679 $params = array();
3680 foreach ($tags as $key => $val){
3681 array_push($params, '%'.$_data.'%');
3682 array_push($params, '%'.$val.'%');
3683 }
3684 $stmt = $pdo->prepare($sql);
3685 $stmt->execute($params);
3686
3687 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
3688 while($row = array_shift($rows)) {
3689 if (hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], explode('@', $row['username'])[1]))
3690 $mailboxes[] = $row['username'];
3691 }
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01003692 }
3693 elseif (isset($_data) && hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01003694 // get by domain
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02003695 $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE (`kind` = '' OR `kind` = NULL) AND `domain` = :domain");
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01003696 $stmt->execute(array(
3697 ':domain' => $_data,
3698 ));
3699 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
3700 while($row = array_shift($rows)) {
3701 $mailboxes[] = $row['username'];
3702 }
3703 }
3704 else {
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02003705 $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE (`kind` = '' OR `kind` = NULL) AND (`domain` IN (SELECT `domain` FROM `domain_admins` WHERE `active` = '1' AND `username` = :username) OR 'admin' = :role)");
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01003706 $stmt->execute(array(
3707 ':username' => $_SESSION['mailcow_cc_username'],
3708 ':role' => $_SESSION['mailcow_cc_role'],
3709 ));
3710 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
3711 while($row = array_shift($rows)) {
3712 $mailboxes[] = $row['username'];
3713 }
3714 }
3715 return $mailboxes;
3716 break;
3717 case 'tls_policy':
3718 $attrs = array();
3719 if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
3720 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
3721 return false;
3722 }
3723 }
3724 else {
3725 $_data = $_SESSION['mailcow_cc_username'];
3726 }
3727 $stmt = $pdo->prepare("SELECT `attributes` FROM `mailbox` WHERE `username` = :username");
3728 $stmt->execute(array(':username' => $_data));
3729 $attrs = $stmt->fetch(PDO::FETCH_ASSOC);
3730 $attrs = json_decode($attrs['attributes'], true);
3731 return array(
3732 'tls_enforce_in' => $attrs['tls_enforce_in'],
3733 'tls_enforce_out' => $attrs['tls_enforce_out']
3734 );
3735 break;
3736 case 'quarantine_notification':
3737 $attrs = array();
3738 if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
3739 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
3740 return false;
3741 }
3742 }
3743 else {
3744 $_data = $_SESSION['mailcow_cc_username'];
3745 }
3746 $stmt = $pdo->prepare("SELECT `attributes` FROM `mailbox` WHERE `username` = :username");
3747 $stmt->execute(array(':username' => $_data));
3748 $attrs = $stmt->fetch(PDO::FETCH_ASSOC);
3749 $attrs = json_decode($attrs['attributes'], true);
3750 return $attrs['quarantine_notification'];
3751 break;
3752 case 'quarantine_category':
3753 $attrs = array();
3754 if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
3755 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
3756 return false;
3757 }
3758 }
3759 else {
3760 $_data = $_SESSION['mailcow_cc_username'];
3761 }
3762 $stmt = $pdo->prepare("SELECT `attributes` FROM `mailbox` WHERE `username` = :username");
3763 $stmt->execute(array(':username' => $_data));
3764 $attrs = $stmt->fetch(PDO::FETCH_ASSOC);
3765 $attrs = json_decode($attrs['attributes'], true);
3766 return $attrs['quarantine_category'];
3767 break;
3768 case 'filters':
3769 $filters = array();
3770 if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
3771 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
3772 return false;
3773 }
3774 }
3775 else {
3776 $_data = $_SESSION['mailcow_cc_username'];
3777 }
3778 $stmt = $pdo->prepare("SELECT `id` FROM `sieve_filters` WHERE `username` = :username");
3779 $stmt->execute(array(':username' => $_data));
3780 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
3781 while($row = array_shift($rows)) {
3782 $filters[] = $row['id'];
3783 }
3784 return $filters;
3785 break;
3786 case 'global_filter_details':
3787 $global_filters = array();
3788 if ($_SESSION['mailcow_cc_role'] != "admin") {
3789 return false;
3790 }
3791 $global_filters['prefilter'] = file_get_contents('/global_sieve/before');
3792 $global_filters['postfilter'] = file_get_contents('/global_sieve/after');
3793 return $global_filters;
3794 break;
3795 case 'filter_details':
3796 $filter_details = array();
3797 if (!is_numeric($_data)) {
3798 return false;
3799 }
3800 $stmt = $pdo->prepare("SELECT CASE `script_name` WHEN 'active' THEN 1 ELSE 0 END AS `active`,
3801 id,
3802 username,
3803 filter_type,
3804 script_data,
3805 script_desc
3806 FROM `sieve_filters`
3807 WHERE `id` = :id");
3808 $stmt->execute(array(':id' => $_data));
3809 $filter_details = $stmt->fetch(PDO::FETCH_ASSOC);
3810 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $filter_details['username'])) {
3811 return false;
3812 }
3813 return $filter_details;
3814 break;
3815 case 'active_user_sieve':
3816 $filter_details = array();
3817 if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
3818 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
3819 return false;
3820 }
3821 }
3822 else {
3823 $_data = $_SESSION['mailcow_cc_username'];
3824 }
3825 $exec_fields = array(
3826 'cmd' => 'sieve',
3827 'task' => 'list',
3828 'username' => $_data
3829 );
3830 $filters = docker('post', 'dovecot-mailcow', 'exec', $exec_fields);
3831 $filters = array_filter(preg_split("/(\r\n|\n|\r)/",$filters));
3832 foreach ($filters as $filter) {
3833 if (preg_match('/.+ ACTIVE/i', $filter)) {
3834 $exec_fields = array(
3835 'cmd' => 'sieve',
3836 'task' => 'print',
3837 'script_name' => substr($filter, 0, -7),
3838 'username' => $_data
3839 );
3840 $script = docker('post', 'dovecot-mailcow', 'exec', $exec_fields);
3841 // Remove first line
3842 return preg_replace('/^.+\n/', '', $script);
3843 }
3844 }
3845 return false;
3846 break;
3847 case 'syncjob_details':
3848 $syncjobdetails = array();
3849 if (!is_numeric($_data)) {
3850 return false;
3851 }
3852 if (isset($_extra) && in_array('no_log', $_extra)) {
3853 $field_query = $pdo->query('SHOW FIELDS FROM `imapsync` WHERE FIELD NOT IN ("returned_text", "password1")');
3854 $fields = $field_query->fetchAll(PDO::FETCH_ASSOC);
3855 while($field = array_shift($fields)) {
3856 $shown_fields[] = $field['Field'];
3857 }
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02003858 $stmt = $pdo->prepare("SELECT " . implode(',', (array)$shown_fields) . ",
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01003859 `active`
3860 FROM `imapsync` WHERE id = :id");
3861 }
3862 elseif (isset($_extra) && in_array('with_password', $_extra)) {
3863 $stmt = $pdo->prepare("SELECT *,
3864 `active`
3865 FROM `imapsync` WHERE id = :id");
3866 }
3867 else {
3868 $field_query = $pdo->query('SHOW FIELDS FROM `imapsync` WHERE FIELD NOT IN ("password1")');
3869 $fields = $field_query->fetchAll(PDO::FETCH_ASSOC);
3870 while($field = array_shift($fields)) {
3871 $shown_fields[] = $field['Field'];
3872 }
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02003873 $stmt = $pdo->prepare("SELECT " . implode(',', (array)$shown_fields) . ",
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01003874 `active`
3875 FROM `imapsync` WHERE id = :id");
3876 }
3877 $stmt->execute(array(':id' => $_data));
3878 $syncjobdetails = $stmt->fetch(PDO::FETCH_ASSOC);
3879 if (!empty($syncjobdetails['returned_text'])) {
3880 $syncjobdetails['log'] = $syncjobdetails['returned_text'];
3881 }
3882 else {
3883 $syncjobdetails['log'] = '';
3884 }
3885 unset($syncjobdetails['returned_text']);
3886 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $syncjobdetails['user2'])) {
3887 return false;
3888 }
3889 return $syncjobdetails;
3890 break;
3891 case 'syncjobs':
3892 $syncjobdata = array();
3893 if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
3894 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
3895 return false;
3896 }
3897 }
3898 else {
3899 $_data = $_SESSION['mailcow_cc_username'];
3900 }
3901 $stmt = $pdo->prepare("SELECT `id` FROM `imapsync` WHERE `user2` = :username");
3902 $stmt->execute(array(':username' => $_data));
3903 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
3904 while($row = array_shift($rows)) {
3905 $syncjobdata[] = $row['id'];
3906 }
3907 return $syncjobdata;
3908 break;
3909 case 'spam_score':
3910 $curl = curl_init();
3911 curl_setopt($curl, CURLOPT_UNIX_SOCKET_PATH, '/var/lib/rspamd/rspamd.sock');
3912 curl_setopt($curl, CURLOPT_URL,"http://rspamd/actions");
3913 curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
3914 $default_actions = curl_exec($curl);
3915 if (!curl_errno($curl)) {
3916 $data_array = json_decode($default_actions, true);
3917 curl_close($curl);
3918 foreach ($data_array as $data) {
3919 if ($data['action'] == 'reject') {
3920 $reject = $data['value'];
3921 continue;
3922 }
3923 elseif ($data['action'] == 'add header') {
3924 $add_header = $data['value'];
3925 continue;
3926 }
3927 }
3928 if (empty($add_header) || empty($reject)) {
3929 // Assume default, set warning
3930 $default = "5, 15";
3931 $_SESSION['return'][] = array(
3932 'type' => 'warning',
3933 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3934 'msg' => 'Could not determine servers default spam score, assuming default'
3935 );
3936 }
3937 else {
3938 $default = $add_header . ', ' . $reject;
3939 }
3940 }
3941 else {
3942 // Assume default, set warning
3943 $default = "5, 15";
3944 $_SESSION['return'][] = array(
3945 'type' => 'warning',
3946 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3947 'msg' => 'Could not determine servers default spam score, assuming default'
3948 );
3949 }
3950 curl_close($curl);
3951 $policydata = array();
3952 if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
3953 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
3954 return false;
3955 }
3956 }
3957 else {
3958 $_data = $_SESSION['mailcow_cc_username'];
3959 }
3960 $stmt = $pdo->prepare("SELECT `value` FROM `filterconf` WHERE `object` = :username AND
3961 (`option` = 'lowspamlevel' OR `option` = 'highspamlevel')");
3962 $stmt->execute(array(':username' => $_data));
3963 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
3964 if (empty($num_results)) {
3965 return $default;
3966 }
3967 else {
3968 $stmt = $pdo->prepare("SELECT `value` FROM `filterconf` WHERE `option` = 'highspamlevel' AND `object` = :username");
3969 $stmt->execute(array(':username' => $_data));
3970 $highspamlevel = $stmt->fetch(PDO::FETCH_ASSOC);
3971 $stmt = $pdo->prepare("SELECT `value` FROM `filterconf` WHERE `option` = 'lowspamlevel' AND `object` = :username");
3972 $stmt->execute(array(':username' => $_data));
3973 $lowspamlevel = $stmt->fetch(PDO::FETCH_ASSOC);
3974 return $lowspamlevel['value'].', '.$highspamlevel['value'];
3975 }
3976 break;
3977 case 'time_limited_aliases':
3978 $tladata = array();
3979 if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
3980 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
3981 return false;
3982 }
3983 }
3984 else {
3985 $_data = $_SESSION['mailcow_cc_username'];
3986 }
3987 $stmt = $pdo->prepare("SELECT `address`,
3988 `goto`,
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02003989 `validity`,
3990 `created`,
3991 `modified`
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01003992 FROM `spamalias`
3993 WHERE `goto` = :username
3994 AND `validity` >= :unixnow");
3995 $stmt->execute(array(':username' => $_data, ':unixnow' => time()));
3996 $tladata = $stmt->fetchAll(PDO::FETCH_ASSOC);
3997 return $tladata;
3998 break;
3999 case 'delimiter_action':
4000 $policydata = array();
4001 if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
4002 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
4003 return false;
4004 }
4005 }
4006 else {
4007 $_data = $_SESSION['mailcow_cc_username'];
4008 }
4009 try {
4010 if ($redis->hGet('RCPT_WANTS_SUBJECT_TAG', $_data)) {
4011 return "subject";
4012 }
4013 elseif ($redis->hGet('RCPT_WANTS_SUBFOLDER_TAG', $_data)) {
4014 return "subfolder";
4015 }
4016 else {
4017 return "none";
4018 }
4019 }
4020 catch (RedisException $e) {
4021 $_SESSION['return'][] = array(
4022 'type' => 'danger',
4023 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4024 'msg' => array('redis_error', $e)
4025 );
4026 return false;
4027 }
4028 break;
4029 case 'resources':
4030 $resources = array();
4031 if (isset($_data) && !hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
4032 return false;
4033 }
4034 elseif (isset($_data) && hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
4035 $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `kind` REGEXP 'location|thing|group' AND `domain` = :domain");
4036 $stmt->execute(array(
4037 ':domain' => $_data,
4038 ));
4039 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
4040 while($row = array_shift($rows)) {
4041 $resources[] = $row['username'];
4042 }
4043 }
4044 else {
4045 $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `kind` REGEXP 'location|thing|group' AND `domain` IN (SELECT `domain` FROM `domain_admins` WHERE `active` = '1' AND `username` = :username) OR 'admin' = :role");
4046 $stmt->execute(array(
4047 ':username' => $_SESSION['mailcow_cc_username'],
4048 ':role' => $_SESSION['mailcow_cc_role'],
4049 ));
4050 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
4051 while($row = array_shift($rows)) {
4052 $resources[] = $row['username'];
4053 }
4054 }
4055 return $resources;
4056 break;
4057 case 'alias_domains':
4058 $aliasdomains = array();
4059 if (isset($_data) && !hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
4060 return false;
4061 }
4062 elseif (isset($_data) && hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
4063 $stmt = $pdo->prepare("SELECT `alias_domain` FROM `alias_domain` WHERE `target_domain` = :domain");
4064 $stmt->execute(array(
4065 ':domain' => $_data,
4066 ));
4067 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
4068 while($row = array_shift($rows)) {
4069 $aliasdomains[] = $row['alias_domain'];
4070 }
4071 }
4072 else {
4073 $stmt = $pdo->prepare("SELECT `alias_domain` FROM `alias_domain` WHERE `target_domain` IN (SELECT `domain` FROM `domain_admins` WHERE `active` = '1' AND `username` = :username) OR 'admin' = :role");
4074 $stmt->execute(array(
4075 ':username' => $_SESSION['mailcow_cc_username'],
4076 ':role' => $_SESSION['mailcow_cc_role'],
4077 ));
4078 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
4079 while($row = array_shift($rows)) {
4080 $aliasdomains[] = $row['alias_domain'];
4081 }
4082 }
4083 return $aliasdomains;
4084 break;
4085 case 'aliases':
4086 $aliases = array();
4087 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
4088 return false;
4089 }
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01004090 $stmt = $pdo->prepare("SELECT `id`, `address` FROM `alias` WHERE `address` != `goto` AND `domain` = :domain");
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01004091 $stmt->execute(array(
4092 ':domain' => $_data,
4093 ));
4094 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
4095 while($row = array_shift($rows)) {
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01004096 if ($_extra == "address"){
4097 $aliases[] = $row['address'];
4098 } else {
4099 $aliases[] = $row['id'];
4100 }
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01004101 }
4102 return $aliases;
4103 break;
4104 case 'alias_details':
4105 $aliasdata = array();
4106 $stmt = $pdo->prepare("SELECT
4107 `id`,
4108 `domain`,
4109 `goto`,
4110 `address`,
4111 `public_comment`,
4112 `private_comment`,
4113 `active`,
4114 `sogo_visible`,
4115 `created`,
4116 `modified`
4117 FROM `alias`
4118 WHERE (`id` = :id OR `address` = :address) AND `address` != `goto`");
4119 $stmt->execute(array(
4120 ':id' => $_data,
4121 ':address' => $_data,
4122 ));
4123 $row = $stmt->fetch(PDO::FETCH_ASSOC);
4124 $stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :domain");
4125 $stmt->execute(array(
4126 ':domain' => $row['domain'],
4127 ));
4128 $row_alias_domain = $stmt->fetch(PDO::FETCH_ASSOC);
4129 if (isset($row_alias_domain['target_domain']) && !empty($row_alias_domain['target_domain'])) {
4130 $aliasdata['in_primary_domain'] = $row_alias_domain['target_domain'];
4131 }
4132 else {
4133 $aliasdata['in_primary_domain'] = "";
4134 }
4135 $aliasdata['id'] = $row['id'];
4136 $aliasdata['domain'] = $row['domain'];
4137 $aliasdata['public_comment'] = $row['public_comment'];
4138 $aliasdata['private_comment'] = $row['private_comment'];
4139 $aliasdata['domain'] = $row['domain'];
4140 $aliasdata['goto'] = $row['goto'];
4141 $aliasdata['address'] = $row['address'];
4142 (!filter_var($aliasdata['address'], FILTER_VALIDATE_EMAIL)) ? $aliasdata['is_catch_all'] = 1 : $aliasdata['is_catch_all'] = 0;
4143 $aliasdata['active'] = $row['active'];
4144 $aliasdata['active_int'] = $row['active'];
4145 $aliasdata['sogo_visible'] = $row['sogo_visible'];
4146 $aliasdata['sogo_visible_int'] = $row['sogo_visible'];
4147 $aliasdata['created'] = $row['created'];
4148 $aliasdata['modified'] = $row['modified'];
4149 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $aliasdata['domain'])) {
4150 return false;
4151 }
4152 return $aliasdata;
4153 break;
4154 case 'alias_domain_details':
4155 $aliasdomaindata = array();
4156 $rl = ratelimit('get', 'domain', $_data);
4157 $stmt = $pdo->prepare("SELECT
4158 `alias_domain`,
4159 `target_domain`,
4160 `active`,
4161 `created`,
4162 `modified`
4163 FROM `alias_domain`
4164 WHERE `alias_domain` = :aliasdomain");
4165 $stmt->execute(array(
4166 ':aliasdomain' => $_data,
4167 ));
4168 $row = $stmt->fetch(PDO::FETCH_ASSOC);
4169 $stmt = $pdo->prepare("SELECT `backupmx` FROM `domain` WHERE `domain` = :target_domain");
4170 $stmt->execute(array(
4171 ':target_domain' => $row['target_domain']
4172 ));
4173 $row_parent = $stmt->fetch(PDO::FETCH_ASSOC);
4174 $aliasdomaindata['alias_domain'] = $row['alias_domain'];
4175 $aliasdomaindata['parent_is_backupmx'] = $row_parent['backupmx'];
4176 $aliasdomaindata['target_domain'] = $row['target_domain'];
4177 $aliasdomaindata['active'] = $row['active'];
4178 $aliasdomaindata['active_int'] = $row['active'];
4179 $aliasdomaindata['rl'] = $rl;
4180 $aliasdomaindata['created'] = $row['created'];
4181 $aliasdomaindata['modified'] = $row['modified'];
4182 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $aliasdomaindata['target_domain'])) {
4183 return false;
4184 }
4185 return $aliasdomaindata;
4186 break;
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01004187 case 'shared_aliases':
4188 $shared_aliases = array();
4189 $stmt = $pdo->query("SELECT `address` FROM `alias`
4190 WHERE `goto` REGEXP ','
4191 AND `address` NOT LIKE '@%'
4192 AND `goto` != `address`");
4193 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
4194 while($row = array_shift($rows)) {
4195 $domain = explode("@", $row['address'])[1];
4196 if (hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
4197 $shared_aliases[] = $row['address'];
4198 }
4199 }
4200
4201 return $shared_aliases;
4202 break;
4203 case 'direct_aliases':
4204 $direct_aliases = array();
4205 $stmt = $pdo->query("SELECT `address` FROM `alias`
4206 WHERE `goto` NOT LIKE '%,%'
4207 AND `address` NOT LIKE '@%'
4208 AND `goto` != `address`");
4209 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
4210
4211 while($row = array_shift($rows)) {
4212 $domain = explode("@", $row['address'])[1];
4213 if (hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
4214 $direct_aliases[] = $row['address'];
4215 }
4216 }
4217
4218 return $direct_aliases;
4219 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01004220 case 'domains':
4221 $domains = array();
4222 if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") {
4223 return false;
4224 }
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01004225
4226 if (isset($_extra) && is_array($_extra)){
4227 // get by tags
4228 $tags = is_array($_extra) ? $_extra : array();
4229 // add % as prefix and suffix to every element for relative searching
4230 $tags = array_map(function($x){ return '%'.$x.'%'; }, $tags);
4231 $sql = "";
4232 foreach ($tags as $key => $tag) {
4233 $sql = $sql."SELECT DISTINCT `domain` FROM `tags_domain` WHERE `tag_name` LIKE ?"; // distinct, avoid duplicates
4234 if ($key === array_key_last($tags)) break;
4235 $sql = $sql.' UNION DISTINCT '; // combine querys with union - distinct, avoid duplicates
4236 }
4237 $stmt = $pdo->prepare($sql);
4238 $stmt->execute($tags);
4239
4240 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
4241 while($row = array_shift($rows)) {
4242 if ($_SESSION['mailcow_cc_role'] == "admin")
4243 $domains[] = $row['domain'];
4244 elseif (hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $row['domain']))
4245 $domains[] = $row['domain'];
4246 }
4247 } else {
4248 // get all
4249 $stmt = $pdo->prepare("SELECT `domain` FROM `domain`
4250 WHERE (`domain` IN (
4251 SELECT `domain` from `domain_admins`
4252 WHERE (`active`='1' AND `username` = :username))
4253 )
4254 OR 'admin'= :role");
4255 $stmt->execute(array(
4256 ':username' => $_SESSION['mailcow_cc_username'],
4257 ':role' => $_SESSION['mailcow_cc_role'],
4258 ));
4259 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
4260 while($row = array_shift($rows)) {
4261 $domains[] = $row['domain'];
4262 }
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01004263 }
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01004264
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01004265 return $domains;
4266 break;
4267 case 'domain_details':
4268 $domaindata = array();
4269 $_data = idn_to_ascii(strtolower(trim($_data)), 0, INTL_IDNA_VARIANT_UTS46);
4270 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
4271 return false;
4272 }
4273 $stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :domain");
4274 $stmt->execute(array(
4275 ':domain' => $_data
4276 ));
4277 $row = $stmt->fetch(PDO::FETCH_ASSOC);
4278 if (!empty($row)) {
4279 $_data = $row['target_domain'];
4280 }
4281 $stmt = $pdo->prepare("SELECT
4282 `domain`,
4283 `description`,
4284 `aliases`,
4285 `mailboxes`,
4286 `defquota`,
4287 `maxquota`,
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01004288 `created`,
4289 `modified`,
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01004290 `quota`,
4291 `relayhost`,
4292 `relay_all_recipients`,
4293 `relay_unknown_only`,
4294 `backupmx`,
4295 `gal`,
4296 `active`
4297 FROM `domain` WHERE `domain`= :domain");
4298 $stmt->execute(array(
4299 ':domain' => $_data
4300 ));
4301 $row = $stmt->fetch(PDO::FETCH_ASSOC);
4302 if (empty($row)) {
4303 return false;
4304 }
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02004305 $stmt = $pdo->prepare("SELECT COUNT(`username`) AS `count`,
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01004306 COALESCE(SUM(`quota`), 0) AS `in_use`
4307 FROM `mailbox`
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02004308 WHERE (`kind` = '' OR `kind` = NULL)
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01004309 AND `domain` = :domain");
4310 $stmt->execute(array(':domain' => $row['domain']));
4311 $MailboxDataDomain = $stmt->fetch(PDO::FETCH_ASSOC);
4312 $stmt = $pdo->prepare("SELECT SUM(bytes) AS `bytes_total`, SUM(messages) AS `msgs_total` FROM `quota2`
4313 WHERE `username` IN (
4314 SELECT `username` FROM `mailbox`
4315 WHERE `domain` = :domain
4316 );");
4317 $stmt->execute(array(':domain' => $row['domain']));
4318 $SumQuotaInUse = $stmt->fetch(PDO::FETCH_ASSOC);
4319 $rl = ratelimit('get', 'domain', $_data);
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02004320 $domaindata['max_new_mailbox_quota'] = ($row['quota'] * 1048576) - $MailboxDataDomain['in_use'];
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01004321 if ($domaindata['max_new_mailbox_quota'] > ($row['maxquota'] * 1048576)) {
4322 $domaindata['max_new_mailbox_quota'] = ($row['maxquota'] * 1048576);
4323 }
4324 $domaindata['def_new_mailbox_quota'] = $domaindata['max_new_mailbox_quota'];
4325 if ($domaindata['def_new_mailbox_quota'] > ($row['defquota'] * 1048576)) {
4326 $domaindata['def_new_mailbox_quota'] = ($row['defquota'] * 1048576);
4327 }
4328 $domaindata['quota_used_in_domain'] = $MailboxDataDomain['in_use'];
4329 if (!empty($SumQuotaInUse['bytes_total'])) {
4330 $domaindata['bytes_total'] = $SumQuotaInUse['bytes_total'];
4331 }
4332 else {
4333 $domaindata['bytes_total'] = 0;
4334 }
4335 if (!empty($SumQuotaInUse['msgs_total'])) {
4336 $domaindata['msgs_total'] = $SumQuotaInUse['msgs_total'];
4337 }
4338 else {
4339 $domaindata['msgs_total'] = 0;
4340 }
4341 $domaindata['mboxes_in_domain'] = $MailboxDataDomain['count'];
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02004342 $domaindata['mboxes_left'] = $row['mailboxes'] - $MailboxDataDomain['count'];
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01004343 $domaindata['domain_name'] = $row['domain'];
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01004344 $domaindata['domain_h_name'] = idn_to_utf8($row['domain']);
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01004345 $domaindata['description'] = $row['description'];
4346 $domaindata['max_num_aliases_for_domain'] = $row['aliases'];
4347 $domaindata['max_num_mboxes_for_domain'] = $row['mailboxes'];
4348 $domaindata['def_quota_for_mbox'] = $row['defquota'] * 1048576;
4349 $domaindata['max_quota_for_mbox'] = $row['maxquota'] * 1048576;
4350 $domaindata['max_quota_for_domain'] = $row['quota'] * 1048576;
4351 $domaindata['relayhost'] = $row['relayhost'];
4352 $domaindata['backupmx'] = $row['backupmx'];
4353 $domaindata['backupmx_int'] = $row['backupmx'];
4354 $domaindata['gal'] = $row['gal'];
4355 $domaindata['gal_int'] = $row['gal'];
4356 $domaindata['rl'] = $rl;
4357 $domaindata['active'] = $row['active'];
4358 $domaindata['active_int'] = $row['active'];
4359 $domaindata['relay_all_recipients'] = $row['relay_all_recipients'];
4360 $domaindata['relay_all_recipients_int'] = $row['relay_all_recipients'];
4361 $domaindata['relay_unknown_only'] = $row['relay_unknown_only'];
4362 $domaindata['relay_unknown_only_int'] = $row['relay_unknown_only'];
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01004363 $domaindata['created'] = $row['created'];
4364 $domaindata['modified'] = $row['modified'];
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02004365 $stmt = $pdo->prepare("SELECT COUNT(`address`) AS `alias_count` FROM `alias`
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01004366 WHERE (`domain`= :domain OR `domain` IN (SELECT `alias_domain` FROM `alias_domain` WHERE `target_domain` = :domain2))
4367 AND `address` NOT IN (
4368 SELECT `username` FROM `mailbox`
4369 )");
4370 $stmt->execute(array(
4371 ':domain' => $_data,
4372 ':domain2' => $_data
4373 ));
4374 $AliasDataDomain = $stmt->fetch(PDO::FETCH_ASSOC);
4375 (isset($AliasDataDomain['alias_count'])) ? $domaindata['aliases_in_domain'] = $AliasDataDomain['alias_count'] : $domaindata['aliases_in_domain'] = "0";
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02004376 $domaindata['aliases_left'] = $row['aliases'] - $AliasDataDomain['alias_count'];
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01004377 if ($_SESSION['mailcow_cc_role'] == "admin")
4378 {
4379 $stmt = $pdo->prepare("SELECT GROUP_CONCAT(`username` SEPARATOR ', ') AS domain_admins FROM `domain_admins` WHERE `domain` = :domain");
4380 $stmt->execute(array(
4381 ':domain' => $_data
4382 ));
4383 $domain_admins = $stmt->fetch(PDO::FETCH_ASSOC);
4384 (isset($domain_admins['domain_admins'])) ? $domaindata['domain_admins'] = $domain_admins['domain_admins'] : $domaindata['domain_admins'] = "-";
4385 }
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01004386 $stmt = $pdo->prepare("SELECT `tag_name`
4387 FROM `tags_domain` WHERE `domain`= :domain");
4388 $stmt->execute(array(
4389 ':domain' => $_data
4390 ));
4391 $tags = $stmt->fetchAll(PDO::FETCH_ASSOC);
4392 while ($tag = array_shift($tags)) {
4393 $domaindata['tags'][] = $tag['tag_name'];
4394 }
4395
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01004396 return $domaindata;
4397 break;
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01004398 case 'domain_templates':
4399 if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") {
4400 return false;
4401 }
4402 $_data = (isset($_data)) ? intval($_data) : null;
4403
4404 if (isset($_data)){
4405 $stmt = $pdo->prepare("SELECT * FROM `templates`
4406 WHERE `id` = :id AND type = :type");
4407 $stmt->execute(array(
4408 ":id" => $_data,
4409 ":type" => "domain"
4410 ));
4411 $row = $stmt->fetch(PDO::FETCH_ASSOC);
4412
4413 if (empty($row)){
4414 return false;
4415 }
4416
4417 $row["attributes"] = json_decode($row["attributes"], true);
4418 return $row;
4419 }
4420 else {
4421 $stmt = $pdo->prepare("SELECT * FROM `templates` WHERE `type` = 'domain'");
4422 $stmt->execute();
4423 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
4424
4425 if (empty($rows)){
4426 return false;
4427 }
4428
4429 foreach($rows as $key => $row){
4430 $rows[$key]["attributes"] = json_decode($row["attributes"], true);
4431 }
4432 return $rows;
4433 }
4434 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01004435 case 'mailbox_details':
4436 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
4437 return false;
4438 }
4439 $mailboxdata = array();
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01004440 if (preg_match('/y|yes/i', getenv('MASTER'))) {
4441 $stmt = $pdo->prepare("SELECT
4442 `domain`.`backupmx`,
4443 `mailbox`.`username`,
4444 `mailbox`.`name`,
4445 `mailbox`.`active`,
4446 `mailbox`.`domain`,
4447 `mailbox`.`local_part`,
4448 `mailbox`.`quota`,
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01004449 `mailbox`.`created`,
4450 `mailbox`.`modified`,
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01004451 `quota2`.`bytes`,
4452 `attributes`,
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01004453 `custom_attributes`,
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01004454 `quota2`.`messages`
4455 FROM `mailbox`, `quota2`, `domain`
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02004456 WHERE (`mailbox`.`kind` = '' OR `mailbox`.`kind` = NULL)
4457 AND `mailbox`.`username` = `quota2`.`username`
4458 AND `domain`.`domain` = `mailbox`.`domain`
4459 AND `mailbox`.`username` = :mailbox");
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01004460 }
4461 else {
4462 $stmt = $pdo->prepare("SELECT
4463 `domain`.`backupmx`,
4464 `mailbox`.`username`,
4465 `mailbox`.`name`,
4466 `mailbox`.`active`,
4467 `mailbox`.`domain`,
4468 `mailbox`.`local_part`,
4469 `mailbox`.`quota`,
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01004470 `mailbox`.`created`,
4471 `mailbox`.`modified`,
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01004472 `quota2replica`.`bytes`,
4473 `attributes`,
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01004474 `custom_attributes`,
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01004475 `quota2replica`.`messages`
4476 FROM `mailbox`, `quota2replica`, `domain`
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02004477 WHERE (`mailbox`.`kind` = '' OR `mailbox`.`kind` = NULL)
4478 AND `mailbox`.`username` = `quota2replica`.`username`
4479 AND `domain`.`domain` = `mailbox`.`domain`
4480 AND `mailbox`.`username` = :mailbox");
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01004481 }
4482 $stmt->execute(array(
4483 ':mailbox' => $_data,
4484 ));
4485 $row = $stmt->fetch(PDO::FETCH_ASSOC);
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02004486
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01004487 $mailboxdata['username'] = $row['username'];
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01004488 $mailboxdata['active'] = $row['active'];
4489 $mailboxdata['active_int'] = $row['active'];
4490 $mailboxdata['domain'] = $row['domain'];
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02004491 $mailboxdata['name'] = $row['name'];
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01004492 $mailboxdata['local_part'] = $row['local_part'];
4493 $mailboxdata['quota'] = $row['quota'];
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02004494 $mailboxdata['messages'] = $row['messages'];
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01004495 $mailboxdata['attributes'] = json_decode($row['attributes'], true);
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01004496 $mailboxdata['custom_attributes'] = json_decode($row['custom_attributes'], true);
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01004497 $mailboxdata['quota_used'] = intval($row['bytes']);
4498 $mailboxdata['percent_in_use'] = ($row['quota'] == 0) ? '- ' : round((intval($row['bytes']) / intval($row['quota'])) * 100);
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01004499 $mailboxdata['created'] = $row['created'];
4500 $mailboxdata['modified'] = $row['modified'];
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02004501
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01004502 if ($mailboxdata['percent_in_use'] === '- ') {
4503 $mailboxdata['percent_class'] = "info";
4504 }
4505 elseif ($mailboxdata['percent_in_use'] >= 90) {
4506 $mailboxdata['percent_class'] = "danger";
4507 }
4508 elseif ($mailboxdata['percent_in_use'] >= 75) {
4509 $mailboxdata['percent_class'] = "warning";
4510 }
4511 else {
4512 $mailboxdata['percent_class'] = "success";
4513 }
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02004514
4515 // Determine last logins
4516 $stmt = $pdo->prepare("SELECT MAX(`datetime`) AS `datetime`, `service` FROM `sasl_log`
4517 WHERE `username` = :mailbox
4518 GROUP BY `service` DESC");
4519 $stmt->execute(array(':mailbox' => $_data));
4520 $SaslLogsData = $stmt->fetchAll(PDO::FETCH_ASSOC);
4521 foreach ($SaslLogsData as $SaslLogs) {
4522 if ($SaslLogs['service'] == 'imap') {
4523 $last_imap_login = strtotime($SaslLogs['datetime']);
4524 }
4525 else if ($SaslLogs['service'] == 'smtp') {
4526 $last_smtp_login = strtotime($SaslLogs['datetime']);
4527 }
4528 else if ($SaslLogs['service'] == 'pop3') {
4529 $last_pop3_login = strtotime($SaslLogs['datetime']);
4530 }
4531 }
4532 if (!isset($last_imap_login) || $GLOBALS['SHOW_LAST_LOGIN'] === false) {
4533 $last_imap_login = 0;
4534 }
4535 if (!isset($last_smtp_login) || $GLOBALS['SHOW_LAST_LOGIN'] === false) {
4536 $last_smtp_login = 0;
4537 }
4538 if (!isset($last_pop3_login) || $GLOBALS['SHOW_LAST_LOGIN'] === false) {
4539 $last_pop3_login = 0;
4540 }
4541 $mailboxdata['last_imap_login'] = $last_imap_login;
4542 $mailboxdata['last_smtp_login'] = $last_smtp_login;
4543 $mailboxdata['last_pop3_login'] = $last_pop3_login;
4544
4545 if (!isset($_extra) || $_extra != 'reduced') {
4546 $rl = ratelimit('get', 'mailbox', $_data);
4547 $stmt = $pdo->prepare("SELECT `maxquota`, `quota` FROM `domain` WHERE `domain` = :domain");
4548 $stmt->execute(array(':domain' => $row['domain']));
4549 $DomainQuota = $stmt->fetch(PDO::FETCH_ASSOC);
4550
4551 $stmt = $pdo->prepare("SELECT IFNULL(COUNT(`active`), 0) AS `pushover_active` FROM `pushover` WHERE `username` = :username AND `active` = 1");
4552 $stmt->execute(array(':username' => $_data));
4553 $PushoverActive = $stmt->fetch(PDO::FETCH_ASSOC);
4554 $stmt = $pdo->prepare("SELECT COALESCE(SUM(`quota`), 0) as `in_use` FROM `mailbox` WHERE (`kind` = '' OR `kind` = NULL) AND `domain` = :domain AND `username` != :username");
4555 $stmt->execute(array(':domain' => $row['domain'], ':username' => $_data));
4556 $MailboxUsage = $stmt->fetch(PDO::FETCH_ASSOC);
4557 $stmt = $pdo->prepare("SELECT IFNULL(COUNT(`address`), 0) AS `sa_count` FROM `spamalias` WHERE `goto` = :address AND `validity` >= :unixnow");
4558 $stmt->execute(array(':address' => $_data, ':unixnow' => time()));
4559 $SpamaliasUsage = $stmt->fetch(PDO::FETCH_ASSOC);
4560 $mailboxdata['max_new_quota'] = ($DomainQuota['quota'] * 1048576) - $MailboxUsage['in_use'];
4561 $mailboxdata['spam_aliases'] = $SpamaliasUsage['sa_count'];
4562 $mailboxdata['pushover_active'] = ($PushoverActive['pushover_active'] == 1) ? 1 : 0;
4563 if ($mailboxdata['max_new_quota'] > ($DomainQuota['maxquota'] * 1048576)) {
4564 $mailboxdata['max_new_quota'] = ($DomainQuota['maxquota'] * 1048576);
4565 }
4566 if (!empty($rl)) {
4567 $mailboxdata['rl'] = $rl;
4568 $mailboxdata['rl_scope'] = 'mailbox';
4569 }
4570 else {
4571 $mailboxdata['rl'] = ratelimit('get', 'domain', $row['domain']);
4572 $mailboxdata['rl_scope'] = 'domain';
4573 }
4574 $mailboxdata['is_relayed'] = $row['backupmx'];
4575 }
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01004576 $stmt = $pdo->prepare("SELECT `tag_name`
4577 FROM `tags_mailbox` WHERE `username`= :username");
4578 $stmt->execute(array(
4579 ':username' => $_data
4580 ));
4581 $tags = $stmt->fetchAll(PDO::FETCH_ASSOC);
4582 while ($tag = array_shift($tags)) {
4583 $mailboxdata['tags'][] = $tag['tag_name'];
4584 }
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02004585
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01004586 return $mailboxdata;
4587 break;
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01004588 case 'mailbox_templates':
4589 if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") {
4590 return false;
4591 }
4592 $_data = (isset($_data)) ? intval($_data) : null;
4593
4594 if (isset($_data)){
4595 $stmt = $pdo->prepare("SELECT * FROM `templates`
4596 WHERE `id` = :id AND type = :type");
4597 $stmt->execute(array(
4598 ":id" => $_data,
4599 ":type" => "mailbox"
4600 ));
4601 $row = $stmt->fetch(PDO::FETCH_ASSOC);
4602
4603 if (empty($row)){
4604 return false;
4605 }
4606
4607 $row["attributes"] = json_decode($row["attributes"], true);
4608 return $row;
4609 }
4610 else {
4611 $stmt = $pdo->prepare("SELECT * FROM `templates` WHERE `type` = 'mailbox'");
4612 $stmt->execute();
4613 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
4614
4615 if (empty($rows)){
4616 return false;
4617 }
4618
4619 foreach($rows as $key => $row){
4620 $rows[$key]["attributes"] = json_decode($row["attributes"], true);
4621 }
4622 return $rows;
4623 }
4624 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01004625 case 'resource_details':
4626 $resourcedata = array();
4627 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
4628 return false;
4629 }
4630 $stmt = $pdo->prepare("SELECT
4631 `username`,
4632 `name`,
4633 `kind`,
4634 `multiple_bookings`,
4635 `local_part`,
4636 `active`,
4637 `domain`
4638 FROM `mailbox` WHERE `kind` REGEXP 'location|thing|group' AND `username` = :resource");
4639 $stmt->execute(array(
4640 ':resource' => $_data,
4641 ));
4642 $row = $stmt->fetch(PDO::FETCH_ASSOC);
4643 $resourcedata['name'] = $row['username'];
4644 $resourcedata['kind'] = $row['kind'];
4645 $resourcedata['multiple_bookings'] = $row['multiple_bookings'];
4646 $resourcedata['description'] = $row['name'];
4647 $resourcedata['active'] = $row['active'];
4648 $resourcedata['active_int'] = $row['active'];
4649 $resourcedata['domain'] = $row['domain'];
4650 $resourcedata['local_part'] = $row['local_part'];
4651 if (!isset($resourcedata['domain']) ||
4652 (isset($resourcedata['domain']) && !hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $resourcedata['domain']))) {
4653 return false;
4654 }
4655 return $resourcedata;
4656 break;
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01004657 case 'domain_wide_footer':
4658 $domain = idn_to_ascii(strtolower(trim($_data)), 0, INTL_IDNA_VARIANT_UTS46);
4659 if (!is_valid_domain_name($domain)) {
4660 $_SESSION['return'][] = array(
4661 'type' => 'danger',
4662 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4663 'msg' => 'domain_invalid'
4664 );
4665 return false;
4666 }
4667 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
4668 $_SESSION['return'][] = array(
4669 'type' => 'danger',
4670 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4671 'msg' => 'access_denied'
4672 );
4673 return false;
4674 }
4675
4676 try {
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01004677 $stmt = $pdo->prepare("SELECT `html`, `plain`, `mbox_exclude`, `alias_domain_exclude`, `skip_replies` FROM `domain_wide_footer`
4678 WHERE `domain` = :domain");
4679 $stmt->execute(array(
4680 ':domain' => $domain
4681 ));
4682 $footer = $stmt->fetch(PDO::FETCH_ASSOC);
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01004683 }
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01004684 catch (PDOException $e) {
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01004685 $_SESSION['return'][] = array(
4686 'type' => 'danger',
4687 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01004688 'msg' => $e->getMessage()
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01004689 );
4690 return false;
4691 }
4692
Matthias Andreas Benkard9dabdab2024-03-06 13:12:09 +01004693 return $footer;
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01004694 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01004695 }
4696 break;
4697 case 'delete':
4698 switch ($_type) {
4699 case 'syncjob':
4700 if (!is_array($_data['id'])) {
4701 $ids = array();
4702 $ids[] = $_data['id'];
4703 }
4704 else {
4705 $ids = $_data['id'];
4706 }
4707 if (!isset($_SESSION['acl']['syncjobs']) || $_SESSION['acl']['syncjobs'] != "1" ) {
4708 $_SESSION['return'][] = array(
4709 'type' => 'danger',
4710 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4711 'msg' => 'access_denied'
4712 );
4713 return false;
4714 }
4715 foreach ($ids as $id) {
4716 if (!is_numeric($id)) {
4717 return false;
4718 }
4719 $stmt = $pdo->prepare("SELECT `user2` FROM `imapsync` WHERE id = :id");
4720 $stmt->execute(array(':id' => $id));
4721 $user2 = $stmt->fetch(PDO::FETCH_ASSOC)['user2'];
4722 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $user2)) {
4723 $_SESSION['return'][] = array(
4724 'type' => 'danger',
4725 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4726 'msg' => 'access_denied'
4727 );
4728 continue;
4729 }
4730 $stmt = $pdo->prepare("DELETE FROM `imapsync` WHERE `id`= :id");
4731 $stmt->execute(array(':id' => $id));
4732 $_SESSION['return'][] = array(
4733 'type' => 'success',
4734 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4735 'msg' => array('deleted_syncjob', $id)
4736 );
4737 }
4738 break;
4739 case 'filter':
4740 if (!is_array($_data['id'])) {
4741 $ids = array();
4742 $ids[] = $_data['id'];
4743 }
4744 else {
4745 $ids = $_data['id'];
4746 }
4747 if (!isset($_SESSION['acl']['filters']) || $_SESSION['acl']['filters'] != "1" ) {
4748 $_SESSION['return'][] = array(
4749 'type' => 'danger',
4750 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4751 'msg' => 'access_denied'
4752 );
4753 return false;
4754 }
4755 foreach ($ids as $id) {
4756 if (!is_numeric($id)) {
4757 continue;
4758 }
4759 $stmt = $pdo->prepare("SELECT `username` FROM `sieve_filters` WHERE id = :id");
4760 $stmt->execute(array(':id' => $id));
4761 $usr = $stmt->fetch(PDO::FETCH_ASSOC)['username'];
4762 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $usr)) {
4763 $_SESSION['return'][] = array(
4764 'type' => 'danger',
4765 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4766 'msg' => 'access_denied'
4767 );
4768 continue;
4769 }
4770 $stmt = $pdo->prepare("DELETE FROM `sieve_filters` WHERE `id`= :id");
4771 $stmt->execute(array(':id' => $id));
4772 $_SESSION['return'][] = array(
4773 'type' => 'success',
4774 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4775 'msg' => array('delete_filter', $id)
4776 );
4777 }
4778 break;
4779 case 'time_limited_alias':
4780 if (!is_array($_data['address'])) {
4781 $addresses = array();
4782 $addresses[] = $_data['address'];
4783 }
4784 else {
4785 $addresses = $_data['address'];
4786 }
4787 if (!isset($_SESSION['acl']['spam_alias']) || $_SESSION['acl']['spam_alias'] != "1" ) {
4788 $_SESSION['return'][] = array(
4789 'type' => 'danger',
4790 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4791 'msg' => 'access_denied'
4792 );
4793 return false;
4794 }
4795 foreach ($addresses as $address) {
4796 $stmt = $pdo->prepare("SELECT `goto` FROM `spamalias` WHERE `address` = :address");
4797 $stmt->execute(array(':address' => $address));
4798 $goto = $stmt->fetch(PDO::FETCH_ASSOC)['goto'];
4799 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $goto)) {
4800 $_SESSION['return'][] = array(
4801 'type' => 'danger',
4802 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4803 'msg' => 'access_denied'
4804 );
4805 continue;
4806 }
4807 $stmt = $pdo->prepare("DELETE FROM `spamalias` WHERE `goto` = :username AND `address` = :item");
4808 $stmt->execute(array(
4809 ':username' => $goto,
4810 ':item' => $address
4811 ));
4812 $_SESSION['return'][] = array(
4813 'type' => 'success',
4814 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4815 'msg' => array('mailbox_modified', htmlspecialchars($goto))
4816 );
4817 }
4818 break;
4819 case 'eas_cache':
4820 if (!is_array($_data['username'])) {
4821 $usernames = array();
4822 $usernames[] = $_data['username'];
4823 }
4824 else {
4825 $usernames = $_data['username'];
4826 }
4827 if (!isset($_SESSION['acl']['eas_reset']) || $_SESSION['acl']['eas_reset'] != "1" ) {
4828 $_SESSION['return'][] = array(
4829 'type' => 'danger',
4830 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4831 'msg' => 'access_denied'
4832 );
4833 return false;
4834 }
4835 foreach ($usernames as $username) {
4836 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
4837 $_SESSION['return'][] = array(
4838 'type' => 'danger',
4839 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4840 'msg' => 'access_denied'
4841 );
4842 continue;
4843 }
4844 $stmt = $pdo->prepare("DELETE FROM `sogo_cache_folder` WHERE `c_uid` = :username");
4845 $stmt->execute(array(
4846 ':username' => $username
4847 ));
4848 $_SESSION['return'][] = array(
4849 'type' => 'success',
4850 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4851 'msg' => array('eas_reset', htmlspecialchars($username))
4852 );
4853 }
4854 break;
4855 case 'sogo_profile':
4856 if (!is_array($_data['username'])) {
4857 $usernames = array();
4858 $usernames[] = $_data['username'];
4859 }
4860 else {
4861 $usernames = $_data['username'];
4862 }
4863 if (!isset($_SESSION['acl']['sogo_profile_reset']) || $_SESSION['acl']['sogo_profile_reset'] != "1" ) {
4864 $_SESSION['return'][] = array(
4865 'type' => 'danger',
4866 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4867 'msg' => 'access_denied'
4868 );
4869 return false;
4870 }
4871 foreach ($usernames as $username) {
4872 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
4873 $_SESSION['return'][] = array(
4874 'type' => 'danger',
4875 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4876 'msg' => 'access_denied'
4877 );
4878 continue;
4879 }
4880 $stmt = $pdo->prepare("DELETE FROM `sogo_user_profile` WHERE `c_uid` = :username");
4881 $stmt->execute(array(
4882 ':username' => $username
4883 ));
4884 $stmt = $pdo->prepare("DELETE FROM `sogo_cache_folder` WHERE `c_uid` = :username");
4885 $stmt->execute(array(
4886 ':username' => $username
4887 ));
4888 $stmt = $pdo->prepare("DELETE FROM `sogo_acl` WHERE `c_object` LIKE '%/" . $username . "/%' OR `c_uid` = :username");
4889 $stmt->execute(array(
4890 ':username' => $username
4891 ));
4892 $stmt = $pdo->prepare("DELETE FROM `sogo_store` WHERE `c_folder_id` IN (SELECT `c_folder_id` FROM `sogo_folder_info` WHERE `c_path2` = :username)");
4893 $stmt->execute(array(
4894 ':username' => $username
4895 ));
4896 $stmt = $pdo->prepare("DELETE FROM `sogo_quick_contact` WHERE `c_folder_id` IN (SELECT `c_folder_id` FROM `sogo_folder_info` WHERE `c_path2` = :username)");
4897 $stmt->execute(array(
4898 ':username' => $username
4899 ));
4900 $stmt = $pdo->prepare("DELETE FROM `sogo_quick_appointment` WHERE `c_folder_id` IN (SELECT `c_folder_id` FROM `sogo_folder_info` WHERE `c_path2` = :username)");
4901 $stmt->execute(array(
4902 ':username' => $username
4903 ));
4904 $stmt = $pdo->prepare("DELETE FROM `sogo_folder_info` WHERE `c_path2` = :username");
4905 $stmt->execute(array(
4906 ':username' => $username
4907 ));
4908 $_SESSION['return'][] = array(
4909 'type' => 'success',
4910 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4911 'msg' => array('sogo_profile_reset', htmlspecialchars($username))
4912 );
4913 }
4914 break;
4915 case 'domain':
4916 if (!is_array($_data['domain'])) {
4917 $domains = array();
4918 $domains[] = $_data['domain'];
4919 }
4920 else {
4921 $domains = $_data['domain'];
4922 }
4923 if ($_SESSION['mailcow_cc_role'] != "admin") {
4924 $_SESSION['return'][] = array(
4925 'type' => 'danger',
4926 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4927 'msg' => 'access_denied'
4928 );
4929 return false;
4930 }
4931 foreach ($domains as $domain) {
4932 if (!is_valid_domain_name($domain)) {
4933 $_SESSION['return'][] = array(
4934 'type' => 'danger',
4935 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4936 'msg' => 'domain_invalid'
4937 );
4938 continue;
4939 }
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02004940 $domain = idn_to_ascii(strtolower(trim($domain)), 0, INTL_IDNA_VARIANT_UTS46);
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01004941 $stmt = $pdo->prepare("SELECT `username` FROM `mailbox`
4942 WHERE `domain` = :domain");
4943 $stmt->execute(array(':domain' => $domain));
4944 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
4945 if ($num_results != 0 || !empty($num_results)) {
4946 $_SESSION['return'][] = array(
4947 'type' => 'danger',
4948 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4949 'msg' => array('domain_not_empty', $domain)
4950 );
4951 continue;
4952 }
4953 $exec_fields = array('cmd' => 'maildir', 'task' => 'cleanup', 'maildir' => $domain);
4954 $maildir_gc = json_decode(docker('post', 'dovecot-mailcow', 'exec', $exec_fields), true);
4955 if ($maildir_gc['type'] != 'success') {
4956 $_SESSION['return'][] = array(
4957 'type' => 'warning',
4958 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4959 'msg' => 'Could not move mail storage to garbage collector: ' . $maildir_gc['msg']
4960 );
4961 }
4962 $stmt = $pdo->prepare("DELETE FROM `domain` WHERE `domain` = :domain");
4963 $stmt->execute(array(
4964 ':domain' => $domain,
4965 ));
4966 $stmt = $pdo->prepare("DELETE FROM `domain_admins` WHERE `domain` = :domain");
4967 $stmt->execute(array(
4968 ':domain' => $domain,
4969 ));
4970 $stmt = $pdo->prepare("DELETE FROM `alias` WHERE `domain` = :domain");
4971 $stmt->execute(array(
4972 ':domain' => $domain,
4973 ));
4974 $stmt = $pdo->prepare("DELETE FROM `alias_domain` WHERE `target_domain` = :domain");
4975 $stmt->execute(array(
4976 ':domain' => $domain,
4977 ));
4978 $stmt = $pdo->prepare("DELETE FROM `mailbox` WHERE `domain` = :domain");
4979 $stmt->execute(array(
4980 ':domain' => $domain,
4981 ));
4982 $stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `logged_in_as` LIKE :domain");
4983 $stmt->execute(array(
4984 ':domain' => '%@'.$domain,
4985 ));
4986 $stmt = $pdo->prepare("DELETE FROM `quota2` WHERE `username` LIKE :domain");
4987 $stmt->execute(array(
4988 ':domain' => '%@'.$domain,
4989 ));
4990 $stmt = $pdo->prepare("DELETE FROM `pushover` WHERE `username` LIKE :domain");
4991 $stmt->execute(array(
4992 ':domain' => '%@'.$domain,
4993 ));
4994 $stmt = $pdo->prepare("DELETE FROM `quota2replica` WHERE `username` LIKE :domain");
4995 $stmt->execute(array(
4996 ':domain' => '%@'.$domain,
4997 ));
4998 $stmt = $pdo->prepare("DELETE FROM `spamalias` WHERE `address` LIKE :domain");
4999 $stmt->execute(array(
5000 ':domain' => '%@'.$domain,
5001 ));
5002 $stmt = $pdo->prepare("DELETE FROM `filterconf` WHERE `object` = :domain");
5003 $stmt->execute(array(
5004 ':domain' => $domain,
5005 ));
5006 $stmt = $pdo->prepare("DELETE FROM `bcc_maps` WHERE `local_dest` = :domain");
5007 $stmt->execute(array(
5008 ':domain' => $domain,
5009 ));
5010 $stmt = $pdo->query("DELETE FROM `admin` WHERE `superadmin` = 0 AND `username` NOT IN (SELECT `username`FROM `domain_admins`);");
5011 $stmt = $pdo->query("DELETE FROM `da_acl` WHERE `username` NOT IN (SELECT `username`FROM `domain_admins`);");
5012 try {
5013 $redis->hDel('DOMAIN_MAP', $domain);
5014 $redis->hDel('RL_VALUE', $domain);
5015 }
5016 catch (RedisException $e) {
5017 $_SESSION['return'][] = array(
5018 'type' => 'danger',
5019 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5020 'msg' => array('redis_error', $e)
5021 );
5022 continue;
5023 }
5024 $_SESSION['return'][] = array(
5025 'type' => 'success',
5026 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5027 'msg' => array('domain_removed', htmlspecialchars($domain))
5028 );
5029 }
5030 break;
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01005031 case 'domain_templates':
5032 if ($_SESSION['mailcow_cc_role'] != "admin") {
5033 $_SESSION['return'][] = array(
5034 'type' => 'danger',
5035 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5036 'msg' => 'access_denied'
5037 );
5038 return false;
5039 }
5040 if (!is_array($_data['ids'])) {
5041 $ids = array();
5042 $ids[] = $_data['ids'];
5043 }
5044 else {
5045 $ids = $_data['ids'];
5046 }
5047
5048
5049 foreach ($ids as $id) {
5050 // delete template
5051 $stmt = $pdo->prepare("DELETE FROM `templates`
5052 WHERE id = :id AND type = :type AND NOT template = :template");
5053 $stmt->execute(array(
5054 ":id" => $id,
5055 ":type" => "domain",
5056 ":template" => "Default"
5057 ));
5058
5059 $_SESSION['return'][] = array(
5060 'type' => 'success',
5061 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5062 'msg' => array('template_removed', htmlspecialchars($id))
5063 );
5064 return true;
5065 }
5066 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01005067 case 'alias':
5068 if (!is_array($_data['id'])) {
5069 $ids = array();
5070 $ids[] = $_data['id'];
5071 }
5072 else {
5073 $ids = $_data['id'];
5074 }
5075 foreach ($ids as $id) {
5076 $alias_data = mailbox('get', 'alias_details', $id);
5077 if (empty($alias_data)) {
5078 $_SESSION['return'][] = array(
5079 'type' => 'danger',
5080 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5081 'msg' => 'access_denied'
5082 );
5083 continue;
5084 }
5085 $stmt = $pdo->prepare("DELETE FROM `alias` WHERE `id` = :id");
5086 $stmt->execute(array(
5087 ':id' => $alias_data['id']
5088 ));
5089 $stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `send_as` = :alias_address");
5090 $stmt->execute(array(
5091 ':alias_address' => $alias_data['address']
5092 ));
5093 $_SESSION['return'][] = array(
5094 'type' => 'success',
5095 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5096 'msg' => array('alias_removed', htmlspecialchars($alias_data['address']))
5097 );
5098 }
5099 break;
5100 case 'alias_domain':
5101 if (!is_array($_data['alias_domain'])) {
5102 $alias_domains = array();
5103 $alias_domains[] = $_data['alias_domain'];
5104 }
5105 else {
5106 $alias_domains = $_data['alias_domain'];
5107 }
5108 foreach ($alias_domains as $alias_domain) {
5109 if (!is_valid_domain_name($alias_domain)) {
5110 $_SESSION['return'][] = array(
5111 'type' => 'danger',
5112 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5113 'msg' => 'domain_invalid'
5114 );
5115 continue;
5116 }
5117 $stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain`
5118 WHERE `alias_domain`= :alias_domain");
5119 $stmt->execute(array(':alias_domain' => $alias_domain));
5120 $DomainData = $stmt->fetch(PDO::FETCH_ASSOC);
5121 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $DomainData['target_domain'])) {
5122 $_SESSION['return'][] = array(
5123 'type' => 'danger',
5124 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5125 'msg' => 'access_denied'
5126 );
5127 continue;
5128 }
5129 $stmt = $pdo->prepare("DELETE FROM `alias_domain` WHERE `alias_domain` = :alias_domain");
5130 $stmt->execute(array(
5131 ':alias_domain' => $alias_domain,
5132 ));
5133 $stmt = $pdo->prepare("DELETE FROM `alias` WHERE `domain` = :alias_domain");
5134 $stmt->execute(array(
5135 ':alias_domain' => $alias_domain,
5136 ));
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01005137 $stmt = $pdo->prepare("DELETE FROM `spamalias` WHERE `address` LIKE :domain");
5138 $stmt->execute(array(
5139 ':domain' => '%@'.$alias_domain,
5140 ));
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01005141 $stmt = $pdo->prepare("DELETE FROM `bcc_maps` WHERE `local_dest` = :alias_domain");
5142 $stmt->execute(array(
5143 ':alias_domain' => $alias_domain,
5144 ));
5145 try {
5146 $redis->hDel('DOMAIN_MAP', $alias_domain);
5147 $redis->hDel('RL_VALUE', $domain);
5148 }
5149 catch (RedisException $e) {
5150 $_SESSION['return'][] = array(
5151 'type' => 'danger',
5152 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5153 'msg' => array('redis_error', $e)
5154 );
5155 continue;
5156 }
5157 $_SESSION['return'][] = array(
5158 'type' => 'success',
5159 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5160 'msg' => array('alias_domain_removed', htmlspecialchars($alias_domain))
5161 );
5162 }
5163 break;
5164 case 'mailbox':
5165 if (!is_array($_data['username'])) {
5166 $usernames = array();
5167 $usernames[] = $_data['username'];
5168 }
5169 else {
5170 $usernames = $_data['username'];
5171 }
5172 foreach ($usernames as $username) {
5173 if (!filter_var($username, FILTER_VALIDATE_EMAIL)) {
5174 $_SESSION['return'][] = array(
5175 'type' => 'danger',
5176 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5177 'msg' => 'access_denied'
5178 );
5179 continue;
5180 }
5181 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
5182 $_SESSION['return'][] = array(
5183 'type' => 'danger',
5184 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5185 'msg' => 'access_denied'
5186 );
5187 continue;
5188 }
5189 $mailbox_details = mailbox('get', 'mailbox_details', $username);
5190 if (!empty($mailbox_details['domain']) && !empty($mailbox_details['local_part'])) {
5191 $maildir = $mailbox_details['domain'] . '/' . $mailbox_details['local_part'];
5192 $exec_fields = array('cmd' => 'maildir', 'task' => 'cleanup', 'maildir' => $maildir);
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01005193
5194 if (getenv("CLUSTERMODE") == "replication") {
5195 // broadcast to each dovecot container
5196 docker('broadcast', 'dovecot-mailcow', 'exec', $exec_fields);
5197 } else {
5198 $maildir_gc = json_decode(docker('post', 'dovecot-mailcow', 'exec', $exec_fields), true);
5199 if ($maildir_gc['type'] != 'success') {
5200 $_SESSION['return'][] = array(
5201 'type' => 'warning',
5202 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5203 'msg' => 'Could not move maildir to garbage collector: ' . $maildir_gc['msg']
5204 );
5205 }
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01005206 }
5207 }
5208 else {
5209 $_SESSION['return'][] = array(
5210 'type' => 'warning',
5211 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5212 'msg' => 'Could not move maildir to garbage collector: variables local_part and/or domain empty'
5213 );
5214 }
5215 if (strtolower(getenv('SKIP_SOLR')) == 'n') {
5216 $curl = curl_init();
5217 curl_setopt($curl, CURLOPT_URL, 'http://solr:8983/solr/dovecot-fts/update?commit=true');
5218 curl_setopt($curl, CURLOPT_HTTPHEADER,array('Content-Type: text/xml'));
5219 curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
5220 curl_setopt($curl, CURLOPT_POST, 1);
5221 curl_setopt($curl, CURLOPT_POSTFIELDS, '<delete><query>user:' . $username . '</query></delete>');
5222 curl_setopt($curl, CURLOPT_TIMEOUT, 30);
5223 $response = curl_exec($curl);
5224 if ($response === false) {
5225 $err = curl_error($curl);
5226 $_SESSION['return'][] = array(
5227 'type' => 'warning',
5228 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5229 'msg' => 'Could not remove Solr index: ' . print_r($err, true)
5230 );
5231 }
5232 curl_close($curl);
5233 }
5234 $stmt = $pdo->prepare("DELETE FROM `alias` WHERE `goto` = :username");
5235 $stmt->execute(array(
5236 ':username' => $username
5237 ));
5238 $stmt = $pdo->prepare("DELETE FROM `pushover` WHERE `username` = :username");
5239 $stmt->execute(array(
5240 ':username' => $username
5241 ));
5242 $stmt = $pdo->prepare("DELETE FROM `quarantine` WHERE `rcpt` = :username");
5243 $stmt->execute(array(
5244 ':username' => $username
5245 ));
5246 $stmt = $pdo->prepare("DELETE FROM `quota2` WHERE `username` = :username");
5247 $stmt->execute(array(
5248 ':username' => $username
5249 ));
5250 $stmt = $pdo->prepare("DELETE FROM `quota2replica` WHERE `username` = :username");
5251 $stmt->execute(array(
5252 ':username' => $username
5253 ));
5254 $stmt = $pdo->prepare("DELETE FROM `mailbox` WHERE `username` = :username");
5255 $stmt->execute(array(
5256 ':username' => $username
5257 ));
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01005258 $stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `logged_in_as` = :logged_in_as OR `send_as` = :send_as");
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01005259 $stmt->execute(array(
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01005260 ':logged_in_as' => $username,
5261 ':send_as' => $username
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01005262 ));
5263 // fk, better safe than sorry
5264 $stmt = $pdo->prepare("DELETE FROM `user_acl` WHERE `username` = :username");
5265 $stmt->execute(array(
5266 ':username' => $username
5267 ));
5268 $stmt = $pdo->prepare("DELETE FROM `spamalias` WHERE `goto` = :username");
5269 $stmt->execute(array(
5270 ':username' => $username
5271 ));
5272 $stmt = $pdo->prepare("DELETE FROM `imapsync` WHERE `user2` = :username");
5273 $stmt->execute(array(
5274 ':username' => $username
5275 ));
5276 $stmt = $pdo->prepare("DELETE FROM `filterconf` WHERE `object` = :username");
5277 $stmt->execute(array(
5278 ':username' => $username
5279 ));
5280 $stmt = $pdo->prepare("DELETE FROM `sogo_user_profile` WHERE `c_uid` = :username");
5281 $stmt->execute(array(
5282 ':username' => $username
5283 ));
5284 $stmt = $pdo->prepare("DELETE FROM `sogo_cache_folder` WHERE `c_uid` = :username");
5285 $stmt->execute(array(
5286 ':username' => $username
5287 ));
5288 $stmt = $pdo->prepare("DELETE FROM `sogo_acl` WHERE `c_object` LIKE '%/" . str_replace('%', '\%', $username) . "/%' OR `c_uid` = :username");
5289 $stmt->execute(array(
5290 ':username' => $username
5291 ));
5292 $stmt = $pdo->prepare("DELETE FROM `sogo_store` WHERE `c_folder_id` IN (SELECT `c_folder_id` FROM `sogo_folder_info` WHERE `c_path2` = :username)");
5293 $stmt->execute(array(
5294 ':username' => $username
5295 ));
5296 $stmt = $pdo->prepare("DELETE FROM `sogo_quick_contact` WHERE `c_folder_id` IN (SELECT `c_folder_id` FROM `sogo_folder_info` WHERE `c_path2` = :username)");
5297 $stmt->execute(array(
5298 ':username' => $username
5299 ));
5300 $stmt = $pdo->prepare("DELETE FROM `sogo_quick_appointment` WHERE `c_folder_id` IN (SELECT `c_folder_id` FROM `sogo_folder_info` WHERE `c_path2` = :username)");
5301 $stmt->execute(array(
5302 ':username' => $username
5303 ));
5304 $stmt = $pdo->prepare("DELETE FROM `sogo_folder_info` WHERE `c_path2` = :username");
5305 $stmt->execute(array(
5306 ':username' => $username
5307 ));
5308 $stmt = $pdo->prepare("DELETE FROM `bcc_maps` WHERE `local_dest` = :username");
5309 $stmt->execute(array(
5310 ':username' => $username
5311 ));
5312 $stmt = $pdo->prepare("DELETE FROM `oauth_access_tokens` WHERE `user_id` = :username");
5313 $stmt->execute(array(
5314 ':username' => $username
5315 ));
5316 $stmt = $pdo->prepare("DELETE FROM `oauth_refresh_tokens` WHERE `user_id` = :username");
5317 $stmt->execute(array(
5318 ':username' => $username
5319 ));
5320 $stmt = $pdo->prepare("DELETE FROM `oauth_authorization_codes` WHERE `user_id` = :username");
5321 $stmt->execute(array(
5322 ':username' => $username
5323 ));
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02005324 $stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `username` = :username");
5325 $stmt->execute(array(
5326 ':username' => $username,
5327 ));
5328 $stmt = $pdo->prepare("DELETE FROM `fido2` WHERE `username` = :username");
5329 $stmt->execute(array(
5330 ':username' => $username,
5331 ));
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01005332 $stmt = $pdo->prepare("SELECT `address`, `goto` FROM `alias`
5333 WHERE `goto` REGEXP :username");
5334 $stmt->execute(array(':username' => '(^|,)'.$username.'($|,)'));
5335 $GotoData = $stmt->fetchAll(PDO::FETCH_ASSOC);
5336 foreach ($GotoData as $gotos) {
5337 $goto_exploded = explode(',', $gotos['goto']);
5338 if (($key = array_search($username, $goto_exploded)) !== false) {
5339 unset($goto_exploded[$key]);
5340 }
Matthias Andreas Benkard8f915942021-08-16 10:57:25 +02005341 $gotos_rebuild = implode(',', (array)$goto_exploded);
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01005342 $stmt = $pdo->prepare("UPDATE `alias` SET
5343 `goto` = :goto
5344 WHERE `address` = :address");
5345 $stmt->execute(array(
5346 ':goto' => $gotos_rebuild,
5347 ':address' => $gotos['address']
5348 ));
5349 }
5350 try {
5351 $redis->hDel('RL_VALUE', $username);
5352 }
5353 catch (RedisException $e) {
5354 $_SESSION['return'][] = array(
5355 'type' => 'danger',
5356 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5357 'msg' => array('redis_error', $e)
5358 );
5359 continue;
5360 }
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01005361
5362 update_sogo_static_view($username);
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01005363 $_SESSION['return'][] = array(
5364 'type' => 'success',
5365 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5366 'msg' => array('mailbox_removed', htmlspecialchars($username))
5367 );
5368 }
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01005369 return true;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01005370 break;
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01005371 case 'mailbox_templates':
5372 if ($_SESSION['mailcow_cc_role'] != "admin") {
5373 $_SESSION['return'][] = array(
5374 'type' => 'danger',
5375 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5376 'msg' => 'access_denied'
5377 );
5378 return false;
5379 }
5380 if (!is_array($_data['ids'])) {
5381 $ids = array();
5382 $ids[] = $_data['ids'];
5383 }
5384 else {
5385 $ids = $_data['ids'];
5386 }
5387
5388
5389 foreach ($ids as $id) {
5390 // delete template
5391 $stmt = $pdo->prepare("DELETE FROM `templates`
5392 WHERE id = :id AND type = :type AND NOT template = :template");
5393 $stmt->execute(array(
5394 ":id" => $id,
5395 ":type" => "mailbox",
5396 ":template" => "Default"
5397 ));
5398 }
5399
5400 $_SESSION['return'][] = array(
5401 'type' => 'success',
5402 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5403 'msg' => 'template_removed'
5404 );
5405 return true;
5406 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01005407 case 'resource':
5408 if (!is_array($_data['name'])) {
5409 $names = array();
5410 $names[] = $_data['name'];
5411 }
5412 else {
5413 $names = $_data['name'];
5414 }
5415 foreach ($names as $name) {
5416 if (!filter_var($name, FILTER_VALIDATE_EMAIL)) {
5417 $_SESSION['return'][] = array(
5418 'type' => 'danger',
5419 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5420 'msg' => 'access_denied'
5421 );
5422 continue;
5423 }
5424 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $name)) {
5425 $_SESSION['return'][] = array(
5426 'type' => 'danger',
5427 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5428 'msg' => 'access_denied'
5429 );
5430 continue;
5431 }
5432 $stmt = $pdo->prepare("DELETE FROM `mailbox` WHERE `username` = :username");
5433 $stmt->execute(array(
5434 ':username' => $name
5435 ));
5436 $stmt = $pdo->prepare("DELETE FROM `sogo_user_profile` WHERE `c_uid` = :username");
5437 $stmt->execute(array(
5438 ':username' => $name
5439 ));
5440 $stmt = $pdo->prepare("DELETE FROM `sogo_cache_folder` WHERE `c_uid` = :username");
5441 $stmt->execute(array(
5442 ':username' => $name
5443 ));
5444 $stmt = $pdo->prepare("DELETE FROM `sogo_acl` WHERE `c_object` LIKE '%/" . $name . "/%' OR `c_uid` = :username");
5445 $stmt->execute(array(
5446 ':username' => $name
5447 ));
5448 $stmt = $pdo->prepare("DELETE FROM `sogo_store` WHERE `c_folder_id` IN (SELECT `c_folder_id` FROM `sogo_folder_info` WHERE `c_path2` = :username)");
5449 $stmt->execute(array(
5450 ':username' => $name
5451 ));
5452 $stmt = $pdo->prepare("DELETE FROM `sogo_quick_contact` WHERE `c_folder_id` IN (SELECT `c_folder_id` FROM `sogo_folder_info` WHERE `c_path2` = :username)");
5453 $stmt->execute(array(
5454 ':username' => $name
5455 ));
5456 $stmt = $pdo->prepare("DELETE FROM `sogo_quick_appointment` WHERE `c_folder_id` IN (SELECT `c_folder_id` FROM `sogo_folder_info` WHERE `c_path2` = :username)");
5457 $stmt->execute(array(
5458 ':username' => $name
5459 ));
5460 $stmt = $pdo->prepare("DELETE FROM `sogo_folder_info` WHERE `c_path2` = :username");
5461 $stmt->execute(array(
5462 ':username' => $name
5463 ));
5464 $_SESSION['return'][] = array(
5465 'type' => 'success',
5466 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5467 'msg' => array('resource_removed', htmlspecialchars($name))
5468 );
5469 }
5470 break;
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01005471 case 'tags_domain':
5472 if (!is_array($_data['domain'])) {
5473 $domains = array();
5474 $domains[] = $_data['domain'];
5475 }
5476 else {
5477 $domains = $_data['domain'];
5478 }
5479 $tags = $_data['tags'];
5480 if (!is_array($tags)) $tags = array();
5481
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01005482
5483 $wasModified = false;
5484 foreach ($domains as $domain) {
5485 if (!is_valid_domain_name($domain)) {
5486 $_SESSION['return'][] = array(
5487 'type' => 'danger',
5488 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5489 'msg' => 'domain_invalid'
5490 );
5491 continue;
5492 }
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01005493 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
5494 $_SESSION['return'][] = array(
5495 'type' => 'danger',
5496 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5497 'msg' => 'access_denied'
5498 );
5499 return false;
5500 }
5501
Matthias Andreas Benkard3c18a082022-12-27 17:32:58 +01005502 foreach($tags as $tag){
5503 // delete tag
5504 $wasModified = true;
5505 $stmt = $pdo->prepare("DELETE FROM `tags_domain` WHERE `domain` = :domain AND `tag_name` = :tag_name");
5506 $stmt->execute(array(
5507 ':domain' => $domain,
5508 ':tag_name' => $tag,
5509 ));
5510 }
5511 }
5512
5513 if (!$wasModified) return false;
5514 $_SESSION['return'][] = array(
5515 'type' => 'success',
5516 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5517 'msg' => array('domain_modified', $domain)
5518 );
5519 break;
5520 case 'tags_mailbox':
5521 if (!is_array($_data['username'])) {
5522 $usernames = array();
5523 $usernames[] = $_data['username'];
5524 }
5525 else {
5526 $usernames = $_data['username'];
5527 }
5528 $tags = $_data['tags'];
5529 if (!is_array($tags)) $tags = array();
5530
5531 $wasModified = false;
5532 foreach ($usernames as $username) {
5533 if (!filter_var($username, FILTER_VALIDATE_EMAIL)) {
5534 $_SESSION['return'][] = array(
5535 'type' => 'danger',
5536 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5537 'msg' => 'email invalid'
5538 );
5539 continue;
5540 }
5541
5542 $is_now = mailbox('get', 'mailbox_details', $username);
5543 $domain = $is_now['domain'];
5544 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
5545 $_SESSION['return'][] = array(
5546 'type' => 'danger',
5547 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5548 'msg' => 'access_denied'
5549 );
5550 continue;
5551 }
5552
5553 // delete tags
5554 foreach($tags as $tag){
5555 $wasModified = true;
5556
5557 $stmt = $pdo->prepare("DELETE FROM `tags_mailbox` WHERE `username` = :username AND `tag_name` = :tag_name");
5558 $stmt->execute(array(
5559 ':username' => $username,
5560 ':tag_name' => $tag,
5561 ));
5562 }
5563 }
5564
5565 if (!$wasModified) return false;
5566 $_SESSION['return'][] = array(
5567 'type' => 'success',
5568 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5569 'msg' => array('mailbox_modified', $username)
5570 );
5571 break;
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01005572 }
5573 break;
5574 }
Matthias Andreas Benkardd63fe562023-11-18 13:18:30 +01005575 if ($_action != 'get' && in_array($_type, array('domain', 'alias', 'alias_domain', 'resource')) && getenv('SKIP_SOGO') != "y") {
Matthias Andreas Benkard4edeb9f2021-01-02 15:32:21 +01005576 update_sogo_static_view();
5577 }
5578}