PostfixAdmin - web based virtual user administration interface for Postfix mail servers https://postfixadmin.github.io/postfixadmin/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

490 lines
17 KiB

reverting most changes from SVN r572 aka https://sourceforge.net/tracker/index.php?func=detail&aid=2567466&group_id=191583&atid=937966 because - it undermines the $CONF[*alias_control*] settings more or less - mailbox aliases with non-default targets are always shown in the "Aliases" section - see comment from 2009-05-04 on https://sourceforge.net/tracker/?func=detail&aid=1902476&group_id=191583&atid=937964 - it introduced some "funny" bugs - a nice example is http://sourceforge.net/tracker/?func=detail&aid=2786284&group_id=191583&atid=937964 Files / sections affected by the revert: - list-virtual.php: all numbers (alias count etc.) correct? (the changes in this file are the largest ones) - functions.inc.php: SQL queries in get_domain_properties() - delete.php: the only change since r572 affected code that was inserted in r572 (and is now deleted again) - nothing should break here - create-alias.php: had no changes since r572 - therefore nothing should break here Exceptions (not reverted): - edit-alias: this change looks useful (hide mailbox alias target from admins if they don't have permissions to change it). The actual code has changed in the meantime, but the functionality stays. Additionally, reverting this would be very hard or throw useful later changes away. BUT: shouldn't the page completely forbid to edit a mailbox alias if the admin doesn't have permissions for it? - functions.inc.php: comment for pacrypt() ;-) - linebreaks in long SQL queries Please check if everything is still working as expected (especially the domain list and the virtual list) - I did only some quick tests. git-svn-id: https://svn.code.sf.net/p/postfixadmin/code/trunk@652 a1433add-5e2c-0410-b055-b7f2511e0802
17 years ago
  1. <?php
  2. /**
  3. * Postfix Admin
  4. *
  5. * LICENSE
  6. * This source file is subject to the GPL license that is bundled with
  7. * this package in the file LICENSE.TXT.
  8. *
  9. * Further details on the project are available at :
  10. * http://www.postfixadmin.com or http://postfixadmin.sf.net
  11. *
  12. * @version $Id$
  13. * @license GNU GPL v2 or later.
  14. *
  15. * File: list-virtual.php
  16. * List virtual users for a domain.
  17. *
  18. * Template File: list-virtual.php
  19. *
  20. * Template Variables:
  21. *
  22. * tMessage
  23. * tAlias
  24. * tMailbox
  25. *
  26. * Form POST \ GET Variables:
  27. *
  28. * fDomain
  29. * fDisplay
  30. */
  31. require_once('common.php');
  32. authentication_require_role('admin');
  33. $fDomain = false;
  34. $SESSID_USERNAME = authentication_get_username();
  35. if (authentication_has_role('global-admin')) {
  36. $list_domains = list_domains ();
  37. $is_superadmin = 1;
  38. } else {
  39. $list_domains = list_domains_for_admin(authentication_get_username());
  40. $is_superadmin = 0;
  41. }
  42. $tAlias = array();
  43. $tMailbox = array();
  44. $fDisplay = 0;
  45. $page_size = $CONF['page_size'];
  46. if ($_SERVER['REQUEST_METHOD'] == "GET")
  47. {
  48. if (isset ($_GET['domain'])) $fDomain = escape_string ($_GET['domain']);
  49. if (isset ($_GET['limit'])) $fDisplay = intval ($_GET['limit']);
  50. $search = escape_string(safeget('search'));
  51. }
  52. else
  53. {
  54. if (isset ($_POST['fDomain'])) $fDomain = escape_string ($_POST['fDomain']);
  55. if (isset ($_POST['limit'])) $fDisplay = intval ($_POST['limit']);
  56. $search = escape_string(safepost('search'));
  57. }
  58. if (count($list_domains) == 0) {
  59. # die("no domains");
  60. flash_error( $PALANG['invalid_parameter'] );
  61. header("Location: list-domain.php"); # no domains (for this admin at least) - redirect to domain list
  62. exit;
  63. }
  64. if ((is_array ($list_domains) and sizeof ($list_domains) > 0)) {
  65. if (empty ($fDomain)) {
  66. $fDomain = $list_domains[0];
  67. }
  68. }
  69. if(!in_array($fDomain, $list_domains)) {
  70. flash_error( $PALANG['invalid_parameter'] );
  71. header("Location: list-domain.php"); # invalid domain, or not owned by this admin
  72. exit;
  73. }
  74. if (!check_owner(authentication_get_username(), $fDomain)) {
  75. flash_error( $PALANG['invalid_parameter'] . " If you see this message, please open a bugreport"); # this check is most probably obsoleted by the in_array() check above
  76. header("Location: list-domain.php"); # domain not owned by this admin
  77. exit(0);
  78. }
  79. // store fDomain in $_SESSION so after adding/editing aliases/mailboxes we can
  80. // take the user back to the appropriate domain listing. (see templates/menu.tpl)
  81. if($fDomain) {
  82. $_SESSION['list_virtual_sticky_domain'] = $fDomain;
  83. }
  84. #
  85. # alias domain
  86. #
  87. # TODO: add search support for alias domains
  88. if (boolconf('alias_domain')) {
  89. # Alias-Domains
  90. # first try to get a list of other domains pointing
  91. # to this currently chosen one (aka. alias domains)
  92. $query = "SELECT $table_alias_domain.alias_domain,$table_alias_domain.target_domain,$table_alias_domain.modified,$table_alias_domain.active FROM $table_alias_domain WHERE target_domain='$fDomain' ORDER BY $table_alias_domain.alias_domain LIMIT $fDisplay, $page_size";
  93. if ('pgsql'==$CONF['database_type'])
  94. {
  95. $query = "SELECT alias_domain,target_domain,extract(epoch from modified) as modified,active FROM $table_alias_domain WHERE target_domain='$fDomain' ORDER BY alias_domain LIMIT $page_size OFFSET $fDisplay";
  96. }
  97. $result = db_query ($query);
  98. $tAliasDomains = array();
  99. if ($result['rows'] > 0)
  100. {
  101. while ($row = db_array ($result['result']))
  102. {
  103. if ('pgsql'==$CONF['database_type'])
  104. {
  105. $row['modified']=gmstrftime('%c %Z',$row['modified']);
  106. $row['active']=('t'==$row['active']) ? 1 : 0;
  107. }
  108. $tAliasDomains[] = $row;
  109. }
  110. }
  111. # now let's see if the current domain itself is an alias for another domain
  112. $query = "SELECT $table_alias_domain.alias_domain,$table_alias_domain.target_domain,$table_alias_domain.modified,$table_alias_domain.active FROM $table_alias_domain WHERE alias_domain='$fDomain'";
  113. if ('pgsql'==$CONF['database_type'])
  114. {
  115. $query = "SELECT alias_domain,target_domain,extract(epoch from modified) as modified,active FROM $table_alias_domain WHERE alias_domain='$fDomain'";
  116. }
  117. $result = db_query ($query);
  118. $tTargetDomain = "";
  119. if ($result['rows'] > 0)
  120. {
  121. if($row = db_array ($result['result']))
  122. {
  123. if ('pgsql'==$CONF['database_type'])
  124. {
  125. $row['modified']=gmstrftime('%c %Z',$row['modified']);
  126. $row['active']=('t'==$row['active']) ? 1 : 0;
  127. }
  128. $tTargetDomain = $row;
  129. }
  130. }
  131. }
  132. #
  133. # aliases
  134. #
  135. if ($search == "") {
  136. $sql_domain = " $table_alias.domain='$fDomain' ";
  137. $sql_where = "";
  138. } else {
  139. $sql_domain = db_in_clause("$table_alias.domain", $list_domains);
  140. $sql_where = " AND ( address LIKE '%$search%' OR goto LIKE '%$search%' ) ";
  141. }
  142. $query = "SELECT address,
  143. goto,
  144. modified,
  145. active
  146. FROM $table_alias
  147. WHERE $sql_domain AND NOT EXISTS(SELECT 1 FROM $table_mailbox WHERE username=$table_alias.address) $sql_where
  148. ORDER BY address LIMIT $page_size OFFSET $fDisplay";
  149. $result = db_query ($query);
  150. if ($result['rows'] > 0)
  151. {
  152. while ($row = db_array ($result['result']))
  153. {
  154. if ('pgsql'==$CONF['database_type'])
  155. {
  156. //. at least in my database, $row['modified'] already looks like : 2009-04-11 21:38:10.75586+01,
  157. // while gmstrftime expects an integer value. strtotime seems happy though.
  158. //$row['modified']=gmstrftime('%c %Z',$row['modified']);
  159. $row['modified'] = date('Y-m-d H:i', strtotime($row['modified']));
  160. $row['active']=('t'==$row['active']) ? 1 : 0;
  161. }
  162. $tAlias[] = $row;
  163. }
  164. }
  165. #
  166. # mailboxes
  167. #
  168. $display_mailbox_aliases = boolconf('alias_control_admin');
  169. # build the sql query
  170. $sql_select = "SELECT $table_mailbox.* ";
  171. $sql_from = " FROM $table_mailbox ";
  172. $sql_join = "";
  173. $sql_where = " WHERE ";
  174. $sql_order = " ORDER BY $table_mailbox.username ";
  175. $sql_limit = " LIMIT $page_size OFFSET $fDisplay";
  176. if ($search == "") {
  177. $sql_where .= " $table_mailbox.domain='$fDomain' ";
  178. } else {
  179. $sql_where .= db_in_clause("$table_mailbox.domain", $list_domains) . " ";
  180. $sql_where .= " AND ( $table_mailbox.username LIKE '%$search%' OR $table_mailbox.name LIKE '%$search%' ";
  181. if ($display_mailbox_aliases) {
  182. $sql_where .= " OR $table_alias.goto LIKE '%$search%' ";
  183. }
  184. $sql_where .= " ) "; # $search is already escaped
  185. }
  186. if ($display_mailbox_aliases) {
  187. $sql_select .= ", $table_alias.goto ";
  188. $sql_join .= " LEFT JOIN $table_alias ON $table_mailbox.username=$table_alias.address ";
  189. }
  190. if (boolconf('vacation_control_admin')) {
  191. $sql_select .= ", $table_vacation.active AS v_active ";
  192. $sql_join .= " LEFT JOIN $table_vacation ON $table_mailbox.username=$table_vacation.email ";
  193. }
  194. if (boolconf('used_quotas') && boolconf('new_quota_table')) {
  195. $sql_select .= ", $table_quota2.bytes as current ";
  196. $sql_join .= " LEFT JOIN $table_quota2 ON $table_mailbox.username=$table_quota2.username ";
  197. }
  198. if (boolconf('used_quotas') && ( ! boolconf('new_quota_table') ) ) {
  199. $sql_select .= ", $table_quota.current ";
  200. $sql_join .= " LEFT JOIN $table_quota ON $table_mailbox.username=$table_quota.username ";
  201. $sql_where .= " AND ( $table_quota.path='quota/storage' OR $table_quota.path IS NULL ) ";
  202. }
  203. $query = "$sql_select\n$sql_from\n$sql_join\n$sql_where\n$sql_order\n$sql_limit";
  204. $result = db_query ($query);
  205. if ($result['rows'] > 0)
  206. {
  207. while ($row = db_array ($result['result']))
  208. {
  209. if ($display_mailbox_aliases) {
  210. $goto_split = explode(",", $row['goto']);
  211. $row['goto_mailbox'] = 0;
  212. $row['goto_other'] = array();
  213. foreach ($goto_split as $goto_single) {
  214. if ($goto_single == $row['username']) { # delivers to mailbox
  215. $row['goto_mailbox'] = 1;
  216. } elseif (boolconf('vacation') && strstr($goto_single, '@' . $CONF['vacation_domain']) ) { # vacation alias - TODO: check for full vacation alias
  217. # skip the vacation alias, vacation status is detected otherwise
  218. } else { # forwarding to other alias
  219. $row['goto_other'][] = $goto_single;
  220. }
  221. }
  222. }
  223. if ('pgsql'==$CONF['database_type'])
  224. {
  225. // XXX
  226. $row['modified'] = date('Y-m-d H:i', strtotime($row['modified']));
  227. $row['created'] = date('Y-m-d H:i', strtotime($row['created']));
  228. $row['active']=('t'==$row['active']) ? 1 : 0;
  229. if($row['v_active'] == NULL) {
  230. $row['v_active'] = 'f';
  231. }
  232. $row['v_active']=('t'==$row['v_active']) ? 1 : 0;
  233. }
  234. $tMailbox[] = $row;
  235. }
  236. }
  237. $tCanAddAlias = false;
  238. $tCanAddMailbox = false;
  239. # TODO: needs reworking for $search...
  240. # TODO: (= bug: no page browser displayed in search mode!) - https://sourceforge.net/tracker/?func=detail&aid=2782818&group_id=191583&atid=937964
  241. # for non-search mode, get_domain_properties counts the aliases and mailboxes
  242. # Options:
  243. # a)
  244. # if ($search == "") -> get_domain_properties
  245. # else -> "manual count"
  246. # b)
  247. # "manual count" for all cases (not really more work, queries are similar)
  248. #
  249. # Note: get_domain_properties also creates the page browser (which needs performance tuning anyway...)
  250. $limit = get_domain_properties($fDomain);
  251. if (isset ($limit)) {
  252. if ($fDisplay >= $page_size) {
  253. $tDisplay_back_show = 1;
  254. $tDisplay_back = $fDisplay - $page_size;
  255. }
  256. if (($limit['alias_count'] > $page_size) or ($limit['mailbox_count'] > $page_size)) {
  257. $tDisplay_up_show = 1;
  258. }
  259. if ((($fDisplay + $page_size) < $limit['alias_count']) or
  260. (($fDisplay + $page_size) < $limit['mailbox_count']))
  261. {
  262. $tDisplay_next_show = 1;
  263. $tDisplay_next = $fDisplay + $page_size;
  264. }
  265. if($limit['aliases'] == 0) {
  266. $tCanAddAlias = true;
  267. }
  268. elseif($limit['alias_count'] < $limit['aliases']) {
  269. $tCanAddAlias = true;
  270. }
  271. if($limit['mailboxes'] == 0) {
  272. $tCanAddMailbox = true;
  273. }
  274. elseif($limit['mailbox_count'] < $limit['mailboxes']) {
  275. $tCanAddMailbox = true;
  276. }
  277. $limit ['aliases'] = eval_size ($limit ['aliases']);
  278. $limit ['mailboxes'] = eval_size ($limit ['mailboxes']);
  279. $limit ['maxquota'] = eval_size ($limit ['maxquota']);
  280. }
  281. $gen_show_status = array ();
  282. $check_alias_owner = array ();
  283. if ((is_array ($tAlias) and sizeof ($tAlias) > 0))
  284. for ($i = 0; $i < sizeof ($tAlias); $i++)
  285. {
  286. $gen_show_status [$i] = gen_show_status($tAlias[$i]['address']);
  287. $check_alias_owner [$i] = check_alias_owner($SESSID_USERNAME, $tAlias[$i]['address']);
  288. }
  289. $gen_show_status_mailbox = array ();
  290. $divide_quota = array ('current' => array(), 'quota' => array());
  291. if ((is_array ($tMailbox) and sizeof ($tMailbox) > 0))
  292. for ($i = 0; $i < sizeof ($tMailbox); $i++)
  293. {
  294. $gen_show_status_mailbox [$i] = gen_show_status($tMailbox[$i]['username']);
  295. if(isset($tMailbox[$i]['current'])) {
  296. $divide_quota ['current'][$i] = divide_quota ($tMailbox[$i]['current']);
  297. }
  298. if(isset($tMailbox[$i]['quota'])) {
  299. $divide_quota ['quota'][$i] = divide_quota ($tMailbox[$i]['quota']);
  300. }
  301. }
  302. class cNav_bar
  303. {
  304. var $count, $title, $limit, $page_size, $pages, $search; //* arguments
  305. var $url; //* manually
  306. var $fInit, $arr_prev, $arr_next, $arr_top; //* internal
  307. var $anchor;
  308. function cNav_bar ($aCount, $aTitle, $aLimit, $aPage_size, $aPages, $aSearch)
  309. {
  310. $this->count = $aCount;
  311. $this->title = $aTitle;
  312. $this->limit = $aLimit;
  313. $this->page_size = $aPage_size;
  314. $this->pages = $aPages;
  315. if ($aSearch == "") {
  316. $this->search = "";
  317. } else {
  318. $this->search = "&search=" . htmlentities($aSearch);
  319. }
  320. $this->url = '';
  321. $this->fInit = false;
  322. }
  323. function init ()
  324. {
  325. $this->anchor = 'a'.substr ($this->title, 3);
  326. $this->url .= '#'.$this->anchor;
  327. ($this->limit >= $this->page_size) ? $this->arr_prev = '&nbsp;<a href="?limit='.($this->limit - $this->page_size).$this->search.$this->url.'"><img border="0" src="images/arrow-l.png" title="'.$GLOBALS ['PALANG']['pOverview_left_arrow'].'" alt="'.$GLOBALS ['PALANG']['pOverview_left_arrow'].'"/></a>&nbsp;' : $this->arr_prev = '';
  328. ($this->limit > 0) ? $this->arr_top = '&nbsp;<a href="?limit=0' .$this->search.$this->url.'"><img border="0" src="images/arrow-u.png" title="'.$GLOBALS ['PALANG']['pOverview_up_arrow'].'" alt="'.$GLOBALS ['PALANG']['pOverview_up_arrow'].'"/></a>&nbsp;' : $this->arr_top = '';
  329. (($this->limit + $this->page_size) < ($this->count * $this->page_size)) ? $this->arr_next = '&nbsp;<a href="?limit='.($this->limit + $this->page_size).$this->search.$this->url.'"><img border="0" src="images/arrow-r.png" title="'.$GLOBALS ['PALANG']['pOverview_right_arrow'].'" alt="'.$GLOBALS ['PALANG']['pOverview_right_arrow'].'"/></a>&nbsp;' : $this->arr_next = '';
  330. $this->fInit = true;
  331. }
  332. function display_pre ()
  333. {
  334. $ret_val = '<div class="nav_bar"';
  335. //$ret_val .= ' style="background-color:#ffa;"';
  336. $ret_val .= '>';
  337. $ret_val .= '<table width="730"><colgroup span="1"><col width="550"></col></colgroup> ';
  338. $ret_val .= '<tr><td align="left">';
  339. return $ret_val;
  340. }
  341. function display_post ()
  342. {
  343. $ret_val = '</td></tr></table></div>';
  344. return $ret_val;
  345. }
  346. function display_top ()
  347. {
  348. $ret_val = '';
  349. if ($this->count < 1)
  350. return $ret_val;
  351. if (!$this->fInit)
  352. $this->init ();
  353. $ret_val .= '<a name="'.$this->anchor.'"></a>';
  354. $ret_val .= $this->display_pre ();
  355. $ret_val .= '<b>'.$this->title.'</b>&nbsp;&nbsp;';
  356. ($this->limit >= $this->page_size) ? $highlight_at = $this->limit / $this->page_size : $highlight_at = 0;
  357. for ($i = 0; $i < count ($this->pages); $i++)
  358. {
  359. $lPage = $this->pages [$i];
  360. if ($i == $highlight_at)
  361. $lPage = '<b>'.$lPage.'</b>';
  362. $ret_val .= '<a href="?limit='.($i * $this->page_size).$this->search.$this->url.'">'.$lPage.'</a>'."\n";
  363. }
  364. $ret_val .= '</td><td valign="middle" align="right">';
  365. $ret_val .= $this->arr_prev;
  366. $ret_val .= $this->arr_top;
  367. $ret_val .= $this->arr_next;
  368. $ret_val .= $this->display_post ();
  369. return $ret_val;
  370. }
  371. function display_bottom ()
  372. {
  373. $ret_val = '';
  374. if ($this->count < 1)
  375. return $ret_val;
  376. if (!$this->fInit)
  377. $this->init ();
  378. $ret_val .= $this->display_pre ();
  379. $ret_val .= '</td><td valign="middle" align="right">';
  380. $ret_val .= $this->arr_prev;
  381. $ret_val .= $this->arr_top;
  382. $ret_val .= $this->arr_next;
  383. $ret_val .= $this->display_post ();
  384. return $ret_val;
  385. }
  386. }
  387. $nav_bar_alias = new cNav_bar ($limit['alias_pgindex_count'], $PALANG['pOverview_alias_title'], $fDisplay, $CONF['page_size'], $limit['alias_pgindex'], $search);
  388. $nav_bar_alias->url = '&amp;domain='.$fDomain;
  389. $nav_bar_mailbox = new cNav_bar ($limit['mbox_pgindex_count'], $PALANG['pOverview_mailbox_title'], $fDisplay, $CONF['page_size'], $limit['mbox_pgindex'], $search);
  390. $nav_bar_mailbox->url = '&amp;domain='.$fDomain;
  391. //print $nav_bar_alias->display_top ();
  392. // this is why we need a proper template layer.
  393. $fDomain = htmlentities($fDomain, ENT_QUOTES);
  394. if(empty($_GET['domain'])) {
  395. $_GET['domain'] = '';
  396. }
  397. $smarty->assign ('select_options', select_options ($list_domains, array ($fDomain)), false);
  398. $smarty->assign ('nav_bar_alias', array ('top' => $nav_bar_alias->display_top (), 'bottom' => $nav_bar_alias->display_bottom ()), false);
  399. $smarty->assign ('nav_bar_mailbox', array ('top' => $nav_bar_mailbox->display_top (), 'bottom' => $nav_bar_mailbox->display_bottom ()), false);
  400. $smarty->assign ('fDomain', $fDomain, false);
  401. $smarty->assign ('search', $search);
  402. $smarty->assign ('list_domains', $list_domains);
  403. $smarty->assign ('limit', $limit);
  404. $smarty->assign ('tDisplay_back_show', $tDisplay_back_show);
  405. $smarty->assign ('tDisplay_back', $tDisplay_back);
  406. $smarty->assign ('tDisplay_up_show', $tDisplay_up_show);
  407. $smarty->assign ('tDisplay_next_show', $tDisplay_next_show);
  408. $smarty->assign ('tDisplay_next', $tDisplay_next);
  409. if(sizeof ($tAliasDomains) > 0)
  410. $smarty->assign ('tAliasDomains', $tAliasDomains);
  411. if(is_array($tTargetDomain))
  412. {
  413. $smarty->assign ('tTargetDomain', $tTargetDomain);
  414. $smarty->assign ('PALANG_pOverview_alias_domain_target', sprintf($PALANG['pOverview_alias_domain_target'], $fDomain));
  415. }
  416. $smarty->assign ('tAlias', $tAlias);
  417. $smarty->assign ('gen_show_status', $gen_show_status, false);
  418. $smarty->assign ('check_alias_owner', $check_alias_owner);
  419. $smarty->assign ('tCanAddAlias', $tCanAddAlias);
  420. $smarty->assign ('tMailbox', $tMailbox);
  421. $smarty->assign ('gen_show_status_mailbox', $gen_show_status_mailbox, false);
  422. $smarty->assign ('boolconf_used_quotas', boolconf('used_quotas'));
  423. $smarty->assign ('divide_quota', $divide_quota);
  424. $smarty->assign ('tCanAddMailbox', $tCanAddMailbox);
  425. $smarty->assign ('display_mailbox_aliases', $display_mailbox_aliases);
  426. if (isset ($_GET ['tab']))
  427. $_SESSION ['tab'] = $_GET ['tab'];
  428. //if (empty ($_GET ['tab']))
  429. // unset ($_SESSION ['tab']);
  430. if (!isset ($_SESSION ['tab']))
  431. $_SESSION ['tab'] = 'mailbox';
  432. $smarty->assign ('tab', $_SESSION ['tab']);
  433. $smarty->assign ('smarty_template', 'list-virtual');
  434. $smarty->display ('index.tpl');
  435. /* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */
  436. ?>