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.

list-virtual.php 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  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 http://postfixadmin.sf.net
  10. *
  11. * @version $Id$
  12. * @license GNU GPL v2 or later.
  13. *
  14. * File: list-virtual.php
  15. * List virtual users for a domain.
  16. *
  17. * Template File: list-virtual.php
  18. *
  19. * Form POST \ GET Variables:
  20. *
  21. * fDomain
  22. * fDisplay
  23. * search
  24. */
  25. require_once('common.php');
  26. authentication_require_role('admin');
  27. $admin_username = authentication_get_username();
  28. $list_domains = list_domains_for_admin($admin_username);
  29. $page_size = $CONF['page_size'];
  30. $fDomain = safepost('fDomain', safeget('domain', safesession('list-virtual:domain')));
  31. if (safesession('list-virtual:domain') != $fDomain) {
  32. unset($_SESSION['list-virtual:limit']);
  33. }
  34. $fDisplay = (int) safepost('limit', safeget('limit', safesession('list-virtual:limit')));
  35. $search = safepost('search', safeget('search', array())); # not remembered in the session
  36. if (!is_array($search)) {
  37. die(Config::Lang('invalid_parameter'));
  38. }
  39. if (count($list_domains) == 0) {
  40. if (authentication_has_role('global-admin')) {
  41. flash_error($PALANG['no_domains_exist']);
  42. } else {
  43. flash_error($PALANG['no_domains_for_this_admin']);
  44. }
  45. header("Location: list.php?table=domain"); # no domains (for this admin at least) - redirect to domain list
  46. exit;
  47. }
  48. if ((is_array($list_domains) and sizeof($list_domains) > 0)) {
  49. if (empty($fDomain)) {
  50. $fDomain = escape_string($list_domains[0]);
  51. }
  52. }
  53. if (!in_array($fDomain, $list_domains)) {
  54. flash_error($PALANG['invalid_parameter']);
  55. unset($_SESSION['list-virtual:domain']);
  56. header("Location: list.php?table=domain"); # invalid domain, or not owned by this admin
  57. exit;
  58. }
  59. if (!check_owner(authentication_get_username(), $fDomain)) {
  60. 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
  61. unset($_SESSION['list-virtual:domain']);
  62. header("Location: list.php?table=domain"); # domain not owned by this admin
  63. exit(0);
  64. }
  65. // store domain and page browser offset in $_SESSION so after adding/editing aliases/mailboxes we can
  66. // take the user back to the appropriate domain listing.
  67. $_SESSION['list-virtual:domain'] = $fDomain;
  68. $_SESSION['prefill:alias:domain'] = $fDomain;
  69. $_SESSION['prefill:mailbox:domain'] = $fDomain;
  70. $_SESSION['prefill:aliasdomain:target_domain'] = $fDomain;
  71. $_SESSION['list-virtual:limit'] = $fDisplay;
  72. #
  73. # alias domain
  74. #
  75. if (Config::bool('alias_domain')) {
  76. $handler = new AliasdomainHandler(0, $admin_username);
  77. $formconf = $handler->webformConfig(); # might change struct
  78. $aliasdomain_data = array(
  79. 'struct' => $handler->getStruct(),
  80. 'msg' => $handler->getMsg(),
  81. 'formconf' => $formconf,
  82. );
  83. $aliasdomain_data['msg']['show_simple_search'] = false; # hide search box
  84. $aliasdomain_data['msg']['can_create'] = 1;
  85. # hide create button if all domains (of this admin) are already used as alias domains
  86. $handler->getList("");
  87. if (count($handler->result()) + 1 >= count($list_domains)) {
  88. $aliasdomain_data['msg']['can_create'] = 0;
  89. } # all domains (of this admin) are already alias domains
  90. # get the really requested list
  91. if (count($search) == 0) {
  92. $list_param = "alias_domain='$fDomain' OR target_domain='$fDomain'";
  93. } else {
  94. $list_param = $search;
  95. }
  96. $handler->getList($list_param);
  97. $tAliasDomains = $handler->result();
  98. foreach ($tAliasDomains as $row) {
  99. if ($row['alias_domain'] == $fDomain) {
  100. $aliasdomain_data['struct']['target_domain']['linkto'] = 'target';
  101. if (count($search) == 0) {
  102. $aliasdomain_data['struct']['alias_domain']['linkto'] = '';
  103. $aliasdomain_data['msg']['can_create'] = 0; # domain is already an alias domain
  104. }
  105. }
  106. }
  107. if (count($search) > 0) {
  108. $aliasdomain_data['struct']['target_domain']['linkto'] = 'target';
  109. }
  110. }
  111. #
  112. # aliases
  113. #
  114. $table_alias = table_by_key('alias');
  115. $table_mailbox = table_by_key('mailbox');
  116. if (count($search) == 0 || !isset($search['_'])) {
  117. $search_alias = array('domain' => $fDomain);
  118. } else {
  119. $search_alias = array('_' => $search['_']);
  120. }
  121. $handler = new AliasHandler(0, $admin_username);
  122. $formconf = $handler->webformConfig(); # might change struct
  123. $alias_data = array(
  124. 'formconf' => $formconf,
  125. 'struct' => $handler->getStruct(),
  126. 'msg' => $handler->getMsg(),
  127. );
  128. $alias_data['struct']['goto_mailbox']['display_in_list'] = 0; # not useful/defined for non-mailbox aliases
  129. $alias_data['struct']['on_vacation']['display_in_list'] = 0;
  130. $alias_data['msg']['show_simple_search'] = false; # hide search box
  131. $handler->getList($search_alias, array(), $page_size, $fDisplay);
  132. $pagebrowser_alias = $handler->getPagebrowser($search_alias, array());
  133. $tAlias = $handler->result();
  134. #
  135. # mailboxes
  136. #
  137. $display_mailbox_aliases = Config::bool('alias_control_admin');
  138. # build the sql query
  139. $sql_select = "SELECT $table_mailbox.* ";
  140. $sql_from = " FROM $table_mailbox ";
  141. $sql_join = "";
  142. $sql_where = " WHERE ";
  143. $sql_order = " ORDER BY $table_mailbox.username ";
  144. $sql_limit = " LIMIT $page_size OFFSET $fDisplay";
  145. if (count($search) == 0 || !isset($search['_'])) {
  146. $sql_where .= " $table_mailbox.domain='$fDomain' ";
  147. } else {
  148. $searchterm = escape_string($search['_']);
  149. $sql_where .= db_in_clause("$table_mailbox.domain", $list_domains) . " ";
  150. $sql_where .= " AND ( $table_mailbox.username LIKE '%$searchterm%' OR $table_mailbox.name LIKE '%$searchterm%' ";
  151. if ($display_mailbox_aliases) {
  152. $sql_where .= " OR $table_alias.goto LIKE '%$searchterm%' ";
  153. }
  154. $sql_where .= " ) "; # $search is already escaped
  155. }
  156. if ($display_mailbox_aliases) {
  157. $sql_select .= ", $table_alias.goto ";
  158. $sql_join .= " LEFT JOIN $table_alias ON $table_mailbox.username=$table_alias.address ";
  159. }
  160. if (Config::bool('vacation_control_admin')) {
  161. $table_vacation = table_by_key('vacation');
  162. $sql_select .= ", $table_vacation.active AS v_active ";
  163. $sql_join .= " LEFT JOIN $table_vacation ON $table_mailbox.username=$table_vacation.email ";
  164. }
  165. if (Config::bool('used_quotas') && Config::bool('new_quota_table')) {
  166. $table_quota2 = table_by_key('quota2');
  167. $sql_select .= ", $table_quota2.bytes as current ";
  168. $sql_join .= " LEFT JOIN $table_quota2 ON $table_mailbox.username=$table_quota2.username ";
  169. }
  170. if (Config::bool('used_quotas') && (! Config::bool('new_quota_table'))) {
  171. $table_quota = table_by_key('quota');
  172. $sql_select .= ", $table_quota.current ";
  173. $sql_join .= " LEFT JOIN $table_quota ON $table_mailbox.username=$table_quota.username ";
  174. $sql_where .= " AND ( $table_quota.path='quota/storage' OR $table_quota.path IS NULL ) ";
  175. }
  176. $mailbox_pagebrowser_query = "$sql_from\n$sql_join\n$sql_where\n$sql_order" ;
  177. $query = "$sql_select\n$mailbox_pagebrowser_query\n$sql_limit";
  178. $result = db_query($query);
  179. $tMailbox = array();
  180. if ($result['rows'] > 0) {
  181. $delimiter = preg_quote($CONF['recipient_delimiter'], "/");
  182. $goto_single_rec_del = "";
  183. while ($row = db_assoc($result['result'])) {
  184. if ($display_mailbox_aliases) {
  185. $goto_split = explode(",", $row['goto']);
  186. $row['goto_mailbox'] = 0;
  187. $row['goto_other'] = array();
  188. foreach ($goto_split as $goto_single) {
  189. if (!empty($CONF['recipient_delimiter'])) {
  190. $goto_single_rec_del = preg_replace('/' .$delimiter. '[^' .$delimiter. '@]*@/', "@", $goto_single);
  191. }
  192. if ($goto_single == $row['username'] || $goto_single_rec_del == $row['username']) { # delivers to mailbox
  193. $row['goto_mailbox'] = 1;
  194. } elseif (Config::bool('vacation') && strstr($goto_single, '@' . $CONF['vacation_domain'])) { # vacation alias - TODO: check for full vacation alias
  195. # skip the vacation alias, vacation status is detected otherwise
  196. } else { # forwarding to other alias
  197. $row['goto_other'][] = $goto_single;
  198. }
  199. }
  200. }
  201. if (db_pgsql()) {
  202. // XXX
  203. $row['modified'] = date('Y-m-d H:i', strtotime($row['modified']));
  204. $row['created'] = date('Y-m-d H:i', strtotime($row['created']));
  205. $row['active']=('t'==$row['active']) ? 1 : 0;
  206. if (Config::bool('vacation_control_admin')) {
  207. if ($row['v_active'] == null) {
  208. $row['v_active'] = 'f';
  209. }
  210. $row['v_active']=('t'==$row['v_active']) ? 1 : 0;
  211. }
  212. }
  213. $tMailbox[] = $row;
  214. }
  215. }
  216. $alias_data['msg']['can_create'] = false;
  217. $tCanAddMailbox = false;
  218. $tDisplay_back = "";
  219. $tDisplay_back_show = "";
  220. $tDisplay_up_show = "";
  221. $tDisplay_next = "";
  222. $tDisplay_next_show = "";
  223. $limit = get_domain_properties($fDomain);
  224. if (isset($limit)) {
  225. if ($fDisplay >= $page_size) {
  226. $tDisplay_back_show = 1;
  227. $tDisplay_back = $fDisplay - $page_size;
  228. }
  229. if (($limit['alias_count'] > $page_size) or ($limit['mailbox_count'] > $page_size)) {
  230. $tDisplay_up_show = 1;
  231. }
  232. if (
  233. (($fDisplay + $page_size) < $limit['alias_count']) or
  234. (($fDisplay + $page_size) < $limit['mailbox_count'])
  235. ) {
  236. $tDisplay_next_show = 1;
  237. $tDisplay_next = $fDisplay + $page_size;
  238. }
  239. if ($limit['aliases'] == 0) {
  240. $alias_data['msg']['can_create'] = true;
  241. } elseif ($limit['alias_count'] < $limit['aliases']) {
  242. $alias_data['msg']['can_create'] = true;
  243. }
  244. if ($limit['mailboxes'] == 0) {
  245. $tCanAddMailbox = true;
  246. } elseif ($limit['mailbox_count'] < $limit['mailboxes']) {
  247. $tCanAddMailbox = true;
  248. }
  249. $limit ['aliases'] = eval_size($limit ['aliases']);
  250. $limit ['mailboxes'] = eval_size($limit ['mailboxes']);
  251. if (Config::bool('quota')) {
  252. $limit ['maxquota'] = eval_size($limit ['maxquota']);
  253. }
  254. }
  255. $gen_show_status_mailbox = array();
  256. $divide_quota = array('current' => array(), 'quota' => array());
  257. if ((is_array($tMailbox) and sizeof($tMailbox) > 0)) {
  258. for ($i = 0; $i < sizeof($tMailbox); $i++) {
  259. $gen_show_status_mailbox [$i] = gen_show_status($tMailbox[$i]['username']);
  260. if (isset($tMailbox[$i]['current'])) {
  261. $divide_quota ['current'][$i] = divide_quota($tMailbox[$i]['current']);
  262. }
  263. if (isset($tMailbox[$i]['quota'])) {
  264. $divide_quota ['quota'][$i] = divide_quota($tMailbox[$i]['quota']);
  265. }
  266. if (isset($tMailbox[$i]['quota']) && isset($tMailbox[$i]['current'])) {
  267. $divide_quota ['percent'][$i] = min(100, round(($divide_quota ['current'][$i]/max(1, $divide_quota ['quota'][$i]))*100));
  268. $divide_quota ['quota_width'][$i] = ($divide_quota ['percent'][$i] / 100 * 120);
  269. } else {
  270. $divide_quota ['current'][$i] = Config::Lang('unknown');
  271. $divide_quota ['quota_width'][$i] = 0; # TODO: use special value?
  272. }
  273. }
  274. }
  275. class cNav_bar {
  276. protected $count;
  277. protected $title;
  278. protected $limit;
  279. protected $page_size;
  280. protected $pages;
  281. protected $search; //* arguments
  282. /* @var string - appended to page link href */
  283. public $append_to_url = '';
  284. protected $have_run_init = false;
  285. protected $arr_prev;
  286. protected $arr_next;
  287. protected $arr_top; //* internal
  288. protected $anchor;
  289. public function __construct($aTitle, $aLimit, $aPage_size, $aPages, $aSearch) {
  290. $this->count = count($aPages);
  291. $this->title = $aTitle;
  292. $this->limit = $aLimit;
  293. $this->page_size = $aPage_size;
  294. $this->pages = $aPages;
  295. if (is_array($aSearch) && isset($aSearch['_']) && $aSearch['_'] != "") {
  296. $this->search = "&search[_]=" . htmlentities($aSearch['_']);
  297. } else {
  298. $this->search = "";
  299. }
  300. }
  301. private function init() {
  302. $this->anchor = 'a'.substr($this->title, 3);
  303. $this->append_to_url .= '#'.$this->anchor;
  304. ($this->limit >= $this->page_size) ? $this->arr_prev = '&nbsp;<a href="?limit='.($this->limit - $this->page_size).$this->search.$this->append_to_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 = '';
  305. ($this->limit > 0) ? $this->arr_top = '&nbsp;<a href="?limit=0' .$this->search.$this->append_to_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 = '';
  306. (($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->append_to_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 = '';
  307. $this->have_run_init = true;
  308. }
  309. private function display_pre() {
  310. $ret_val = '<div class="nav_bar"';
  311. //$ret_val .= ' style="background-color:#ffa;"';
  312. $ret_val .= '>';
  313. $ret_val .= '<table width="730"><colgroup span="1"><col width="550"></col></colgroup> ';
  314. $ret_val .= '<tr><td align="left">';
  315. return $ret_val;
  316. }
  317. private function display_post() {
  318. $ret_val = '</td></tr></table></div>';
  319. return $ret_val;
  320. }
  321. public function display_top() {
  322. $ret_val = '';
  323. if ($this->count < 1) {
  324. return $ret_val;
  325. }
  326. if (!$this->have_run_init) {
  327. $this->init();
  328. }
  329. $ret_val .= '<a name="'.$this->anchor.'"></a>';
  330. $ret_val .= $this->display_pre();
  331. $ret_val .= '<b>'.$this->title.'</b>&nbsp;&nbsp;';
  332. ($this->limit >= $this->page_size) ? $highlight_at = $this->limit / $this->page_size : $highlight_at = 0;
  333. for ($i = 0; $i < count($this->pages); $i++) {
  334. $lPage = $this->pages [$i];
  335. if ($i == $highlight_at) {
  336. $ret_val .= '<b>'.$lPage.'</b>'."\n";
  337. } else {
  338. $ret_val .= '<a href="?limit='.($i * $this->page_size).$this->search.$this->append_to_url.'">'.$lPage.'</a>'."\n";
  339. }
  340. }
  341. $ret_val .= '</td><td valign="middle" align="right">';
  342. $ret_val .= $this->arr_prev;
  343. $ret_val .= $this->arr_top;
  344. $ret_val .= $this->arr_next;
  345. $ret_val .= $this->display_post();
  346. return $ret_val;
  347. }
  348. public function display_bottom() {
  349. $ret_val = '';
  350. if ($this->count < 1) {
  351. return $ret_val;
  352. }
  353. if (!$this->have_run_init) {
  354. $this->init();
  355. }
  356. $ret_val .= $this->display_pre();
  357. $ret_val .= '</td><td valign="middle" align="right">';
  358. $ret_val .= $this->arr_prev;
  359. $ret_val .= $this->arr_top;
  360. $ret_val .= $this->arr_next;
  361. $ret_val .= $this->display_post();
  362. return $ret_val;
  363. }
  364. }
  365. $nav_bar_alias = new cNav_bar($PALANG['pOverview_alias_title'], $fDisplay, $CONF['page_size'], $pagebrowser_alias, $search);
  366. $nav_bar_alias->append_to_url = '&amp;domain='.$fDomain;
  367. $pagebrowser_mailbox = create_page_browser("$table_mailbox.username", $mailbox_pagebrowser_query);
  368. $nav_bar_mailbox = new cNav_bar($PALANG['pOverview_mailbox_title'], $fDisplay, $CONF['page_size'], $pagebrowser_mailbox, $search);
  369. $nav_bar_mailbox->append_to_url = '&amp;domain='.$fDomain;
  370. // this is why we need a proper template layer.
  371. $fDomain = htmlentities($fDomain, ENT_QUOTES);
  372. if (empty($_GET['domain'])) {
  373. $_GET['domain'] = '';
  374. }
  375. $smarty->assign('admin_list', array());
  376. $smarty->assign('domain_list', $list_domains);
  377. $smarty->assign('domain_selected', $fDomain);
  378. $smarty->assign('nav_bar_alias', array('top' => $nav_bar_alias->display_top(), 'bottom' => $nav_bar_alias->display_bottom()), false);
  379. $smarty->assign('nav_bar_mailbox', array('top' => $nav_bar_mailbox->display_top(), 'bottom' => $nav_bar_mailbox->display_bottom()), false);
  380. $smarty->assign('fDomain', $fDomain, false);
  381. $smarty->assign('search', $search);
  382. $smarty->assign('list_domains', $list_domains);
  383. $smarty->assign('limit', $limit);
  384. $smarty->assign('tDisplay_back_show', $tDisplay_back_show);
  385. $smarty->assign('tDisplay_back', $tDisplay_back);
  386. $smarty->assign('tDisplay_up_show', $tDisplay_up_show);
  387. $smarty->assign('tDisplay_next_show', $tDisplay_next_show);
  388. $smarty->assign('tDisplay_next', $tDisplay_next);
  389. if (Config::bool('alias_domain')) {
  390. $smarty->assign('tAliasDomains', $tAliasDomains);
  391. $smarty->assign('aliasdomain_data', $aliasdomain_data);
  392. }
  393. $smarty->assign('tAlias', $tAlias);
  394. $smarty->assign('alias_data', $alias_data);
  395. $smarty->assign('tMailbox', $tMailbox);
  396. $smarty->assign('gen_show_status_mailbox', $gen_show_status_mailbox, false);
  397. $smarty->assign('boolconf_used_quotas', Config::bool('used_quotas'));
  398. $smarty->assign('divide_quota', $divide_quota);
  399. $smarty->assign('tCanAddMailbox', $tCanAddMailbox);
  400. $smarty->assign('display_mailbox_aliases', $display_mailbox_aliases);
  401. if (isset($_GET ['tab'])) {
  402. $_SESSION ['tab'] = $_GET ['tab'];
  403. }
  404. //if (empty ($_GET ['tab']))
  405. // unset ($_SESSION ['tab']);
  406. if (!isset($_SESSION ['tab'])) {
  407. $_SESSION ['tab'] = 'all';
  408. }
  409. $smarty->assign('tab', $_SESSION ['tab']);
  410. $smarty->assign('smarty_template', 'list-virtual');
  411. $smarty->display('index.tpl');
  412. /* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */