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.

2350 lines
66 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
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: functions.inc.php
  16. * Contains re-usable code.
  17. */
  18. $version = '2.3 rc7';
  19. /**
  20. * check_session
  21. * Action: Check if a session already exists, if not redirect to login.php
  22. * Call: check_session ()
  23. * @return String username (e.g. foo@example.com)
  24. */
  25. function authentication_get_username()
  26. {
  27. global $CONF;
  28. if (!isset($_SESSION['sessid'])) {
  29. header ("Location: " . $CONF['postfix_admin_url'] . "/login.php");
  30. exit(0);
  31. }
  32. $SESSID_USERNAME = $_SESSION['sessid']['username'];
  33. return $SESSID_USERNAME;
  34. }
  35. /**
  36. * Returns the type of user - either 'user' or 'admin'
  37. * Returns false if neither (E.g. if not logged in)
  38. * @return String admin or user or (boolean) false.
  39. */
  40. function authentication_get_usertype() {
  41. if(isset($_SESSION['sessid'])) {
  42. if(isset($_SESSION['sessid']['type'])) {
  43. return $_SESSION['sessid']['type'];
  44. }
  45. }
  46. return false;
  47. }
  48. /**
  49. *
  50. * Used to determine whether a user has a particular role.
  51. * @param String role-name. (E.g. admin, global-admin or user)
  52. * @return boolean True if they have the requested role in their session.
  53. * Note, user < admin < global-admin
  54. */
  55. function authentication_has_role($role) {
  56. global $CONF;
  57. if(isset($_SESSION['sessid'])) {
  58. if(isset($_SESSION['sessid']['roles'])) {
  59. if(in_array($role, $_SESSION['sessid']['roles'])) {
  60. return true;
  61. }
  62. }
  63. }
  64. return false;
  65. }
  66. /**
  67. * Used to enforce that $user has a particular role when
  68. * viewing a page.
  69. * If they are lacking a role, redirect them to
  70. * $CONF['postfix_admin_url']/login.php
  71. *
  72. * Note, user < admin < global-admin
  73. */
  74. function authentication_require_role($role) {
  75. global $CONF;
  76. // redirect to appropriate page?
  77. if(authentication_has_role($role)) {
  78. return True;
  79. }
  80. header("Location: " . $CONF['postfix_admin_url'] . "/login.php");
  81. exit(0);
  82. }
  83. /**
  84. * @return boolean TRUE if a admin, FALSE otherwise.
  85. */
  86. function authentication_is_admin() {
  87. return authentication_get_usertype() == 'admin';
  88. }
  89. /**
  90. * @return boolean TRUE if a user, FALSE otherwise.
  91. */
  92. function authentication_is_user() {
  93. return authentication_get_usertype() == 'user';
  94. }
  95. /**
  96. * Add an error message for display on the next page that is rendered.
  97. * @param String message to show.
  98. *
  99. * Stores string in session. Flushed through header template.
  100. * @see _flash_string()
  101. */
  102. function flash_error($string) {
  103. _flash_string('error', $string);
  104. }
  105. /**
  106. * Used to display an info message on successful update.
  107. * @param String $string
  108. * Stores data in sessio.
  109. * @see _flash_string()
  110. */
  111. function flash_info($string) {
  112. _flash_string('info', $string);
  113. }
  114. /**
  115. * 'Private' method used for flash_info() and flash_error().
  116. */
  117. function _flash_string($type, $string) {
  118. if(!isset($_SESSION['flash'])) {
  119. $_SESSION['flash'] = array();
  120. }
  121. if(!isset($_SESSION['flash'][$type])) {
  122. $_SESSION['flash'][$type] = array();
  123. }
  124. $_SESSION['flash'][$type][] = $string;
  125. }
  126. //
  127. // check_language
  128. // Action: checks what language the browser uses
  129. // Call: check_language
  130. // Parameter: $use_post - set to 0 if $_POST should NOT be read
  131. //
  132. function check_language ($use_post = 1)
  133. {
  134. global $CONF;
  135. global $supported_languages; # from languages/languages.php
  136. $lang = $CONF['default_language'];
  137. if(isset($_SERVER['HTTP_ACCEPT_LANGUAGE']))
  138. {
  139. $lang_array = preg_split ('/(\s*,\s*)/', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
  140. if (safecookie('lang')) {
  141. array_unshift($lang_array, safecookie('lang')); # prefer language from cookie
  142. }
  143. if ( $use_post && safepost('lang')) {
  144. array_unshift($lang_array, safepost('lang')); # but prefer $_POST['lang'] even more
  145. }
  146. for($i = 0; $i < count($lang_array); $i++)
  147. {
  148. $lang_next = $lang_array[$i];
  149. $lang_next = strtolower(trim($lang_next));
  150. if(array_key_exists($lang_next, $supported_languages))
  151. {
  152. $lang = $lang_next;
  153. break;
  154. }
  155. }
  156. }
  157. return $lang;
  158. }
  159. //
  160. // language_selector
  161. // Action: returns a language selector dropdown with the browser (or cookie) language preselected
  162. // Call: language_selector()
  163. //
  164. function language_selector()
  165. {
  166. global $supported_languages; # from languages/languages.php
  167. $current_lang = check_language();
  168. $selector = '<select name="lang" xml:lang="en" dir="ltr">';
  169. foreach($supported_languages as $lang => $lang_name) {
  170. if ($lang == $current_lang) {
  171. $selected = ' selected="selected"';
  172. } else {
  173. $selected = '';
  174. }
  175. $selector .= "<option value='$lang'$selected>$lang_name</option>";
  176. }
  177. $selector .= "</select>";
  178. return $selector;
  179. }
  180. //
  181. // check_string
  182. // Action: checks if a string is valid and returns TRUE if this is the case.
  183. // Call: check_string (string var)
  184. //
  185. function check_string ($var)
  186. {
  187. if (preg_match ('/^([A-Za-z0-9 ]+)+$/', $var))
  188. {
  189. return true;
  190. }
  191. else
  192. {
  193. return false;
  194. }
  195. }
  196. //
  197. // check_domain
  198. // Action: Checks if domain is valid and returns TRUE if this is the case.
  199. // Call: check_domain (string domain)
  200. //
  201. // TODO: make check_domain able to handle as example .local domains
  202. function check_domain ($domain)
  203. {
  204. global $CONF;
  205. global $PALANG;
  206. if (!preg_match ('/([-0-9A-Z]+\.)+' . '([0-9A-Z]){2,6}$/i', trim ($domain)))
  207. {
  208. flash_error(sprintf($PALANG['pInvalidDomainRegex'], htmlentities($domain)));
  209. return false;
  210. }
  211. if (isset($CONF['emailcheck_resolve_domain']) && 'YES' == $CONF['emailcheck_resolve_domain'] && 'WINDOWS'!=(strtoupper(substr(php_uname('s'), 0, 7))))
  212. {
  213. // Look for an AAAA, A, or MX record for the domain
  214. if(function_exists('checkdnsrr')) {
  215. // AAAA (IPv6) is only available in PHP v. >= 5
  216. if (version_compare(phpversion(), "5.0.0", ">="))
  217. {
  218. if (checkdnsrr($domain,'AAAA')) return true;
  219. }
  220. if (checkdnsrr($domain,'A')) return true;
  221. if (checkdnsrr($domain,'MX')) return true;
  222. flash_error(sprintf($PALANG['pInvalidDomainDNS'], htmlentities($domain)));
  223. return false;
  224. }
  225. else {
  226. flash_error("emailcheck_resolve_domain is enabled, but function (checkdnsrr) missing!");
  227. }
  228. }
  229. return true;
  230. }
  231. /**
  232. * check_email
  233. * Checks if an email is valid - if it is, return true, else false.
  234. * @param String $email - a string that may be an email address.
  235. * @return boolean true if it's an email address, else false.
  236. * TODO: make check_email able to handle already added domains
  237. */
  238. function check_email ($email)
  239. {
  240. global $CONF;
  241. global $PALANG;
  242. $ce_email=$email;
  243. //strip the vacation domain out if we are using it
  244. //and change from blah#foo.com@autoreply.foo.com to blah@foo.com
  245. if ($CONF['vacation'] == 'YES')
  246. {
  247. $vacation_domain = $CONF['vacation_domain'];
  248. $ce_email = preg_replace("/@$vacation_domain/", '', $ce_email);
  249. $ce_email = preg_replace("/#/", '@', $ce_email);
  250. }
  251. // Perform non-domain-part sanity checks
  252. if (!preg_match ('/^[-!#$%&\'*+\\.\/0-9=?A-Z^_{|}~]+' . '@' . '[^@]+$/i', trim ($ce_email)))
  253. {
  254. flash_error($PALANG['pInvalidMailRegex']);
  255. return false;
  256. }
  257. // Determine domain name
  258. $matches=array();
  259. if (!preg_match('|@(.+)$|',$ce_email,$matches))
  260. {
  261. flash_error($PALANG['pInvalidMailRegex']);
  262. return false;
  263. }
  264. $domain=$matches[1];
  265. # check domain name
  266. return check_domain($domain);
  267. }
  268. /**
  269. * Clean a string, escaping any meta characters that could be
  270. * used to disrupt an SQL string. i.e. "'" => "\'" etc.
  271. *
  272. * @param String (or Array)
  273. * @return String (or Array) of cleaned data, suitable for use within an SQL
  274. * statement.
  275. */
  276. function escape_string ($string)
  277. {
  278. global $CONF;
  279. // if the string is actually an array, do a recursive cleaning.
  280. // Note, the array keys are not cleaned.
  281. if(is_array($string)) {
  282. $clean = array();
  283. foreach(array_keys($string) as $row) {
  284. $clean[$row] = escape_string($string[$row]);
  285. }
  286. return $clean;
  287. }
  288. if (get_magic_quotes_gpc ())
  289. {
  290. $string = stripslashes($string);
  291. }
  292. if (!is_numeric($string))
  293. {
  294. $link = db_connect();
  295. if ($CONF['database_type'] == "mysql")
  296. {
  297. $escaped_string = mysql_real_escape_string($string, $link);
  298. }
  299. if ($CONF['database_type'] == "mysqli")
  300. {
  301. $escaped_string = mysqli_real_escape_string($link, $string);
  302. }
  303. if ($CONF['database_type'] == "pgsql")
  304. {
  305. // php 5.2+ allows for $link to be specified.
  306. if (version_compare(phpversion(), "5.2.0", ">="))
  307. {
  308. $escaped_string = pg_escape_string($link, $string);
  309. }
  310. else
  311. {
  312. $escaped_string = pg_escape_string($string);
  313. }
  314. }
  315. }
  316. else
  317. {
  318. $escaped_string = $string;
  319. }
  320. return $escaped_string;
  321. }
  322. /**
  323. * safeget
  324. * Action: get value from $_GET[$param], or $default if $_GET[$param] is not set
  325. * Call: $param = safeget('param') # replaces $param = $_GET['param']
  326. * - or -
  327. * $param = safeget('param', 'default')
  328. *
  329. * @param String parameter name.
  330. * @param String (optional) - default value if key is not set.
  331. * @return String
  332. */
  333. function safeget ($param, $default="") {
  334. $retval=$default;
  335. if (isset($_GET[$param])) $retval=$_GET[$param];
  336. return $retval;
  337. }
  338. /**
  339. * safepost - similar to safeget()
  340. * @see safeget()
  341. * @param String parameter name
  342. * @param String (optional) default value (defaults to "")
  343. * @return String - value in $_POST[$param] or $default
  344. * same as safeget, but for $_POST
  345. */
  346. function safepost ($param, $default="") {
  347. $retval=$default;
  348. if (isset($_POST[$param])) $retval=$_POST[$param];
  349. return $retval;
  350. }
  351. /**
  352. * safeserver
  353. * @see safeget()
  354. * @param String $param
  355. * @param String $default (optional)
  356. * @return String value from $_SERVER[$param] or $default
  357. */
  358. function safeserver ($param, $default="") {
  359. $retval=$default;
  360. if (isset($_SERVER[$param])) $retval=$_SERVER[$param];
  361. return $retval;
  362. }
  363. /**
  364. * safecookie
  365. * @see safeget()
  366. * @param String $param
  367. * @param String $default (optional)
  368. * @return String value from $_COOKIE[$param] or $default
  369. */
  370. function safecookie ($param, $default="") {
  371. $retval=$default;
  372. if (isset($_COOKIE[$param])) $retval=$_COOKIE[$param];
  373. return $retval;
  374. }
  375. //
  376. // get_domain_properties
  377. // Action: Get all the properties of a domain.
  378. // Call: get_domain_properties (string domain)
  379. //
  380. function get_domain_properties ($domain)
  381. {
  382. global $CONF;
  383. global $table_alias, $table_mailbox, $table_domain;
  384. $list = array ();
  385. $result = db_query ("SELECT COUNT(*) FROM $table_alias WHERE domain='$domain'");
  386. $row = db_row ($result['result']);
  387. $list['alias_count'] = $row[0];
  388. $result = db_query ("SELECT COUNT(*) FROM $table_mailbox WHERE domain='$domain'");
  389. $row = db_row ($result['result']);
  390. $list['mailbox_count'] = $row[0];
  391. $result = db_query ("SELECT SUM(quota) FROM $table_mailbox WHERE domain='$domain'");
  392. $row = db_row ($result['result']);
  393. $list['quota_sum'] = $row[0];
  394. $list['alias_count'] = $list['alias_count'] - $list['mailbox_count'];
  395. $list['alias_pgindex']=array ();
  396. $list['mbox_pgindex']=array ();
  397. $list['mbox_pgindex_count'] = 0;
  398. //while loop to figure index names. use page_size and loop of queries
  399. $i=0;
  400. $current=0;
  401. $page_size = $CONF['page_size'];
  402. $tmpstr="";
  403. $idxlabel="";
  404. $list['alias_pgindex_count'] = 0;
  405. if ( $list['alias_count'] > $page_size )
  406. {
  407. while ( $current < $list['alias_count'] )
  408. {
  409. $limitSql=('pgsql'==$CONF['database_type']) ? "1 OFFSET $current" : "$current, 1";
  410. $query = "SELECT $table_alias.address
  411. FROM $table_alias
  412. LEFT JOIN $table_mailbox ON $table_alias.address=$table_mailbox.username
  413. WHERE ($table_alias.domain='$domain' AND $table_mailbox.maildir IS NULL)
  414. ORDER BY $table_alias.address LIMIT $limitSql";
  415. $result = db_query ("$query");
  416. $row = db_array ($result['result']);
  417. $tmpstr = $row['address'];
  418. //get first 2 chars
  419. $idxlabel = $tmpstr[0] . $tmpstr[1] . "-";
  420. ($current + $page_size - 1 <= $list['alias_count']) ? $current = $current + $page_size - 1 : $current = $list['alias_count'] - 1;
  421. $limitSql=('pgsql'==$CONF['database_type']) ? "1 OFFSET $current" : "$current, 1";
  422. $query = "SELECT $table_alias.address
  423. FROM $table_alias
  424. LEFT JOIN $table_mailbox ON $table_alias.address=$table_mailbox.username
  425. WHERE ($table_alias.domain='$domain' AND $table_mailbox.maildir IS NULL)
  426. ORDER BY $table_alias.address LIMIT $limitSql";
  427. $result = db_query ("$query");
  428. $row = db_array ($result['result']);
  429. $tmpstr = $row['address'];
  430. $idxlabel = $idxlabel . $tmpstr[0] . $tmpstr[1];
  431. $current = $current + 1;
  432. $list['alias_pgindex'][]=$idxlabel;
  433. $i++;
  434. }
  435. $list['alias_pgindex_count']=$i;
  436. }
  437. $i=0;
  438. $current=0;
  439. $page_size = $CONF['page_size'];
  440. $tmpstr="";
  441. $idxlabel="";
  442. if ( $list['mailbox_count'] > $page_size )
  443. {
  444. while ( $current < $list['mailbox_count'] )
  445. {
  446. $limitSql=('pgsql'==$CONF['database_type']) ? "1 OFFSET $current" : "$current, 1";
  447. $query = "SELECT $table_mailbox.username FROM $table_mailbox WHERE $table_mailbox.domain='$domain' ORDER BY $table_mailbox.username LIMIT $limitSql";
  448. $result = db_query ("$query");
  449. $row = db_array ($result['result']);
  450. $tmpstr = $row['username'];
  451. //get first 2 chars
  452. $idxlabel = $tmpstr[0] . $tmpstr[1] . "-";
  453. ($current + $page_size - 1 <= $list['mailbox_count']) ? $current = $current + $page_size - 1 : $current = $list['mailbox_count'] - 1;
  454. $limitSql=('pgsql'==$CONF['database_type']) ? "1 OFFSET $current" : "$current, 1";
  455. $query = "SELECT $table_mailbox.username FROM $table_mailbox WHERE $table_mailbox.domain='$domain' ORDER BY $table_mailbox.username LIMIT $limitSql";
  456. $result = db_query ("$query");
  457. $row = db_array ($result['result']);
  458. $tmpstr = $row['username'];
  459. $idxlabel = $idxlabel . $tmpstr[0] . $tmpstr[1];
  460. $current = $current + 1;
  461. $list['mbox_pgindex'][]=$idxlabel;
  462. $i++;
  463. }
  464. $list['mbox_pgindex_count']=$i;
  465. }
  466. // end mod
  467. $query="SELECT * FROM $table_domain WHERE domain='$domain'";
  468. if ('pgsql'==$CONF['database_type'])
  469. {
  470. $query=" SELECT *, EXTRACT(epoch FROM created) AS uts_created, EXTRACT(epoch FROM modified) AS uts_modified FROM $table_domain WHERE domain='$domain' ";
  471. }
  472. $result = db_query ($query);
  473. $row = db_array ($result['result']);
  474. $list['description'] = $row['description'];
  475. $list['aliases'] = $row['aliases'];
  476. $list['mailboxes'] = $row['mailboxes'];
  477. $list['maxquota'] = $row['maxquota'];
  478. $list['quota'] = $row['quota'];
  479. $list['transport'] = $row['transport'];
  480. $list['backupmx'] = $row['backupmx'];
  481. $list['created'] = $row['created'];
  482. $list['modified'] = $row['modified'];
  483. $list['active'] = $row['active'];
  484. if ($CONF['database_type'] == "pgsql")
  485. {
  486. $list['active']=('t'==$row['active']) ? 1 : 0;
  487. $list['backupmx']=('t'==$row['backupmx']) ? 1 : 0;
  488. $list['created']= gmstrftime('%c %Z',$row['uts_created']);
  489. $list['modified']= gmstrftime('%c %Z',$row['uts_modified']);
  490. }
  491. else
  492. {
  493. $list['active'] = $row['active'];
  494. $list['backupmx'] = $row['backupmx'];
  495. }
  496. return $list;
  497. }
  498. //
  499. // get_mailbox_properties
  500. // Action: Get all the properties of a mailbox.
  501. // Call: get_mailbox_properties (string mailbox)
  502. //
  503. function get_mailbox_properties ($username)
  504. {
  505. global $CONF;
  506. global $table_mailbox;
  507. $query="SELECT * FROM $table_mailbox WHERE username='$username'";
  508. if ('pgsql'==$CONF['database_type'])
  509. {
  510. $query="
  511. SELECT
  512. *,
  513. EXTRACT(epoch FROM created) AS uts_created,
  514. EXTRACT(epoch FROM modified) AS uts_modified
  515. FROM $table_mailbox
  516. WHERE username='$username'
  517. ";
  518. }
  519. $result = db_query ($query);
  520. $row = db_array ($result['result']);
  521. $list['name'] = $row['name'];
  522. $list['maildir'] = $row['maildir'];
  523. $list['quota'] = $row['quota'];
  524. $list['domain'] = $row['domain'];
  525. $list['created'] = $row['created'];
  526. $list['modified'] = $row['modified'];
  527. $list['active'] = $row['active'];
  528. if ($CONF['database_type'] == "pgsql")
  529. {
  530. $list['active']=('t'==$row['active']) ? 1 : 0;
  531. $list['created']= gmstrftime('%c %Z',$row['uts_created']);
  532. $list['modified']= gmstrftime('%c %Z',$row['uts_modified']);
  533. }
  534. else
  535. {
  536. $list['active'] = $row['active'];
  537. }
  538. return $list;
  539. }
  540. //
  541. // check_alias
  542. // Action: Checks if the domain is still able to create aliases.
  543. // Call: check_alias (string domain)
  544. //
  545. function check_alias ($domain)
  546. {
  547. $limit = get_domain_properties ($domain);
  548. if ($limit['aliases'] == 0)
  549. {
  550. # 0 = unlimited, -1 = disabled
  551. return true;
  552. }
  553. if ($limit['aliases'] < 0)
  554. {
  555. return false;
  556. }
  557. if ($limit['alias_count'] >= $limit['aliases'])
  558. {
  559. return false;
  560. }
  561. else
  562. {
  563. return true;
  564. }
  565. }
  566. //
  567. // check_mailbox
  568. // Action: Checks if the domain is still able to create mailboxes.
  569. // Call: check_mailbox (string domain)
  570. //
  571. function check_mailbox ($domain)
  572. {
  573. $limit = get_domain_properties ($domain);
  574. /* -1 = disable, 0 = unlimited */
  575. if ($limit['mailboxes'] == 0)
  576. {
  577. return true;
  578. }
  579. if ($limit['mailboxes'] < 0)
  580. {
  581. return false;
  582. }
  583. if ($limit['mailbox_count'] >= $limit['mailboxes'])
  584. {
  585. return false;
  586. }
  587. else
  588. {
  589. return true;
  590. }
  591. }
  592. //
  593. // check_quota
  594. // Action: Checks if the user is creating a mailbox with the correct quota
  595. // Call: check_quota (string domain)
  596. //
  597. function check_quota ($quota, $domain)
  598. {
  599. $limit = get_domain_properties ($domain);
  600. if ($limit['maxquota'] == 0)
  601. {
  602. return true;
  603. }
  604. if (($limit['maxquota'] < 0) and ($quota < 0))
  605. {
  606. return true;
  607. }
  608. if (($limit['maxquota'] > 0) and ($quota == 0))
  609. {
  610. return false;
  611. }
  612. if ($quota > $limit['maxquota'])
  613. {
  614. return false;
  615. }
  616. else
  617. {
  618. return true;
  619. }
  620. }
  621. //
  622. // multiply_quota
  623. // Action: Recalculates the quota from bytes to MBs (multiply, *)
  624. // Call: multiply_quota (string $quota)
  625. //
  626. function multiply_quota ($quota)
  627. {
  628. global $CONF;
  629. if ($quota == -1) return $quota;
  630. $value = $quota * $CONF['quota_multiplier'];
  631. return $value;
  632. }
  633. //
  634. // divide_quota
  635. // Action: Recalculates the quota from MBs to bytes (divide, /)
  636. // Call: divide_quota (string $quota)
  637. //
  638. function divide_quota ($quota)
  639. {
  640. global $CONF;
  641. if ($quota == -1) return $quota;
  642. $value = round($quota / $CONF['quota_multiplier'],2);
  643. return $value;
  644. }
  645. //
  646. // check_owner
  647. // Action: Checks if the admin is the owner of the domain (or global-admin)
  648. // Call: check_owner (string admin, string domain)
  649. //
  650. function check_owner ($username, $domain)
  651. {
  652. global $table_domain_admins;
  653. $result = db_query ("SELECT 1 FROM $table_domain_admins WHERE username='$username' AND (domain='$domain' OR domain='ALL') AND active='1'");
  654. if ($result['rows'] != 1)
  655. {
  656. return false;
  657. }
  658. else
  659. {
  660. return true;
  661. }
  662. }
  663. //
  664. // check_alias_owner
  665. // Action: Checks if the admin is the owner of the alias.
  666. // Call: check_alias_owner (string admin, string alias)
  667. //
  668. function check_alias_owner ($username, $alias)
  669. {
  670. global $CONF;
  671. if (authentication_has_role('global-admin')) return true;
  672. $tmp = preg_split('/\@/', $alias);
  673. if (($CONF['special_alias_control'] == 'NO') && array_key_exists($tmp[0], $CONF['default_aliases']))
  674. {
  675. return false;
  676. }
  677. else
  678. {
  679. return true;
  680. }
  681. }
  682. /**
  683. * List domains for an admin user.
  684. * @param String $username
  685. * @return array of domain names.
  686. */
  687. function list_domains_for_admin ($username)
  688. {
  689. global $CONF;
  690. global $table_domain, $table_domain_admins;
  691. $list = array ();
  692. // does $username need escaping here?
  693. $active_sql = db_get_boolean(True);
  694. $backupmx_sql = db_get_boolean(False);
  695. $query = "SELECT $table_domain.domain, $table_domain_admins.username FROM $table_domain
  696. LEFT JOIN $table_domain_admins ON $table_domain.domain=$table_domain_admins.domain
  697. WHERE $table_domain_admins.username='$username'
  698. AND $table_domain.active=$active_sql
  699. AND $table_domain.backupmx=$backupmx_sql
  700. ORDER BY $table_domain_admins.domain";
  701. $result = db_query ($query);
  702. if ($result['rows'] > 0)
  703. {
  704. $i = 0;
  705. while ($row = db_array ($result['result']))
  706. {
  707. $list[$i] = $row['domain'];
  708. $i++;
  709. }
  710. }
  711. return $list;
  712. }
  713. //
  714. // list_domains
  715. // Action: List all available domains.
  716. // Call: list_domains ()
  717. //
  718. function list_domains ()
  719. {
  720. global $table_domain;
  721. $list = array();
  722. $result = db_query ("SELECT domain FROM $table_domain WHERE domain!='ALL' ORDER BY domain");
  723. if ($result['rows'] > 0)
  724. {
  725. $i = 0;
  726. while ($row = db_array ($result['result']))
  727. {
  728. $list[$i] = $row['domain'];
  729. $i++;
  730. }
  731. }
  732. return $list;
  733. }
  734. //
  735. // admin_exist
  736. // Action: Checks if the admin already exists.
  737. // Call: admin_exist (string admin)
  738. //
  739. function admin_exist ($username)
  740. {
  741. $result = db_query ("SELECT 1 FROM " . table_by_key ('admin') . " WHERE username='$username'");
  742. if ($result['rows'] != 1)
  743. {
  744. return false;
  745. }
  746. else
  747. {
  748. return true;
  749. }
  750. }
  751. //
  752. // domain_exist
  753. // Action: Checks if the domain already exists.
  754. // Call: domain_exist (string domain)
  755. //
  756. function domain_exist ($domain)
  757. {
  758. global $table_domain;
  759. $result = db_query("SELECT 1 FROM $table_domain WHERE domain='$domain'");
  760. if ($result['rows'] != 1)
  761. {
  762. return false;
  763. }
  764. else
  765. {
  766. return true;
  767. }
  768. }
  769. //
  770. // list_admins
  771. // Action: Lists all the admins
  772. // Call: list_admins ()
  773. //
  774. // was admin_list_admins
  775. //
  776. function list_admins ()
  777. {
  778. global $table_admin;
  779. $list = "";
  780. $result = db_query ("SELECT username FROM $table_admin ORDER BY username");
  781. if ($result['rows'] > 0)
  782. {
  783. $i = 0;
  784. while ($row = db_array ($result['result']))
  785. {
  786. $list[$i] = $row['username'];
  787. $i++;
  788. }
  789. }
  790. return $list;
  791. }
  792. //
  793. // get_admin_properties
  794. // Action: Get all the admin properties.
  795. // Call: get_admin_properties (string admin)
  796. //
  797. function get_admin_properties ($username)
  798. {
  799. global $CONF;
  800. global $table_admin, $table_domain_admins;
  801. $list = array ();
  802. $result = db_query ("SELECT * FROM $table_domain_admins WHERE username='$username' AND domain='ALL'");
  803. if ($result['rows'] == 1)
  804. {
  805. $list['domain_count'] = 'ALL';
  806. }
  807. else
  808. {
  809. $result = db_query ("SELECT COUNT(*) FROM $table_domain_admins WHERE username='$username'");
  810. $row = db_row ($result['result']);
  811. $list['domain_count'] = $row[0];
  812. }
  813. $query = "SELECT * FROM $table_admin WHERE username='$username'";
  814. if ('pgsql'==$CONF['database_type']) {
  815. $query="
  816. SELECT
  817. *,
  818. EXTRACT(epoch FROM created) AS uts_created,
  819. EXTRACT (epoch FROM modified) AS uts_modified
  820. FROM $table_admin
  821. WHERE username='$username'
  822. ";
  823. }
  824. $result = db_query ($query);
  825. $row = db_array ($result['result']);
  826. $list['created'] = $row['created'];
  827. $list['modified'] = $row['modified'];
  828. $list['active'] = $row['active'];
  829. if ('pgsql'==$CONF['database_type']) {
  830. $list['active'] = ('t'==$row['active']) ? 1 : 0;
  831. $list['created']= gmstrftime('%c %Z',$row['uts_created']);
  832. $list['modified']= gmstrftime('%c %Z',$row['uts_modified']);
  833. }
  834. return $list;
  835. }
  836. //
  837. // encode_header
  838. // Action: Encode a string according to RFC 1522 for use in headers if it contains 8-bit characters.
  839. // Call: encode_header (string header, string charset)
  840. //
  841. function encode_header ($string, $default_charset = "utf-8")
  842. {
  843. if (strtolower ($default_charset) == 'iso-8859-1')
  844. {
  845. $string = str_replace ("\240",' ',$string);
  846. }
  847. $j = strlen ($string);
  848. $max_l = 75 - strlen ($default_charset) - 7;
  849. $aRet = array ();
  850. $ret = '';
  851. $iEncStart = $enc_init = false;
  852. $cur_l = $iOffset = 0;
  853. for ($i = 0; $i < $j; ++$i)
  854. {
  855. switch ($string{$i})
  856. {
  857. case '=':
  858. case '<':
  859. case '>':
  860. case ',':
  861. case '?':
  862. case '_':
  863. if ($iEncStart === false)
  864. {
  865. $iEncStart = $i;
  866. }
  867. $cur_l+=3;
  868. if ($cur_l > ($max_l-2))
  869. {
  870. $aRet[] = substr ($string,$iOffset,$iEncStart-$iOffset);
  871. $aRet[] = "=?$default_charset?Q?$ret?=";
  872. $iOffset = $i;
  873. $cur_l = 0;
  874. $ret = '';
  875. $iEncStart = false;
  876. }
  877. else
  878. {
  879. $ret .= sprintf ("=%02X",ord($string{$i}));
  880. }
  881. break;
  882. case '(':
  883. case ')':
  884. if ($iEncStart !== false)
  885. {
  886. $aRet[] = substr ($string,$iOffset,$iEncStart-$iOffset);
  887. $aRet[] = "=?$default_charset?Q?$ret?=";
  888. $iOffset = $i;
  889. $cur_l = 0;
  890. $ret = '';
  891. $iEncStart = false;
  892. }
  893. break;
  894. case ' ':
  895. if ($iEncStart !== false)
  896. {
  897. $cur_l++;
  898. if ($cur_l > $max_l)
  899. {
  900. $aRet[] = substr ($string,$iOffset,$iEncStart-$iOffset);
  901. $aRet[] = "=?$default_charset?Q?$ret?=";
  902. $iOffset = $i;
  903. $cur_l = 0;
  904. $ret = '';
  905. $iEncStart = false;
  906. }
  907. else
  908. {
  909. $ret .= '_';
  910. }
  911. }
  912. break;
  913. default:
  914. $k = ord ($string{$i});
  915. if ($k > 126)
  916. {
  917. if ($iEncStart === false)
  918. {
  919. // do not start encoding in the middle of a string, also take the rest of the word.
  920. $sLeadString = substr ($string,0,$i);
  921. $aLeadString = explode (' ',$sLeadString);
  922. $sToBeEncoded = array_pop ($aLeadString);
  923. $iEncStart = $i - strlen ($sToBeEncoded);
  924. $ret .= $sToBeEncoded;
  925. $cur_l += strlen ($sToBeEncoded);
  926. }
  927. $cur_l += 3;
  928. // first we add the encoded string that reached it's max size
  929. if ($cur_l > ($max_l-2))
  930. {
  931. $aRet[] = substr ($string,$iOffset,$iEncStart-$iOffset);
  932. $aRet[] = "=?$default_charset?Q?$ret?= ";
  933. $cur_l = 3;
  934. $ret = '';
  935. $iOffset = $i;
  936. $iEncStart = $i;
  937. }
  938. $enc_init = true;
  939. $ret .= sprintf ("=%02X", $k);
  940. }
  941. else
  942. {
  943. if ($iEncStart !== false)
  944. {
  945. $cur_l++;
  946. if ($cur_l > $max_l)
  947. {
  948. $aRet[] = substr ($string,$iOffset,$iEncStart-$iOffset);
  949. $aRet[] = "=?$default_charset?Q?$ret?=";
  950. $iEncStart = false;
  951. $iOffset = $i;
  952. $cur_l = 0;
  953. $ret = '';
  954. }
  955. else
  956. {
  957. $ret .= $string{$i};
  958. }
  959. }
  960. }
  961. break;
  962. }
  963. }
  964. if ($enc_init)
  965. {
  966. if ($iEncStart !== false)
  967. {
  968. $aRet[] = substr ($string,$iOffset,$iEncStart-$iOffset);
  969. $aRet[] = "=?$default_charset?Q?$ret?=";
  970. }
  971. else
  972. {
  973. $aRet[] = substr ($string,$iOffset);
  974. }
  975. $string = implode ('',$aRet);
  976. }
  977. return $string;
  978. }
  979. //
  980. // generate_password
  981. // Action: Generates a random password
  982. // Call: generate_password ()
  983. //
  984. function generate_password ()
  985. {
  986. $password = substr (md5 (mt_rand ()), 0, 8);
  987. return $password;
  988. }
  989. /**
  990. * Encrypt a password, using the apparopriate hashing mechanism as defined in
  991. * config.inc.php ($CONF['encrypt']).
  992. * When wanting to compare one pw to another, it's necessary to provide the salt used - hence
  993. * the second parameter ($pw_db), which is the existing hash from the DB.
  994. *
  995. * @param string $pw
  996. * @param string $encrypted password
  997. * @return string encrypted password.
  998. */
  999. function pacrypt ($pw, $pw_db="")
  1000. {
  1001. global $CONF;
  1002. $pw = stripslashes($pw);
  1003. $password = "";
  1004. $salt = "";
  1005. if ($CONF['encrypt'] == 'md5crypt') {
  1006. $split_salt = preg_split ('/\$/', $pw_db);
  1007. if (isset ($split_salt[2])) {
  1008. $salt = $split_salt[2];
  1009. }
  1010. $password = md5crypt ($pw, $salt);
  1011. }
  1012. elseif ($CONF['encrypt'] == 'md5') {
  1013. $password = md5($pw);
  1014. }
  1015. elseif ($CONF['encrypt'] == 'system') {
  1016. if (ereg("\\$1\\$", $pw_db)) {
  1017. $split_salt = preg_split ('/\$/', $pw_db);
  1018. $salt = "\$1\$${split_salt[2]}\$";
  1019. }
  1020. else {
  1021. if (strlen($pw_db) == 0) {
  1022. $salt = substr (md5 (mt_rand ()), 0, 2);
  1023. }
  1024. else {
  1025. $salt = substr ($pw_db, 0, 2);
  1026. }
  1027. }
  1028. $password = crypt ($pw, $salt);
  1029. }
  1030. elseif ($CONF['encrypt'] == 'cleartext') {
  1031. $password = $pw;
  1032. }
  1033. // See https://sourceforge.net/tracker/?func=detail&atid=937966&aid=1793352&group_id=191583
  1034. // this is apparently useful for pam_mysql etc.
  1035. elseif ($CONF['encrypt'] == 'mysql_encrypt')
  1036. {
  1037. if ($pw_db!="") {
  1038. $salt=substr($pw_db,0,2);
  1039. $res=db_query("SELECT ENCRYPT('".$pw."','".$salt."');");
  1040. } else {
  1041. $res=db_query("SELECT ENCRYPT('".$pw."');");
  1042. }
  1043. $l = db_row($res["result"]);
  1044. $password = $l[0];
  1045. }
  1046. elseif ($CONF['encrypt'] == 'authlib') {
  1047. $flavor = $CONF['authlib_default_flavor'];
  1048. $salt = substr(create_salt(), 0, 2); # courier-authlib supports only two-character salts
  1049. if(preg_match('/^{.*}/', $pw_db)) {
  1050. // we have a flavor in the db -> use it instead of default flavor
  1051. $result = split('{|}', $pw_db, 3);
  1052. $flavor = $result[1];
  1053. $salt = substr($result[2], 0, 2);
  1054. }
  1055. if(stripos($flavor, 'md5raw') === 0) {
  1056. $password = '{' . $flavor . '}' . md5($pw);
  1057. } elseif(stripos($flavor, 'md5') === 0) {
  1058. $password = '{' . $flavor . '}' . base64_encode(md5($pw, TRUE));
  1059. } elseif(stripos($flavor, 'crypt') === 0) {
  1060. $password = '{' . $flavor . '}' . crypt($pw, $salt);
  1061. } else {
  1062. die("authlib_default_flavor '" . $flavor . "' unknown. Valid flavors are 'md5raw', 'md5' and 'crypt'");
  1063. }
  1064. }
  1065. elseif (preg_match("/^dovecot:/", $CONF['encrypt'])) {
  1066. $split_method = preg_split ('/:/', $CONF['encrypt']);
  1067. $method = strtoupper($split_method[1]);
  1068. if (! preg_match("/^[A-Z0-9-]+$/", $method)) { die("invalid dovecot encryption method"); } # TODO: check against a fixed list?
  1069. $dovecotpw = "dovecotpw";
  1070. if (!empty($CONF['dovecotpw'])) $dovecotpw = $CONF['dovecotpw'];
  1071. // prevent showing plain password in process table
  1072. $prefix = "postfixadmin-";
  1073. $tmpfile = tempnam('/tmp', $prefix);
  1074. $pipe = popen("'$dovecotpw' -s '$method' > '$tmpfile'", 'w'); # TODO: replace tempfile usage with proc_open call
  1075. if (!$pipe) {
  1076. unlink($tmpfile);
  1077. } else {
  1078. // use dovecot's stdin, it uses getpass() twice
  1079. fwrite($pipe, $pw . "\n", 1+strlen($pw)); usleep(1000);
  1080. fwrite($pipe, $pw . "\n", 1+strlen($pw));
  1081. pclose($pipe);
  1082. $password = file_get_contents($tmpfile);
  1083. if ( !preg_match('/^\{' . $method . '\}/', $password)) { die("can't encrypt password with dovecotpw"); }
  1084. $password = trim(str_replace('{' . $method . '}', '', $password));
  1085. unlink($tmpfile);
  1086. }
  1087. }
  1088. else {
  1089. die ('unknown/invalid $CONF["encrypt"] setting: ' . $CONF['encrypt']);
  1090. }
  1091. $password = escape_string ($password);
  1092. return $password;
  1093. }
  1094. //
  1095. // md5crypt
  1096. // Action: Creates MD5 encrypted password
  1097. // Call: md5crypt (string cleartextpassword)
  1098. //
  1099. function md5crypt ($pw, $salt="", $magic="")
  1100. {
  1101. $MAGIC = "$1$";
  1102. if ($magic == "") $magic = $MAGIC;
  1103. if ($salt == "") $salt = create_salt ();
  1104. $slist = explode ("$", $salt);
  1105. if ($slist[0] == "1") $salt = $slist[1];
  1106. $salt = substr ($salt, 0, 8);
  1107. $ctx = $pw . $magic . $salt;
  1108. $final = hex2bin (md5 ($pw . $salt . $pw));
  1109. for ($i=strlen ($pw); $i>0; $i-=16)
  1110. {
  1111. if ($i > 16)
  1112. {
  1113. $ctx .= substr ($final,0,16);
  1114. }
  1115. else
  1116. {
  1117. $ctx .= substr ($final,0,$i);
  1118. }
  1119. }
  1120. $i = strlen ($pw);
  1121. while ($i > 0)
  1122. {
  1123. if ($i & 1) $ctx .= chr (0);
  1124. else $ctx .= $pw[0];
  1125. $i = $i >> 1;
  1126. }
  1127. $final = hex2bin (md5 ($ctx));
  1128. for ($i=0;$i<1000;$i++)
  1129. {
  1130. $ctx1 = "";
  1131. if ($i & 1)
  1132. {
  1133. $ctx1 .= $pw;
  1134. }
  1135. else
  1136. {
  1137. $ctx1 .= substr ($final,0,16);
  1138. }
  1139. if ($i % 3) $ctx1 .= $salt;
  1140. if ($i % 7) $ctx1 .= $pw;
  1141. if ($i & 1)
  1142. {
  1143. $ctx1 .= substr ($final,0,16);
  1144. }
  1145. else
  1146. {
  1147. $ctx1 .= $pw;
  1148. }
  1149. $final = hex2bin (md5 ($ctx1));
  1150. }
  1151. $passwd = "";
  1152. $passwd .= to64 (((ord ($final[0]) << 16) | (ord ($final[6]) << 8) | (ord ($final[12]))), 4);
  1153. $passwd .= to64 (((ord ($final[1]) << 16) | (ord ($final[7]) << 8) | (ord ($final[13]))), 4);
  1154. $passwd .= to64 (((ord ($final[2]) << 16) | (ord ($final[8]) << 8) | (ord ($final[14]))), 4);
  1155. $passwd .= to64 (((ord ($final[3]) << 16) | (ord ($final[9]) << 8) | (ord ($final[15]))), 4);
  1156. $passwd .= to64 (((ord ($final[4]) << 16) | (ord ($final[10]) << 8) | (ord ($final[5]))), 4);
  1157. $passwd .= to64 (ord ($final[11]), 2);
  1158. return "$magic$salt\$$passwd";
  1159. }
  1160. function create_salt ()
  1161. {
  1162. srand ((double) microtime ()*1000000);
  1163. $salt = substr (md5 (rand (0,9999999)), 0, 8);
  1164. return $salt;
  1165. }
  1166. function hex2bin ($str)
  1167. {
  1168. $len = strlen ($str);
  1169. $nstr = "";
  1170. for ($i=0;$i<$len;$i+=2)
  1171. {
  1172. $num = sscanf (substr ($str,$i,2), "%x");
  1173. $nstr.=chr ($num[0]);
  1174. }
  1175. return $nstr;
  1176. }
  1177. function to64 ($v, $n)
  1178. {
  1179. $ITOA64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
  1180. $ret = "";
  1181. while (($n - 1) >= 0)
  1182. {
  1183. $n--;
  1184. $ret .= $ITOA64[$v & 0x3f];
  1185. $v = $v >> 6;
  1186. }
  1187. return $ret;
  1188. }
  1189. //
  1190. // smtp_mail
  1191. // Action: Sends email to new account.
  1192. // Call: smtp_mail (string To, string From, string Data)
  1193. // TODO: Replace this with something decent like PEAR::Mail or Zend_Mail.
  1194. function smtp_mail ($to, $from, $data)
  1195. {
  1196. global $CONF;
  1197. $smtpd_server = $CONF['smtp_server'];
  1198. $smtpd_port = $CONF['smtp_port'];
  1199. $smtp_server = $_SERVER["SERVER_NAME"];
  1200. $errno = "0";
  1201. $errstr = "0";
  1202. $timeout = "30";
  1203. $fh = @fsockopen ($smtpd_server, $smtpd_port, $errno, $errstr, $timeout);
  1204. if (!$fh)
  1205. {
  1206. return false;
  1207. }
  1208. else
  1209. {
  1210. $res = smtp_get_response($fh);
  1211. fputs ($fh, "EHLO $smtp_server\r\n");
  1212. $res = smtp_get_response($fh);
  1213. fputs ($fh, "MAIL FROM:<$from>\r\n");
  1214. $res = smtp_get_response($fh);
  1215. fputs ($fh, "RCPT TO:<$to>\r\n");
  1216. $res = smtp_get_response($fh);
  1217. fputs ($fh, "DATA\r\n");
  1218. $res = smtp_get_response($fh);
  1219. fputs ($fh, "$data\r\n.\r\n");
  1220. $res = smtp_get_response($fh);
  1221. fputs ($fh, "QUIT\r\n");
  1222. $res = smtp_get_response($fh);
  1223. fclose ($fh);
  1224. }
  1225. return true;
  1226. }
  1227. //
  1228. // smtp_get_response
  1229. // Action: Get response from mail server
  1230. // Call: smtp_get_response (string FileHandle)
  1231. //
  1232. function smtp_get_response ($fh)
  1233. {
  1234. $res ='';
  1235. do
  1236. {
  1237. $line = fgets($fh, 256);
  1238. $res .= $line;
  1239. }
  1240. while (preg_match("/^\d\d\d\-/", $line));
  1241. return $res;
  1242. }
  1243. $DEBUG_TEXT = "\n
  1244. <p />\n
  1245. Please check the documentation and website for more information.\n
  1246. <p />\n
  1247. <a href=\"http://postfixadmin.sf.net/\">Postfix Admin</a><br />\n
  1248. <a href='https://sourceforge.net/forum/forum.php?forum_id=676076'>Forums</a>
  1249. ";
  1250. /**
  1251. * db_connect
  1252. * Action: Makes a connection to the database if it doesn't exist
  1253. * Call: db_connect ()
  1254. * Optional parameter: $ignore_errors = TRUE, used by setup.php
  1255. *
  1256. * Return value:
  1257. * a) without $ignore_errors or $ignore_errors == 0
  1258. * - $link - the database connection -OR-
  1259. * - call die() in case of connection problems
  1260. * b) with $ignore_errors == TRUE
  1261. * array($link, $error_text);
  1262. */
  1263. function db_connect ($ignore_errors = 0)
  1264. {
  1265. global $CONF;
  1266. global $DEBUG_TEXT;
  1267. if ($ignore_errors != 0) $DEBUG_TEXT = '';
  1268. $error_text = '';
  1269. $link = 0;
  1270. if ($CONF['database_type'] == "mysql")
  1271. {
  1272. if (function_exists ("mysql_connect"))
  1273. {
  1274. $link = @mysql_connect ($CONF['database_host'], $CONF['database_user'], $CONF['database_password']) or $error_text .= ("<p />DEBUG INFORMATION:<br />Connect: " . mysql_error () . "$DEBUG_TEXT");
  1275. if ($link) {
  1276. @mysql_query("SET CHARACTER SET utf8",$link);
  1277. @mysql_query("SET COLLATION_CONNECTION='utf8_general_ci'",$link);
  1278. $succes = @mysql_select_db ($CONF['database_name'], $link) or $error_text .= ("<p />DEBUG INFORMATION:<br />MySQL Select Database: " . mysql_error () . "$DEBUG_TEXT");
  1279. }
  1280. }
  1281. else
  1282. {
  1283. $error_text .= "<p />DEBUG INFORMATION:<br />MySQL 3.x / 4.0 functions not available!<br />database_type = 'mysql' in config.inc.php, are you using a different database? $DEBUG_TEXT";
  1284. }
  1285. }
  1286. elseif ($CONF['database_type'] == "mysqli")
  1287. {
  1288. if (function_exists ("mysqli_connect"))
  1289. {
  1290. $link = @mysqli_connect ($CONF['database_host'], $CONF['database_user'], $CONF['database_password']) or $error_text .= ("<p />DEBUG INFORMATION:<br />Connect: " . mysqli_connect_error () . "$DEBUG_TEXT");
  1291. if ($link) {
  1292. @mysqli_query($link,"SET CHARACTER SET utf8");
  1293. @mysqli_query($link,"SET COLLATION_CONNECTION='utf8_general_ci'");
  1294. $success = @mysqli_select_db ($link, $CONF['database_name']) or $error_text .= ("<p />DEBUG INFORMATION:<br />MySQLi Select Database: " . mysqli_error ($link) . "$DEBUG_TEXT");
  1295. }
  1296. }
  1297. else
  1298. {
  1299. $error_text .= "<p />DEBUG INFORMATION:<br />MySQL 4.1 functions not available!<br />database_type = 'mysqli' in config.inc.php, are you using a different database? $DEBUG_TEXT";
  1300. }
  1301. }
  1302. elseif ($CONF['database_type'] == "pgsql")
  1303. {
  1304. if (function_exists ("pg_pconnect"))
  1305. {
  1306. $connect_string = "host=" . $CONF['database_host'] . " dbname=" . $CONF['database_name'] . " user=" . $CONF['database_user'] . " password=" . $CONF['database_password'];
  1307. $link = @pg_pconnect ($connect_string) or $error_text .= ("<p />DEBUG INFORMATION:<br />Connect: failed to connect to database. $DEBUG_TEXT");
  1308. if ($link) pg_set_client_encoding($link, 'UNICODE');
  1309. }
  1310. else
  1311. {
  1312. $error_text .= "<p />DEBUG INFORMATION:<br />PostgreSQL functions not available!<br />database_type = 'pgsql' in config.inc.php, are you using a different database? $DEBUG_TEXT";
  1313. }
  1314. }
  1315. else
  1316. {
  1317. $error_text = "<p />DEBUG INFORMATION:<br />Invalid \$CONF['database_type']! Please fix your config.inc.php! $DEBUG_TEXT";
  1318. }
  1319. if ($ignore_errors)
  1320. {
  1321. return array($link, $error_text);
  1322. }
  1323. elseif ($error_text != "")
  1324. {
  1325. print $error_text;
  1326. die();
  1327. }
  1328. elseif ($link)
  1329. {
  1330. return $link;
  1331. }
  1332. else
  1333. {
  1334. print "DEBUG INFORMATION:<br />\n";
  1335. print "Connect: Unable to connect to database<br />\n";
  1336. print "<br />\n";
  1337. print "Make sure that you have set the correct database type in the config.inc.php file<br />\n";
  1338. print $DEBUG_TEXT;
  1339. die();
  1340. }
  1341. }
  1342. /**
  1343. * Returns the appropriate boolean value for the database.
  1344. * Currently only PostgreSQL and MySQL are supported.
  1345. * @param boolean $bool (REQUIRED)
  1346. * @return String or int as appropriate.
  1347. */
  1348. function db_get_boolean($bool) {
  1349. if(!is_bool($bool)) {
  1350. die("Invalid usage of 'db_get_boolean($bool)'");
  1351. }
  1352. global $CONF;
  1353. if($CONF['database_type']=='pgsql') {
  1354. // return either true or false (unquoted strings)
  1355. if($bool) {
  1356. return 'true';
  1357. }
  1358. return 'false';
  1359. }
  1360. elseif($CONF['database_type'] == 'mysql' || $CONF['database_type'] == 'mysqli') {
  1361. if($bool) {
  1362. return 1;
  1363. }
  1364. return 0;
  1365. }
  1366. }
  1367. //
  1368. // db_query
  1369. // Action: Sends a query to the database and returns query result and number of rows
  1370. // Call: db_query (string query)
  1371. // Optional parameter: $ignore_errors = TRUE, used by upgrade.php
  1372. //
  1373. function db_query ($query, $ignore_errors = 0)
  1374. {
  1375. global $CONF;
  1376. global $DEBUG_TEXT;
  1377. $result = "";
  1378. $number_rows = "";
  1379. static $link;
  1380. $error_text = "";
  1381. if ($ignore_errors) $DEBUG_TEXT = "";
  1382. if (!is_resource($link)) $link = db_connect ();
  1383. if ($CONF['database_type'] == "mysql") $result = @mysql_query ($query, $link)
  1384. or $error_text = "<p />DEBUG INFORMATION:<br />Invalid query: " . mysql_error($link) . "$DEBUG_TEXT";
  1385. if ($CONF['database_type'] == "mysqli") $result = @mysqli_query ($link, $query)
  1386. or $error_text = "<p />DEBUG INFORMATION:<br />Invalid query: " . mysqli_error($link) . "$DEBUG_TEXT";
  1387. if ($CONF['database_type'] == "pgsql")
  1388. {
  1389. $result = @pg_query ($link, $query)
  1390. or $error_text = "<p />DEBUG INFORMATION:<br />Invalid query: " . pg_last_error() . "$DEBUG_TEXT";
  1391. }
  1392. if ($error_text != "" && $ignore_errors == 0) die($error_text);
  1393. if ($error_text == "") {
  1394. if (preg_match("/^SELECT/i", $query))
  1395. {
  1396. // if $query was a SELECT statement check the number of rows with [database_type]_num_rows ().
  1397. if ($CONF['database_type'] == "mysql") $number_rows = mysql_num_rows ($result);
  1398. if ($CONF['database_type'] == "mysqli") $number_rows = mysqli_num_rows ($result);
  1399. if ($CONF['database_type'] == "pgsql") $number_rows = pg_num_rows ($result);
  1400. }
  1401. else
  1402. {
  1403. // if $query was something else, UPDATE, DELETE or INSERT check the number of rows with
  1404. // [database_type]_affected_rows ().
  1405. if ($CONF['database_type'] == "mysql") $number_rows = mysql_affected_rows ($link);
  1406. if ($CONF['database_type'] == "mysqli") $number_rows = mysqli_affected_rows ($link);
  1407. if ($CONF['database_type'] == "pgsql") $number_rows = pg_affected_rows ($result);
  1408. }
  1409. }
  1410. $return = array (
  1411. "result" => $result,
  1412. "rows" => $number_rows,
  1413. "error" => $error_text
  1414. );
  1415. return $return;
  1416. }
  1417. // db_row
  1418. // Action: Returns a row from a table
  1419. // Call: db_row (int result)
  1420. //
  1421. function db_row ($result)
  1422. {
  1423. global $CONF;
  1424. $row = "";
  1425. if ($CONF['database_type'] == "mysql") $row = mysql_fetch_row ($result);
  1426. if ($CONF['database_type'] == "mysqli") $row = mysqli_fetch_row ($result);
  1427. if ($CONF['database_type'] == "pgsql") $row = pg_fetch_row ($result);
  1428. return $row;
  1429. }
  1430. // db_array
  1431. // Action: Returns a row from a table
  1432. // Call: db_array (int result)
  1433. //
  1434. function db_array ($result)
  1435. {
  1436. global $CONF;
  1437. $row = "";
  1438. if ($CONF['database_type'] == "mysql") $row = mysql_fetch_array ($result);
  1439. if ($CONF['database_type'] == "mysqli") $row = mysqli_fetch_array ($result);
  1440. if ($CONF['database_type'] == "pgsql") $row = pg_fetch_array ($result);
  1441. return $row;
  1442. }
  1443. // db_assoc
  1444. // Action: Returns a row from a table
  1445. // Call: db_assoc(int result)
  1446. //
  1447. function db_assoc ($result)
  1448. {
  1449. global $CONF;
  1450. $row = "";
  1451. if ($CONF['database_type'] == "mysql") $row = mysql_fetch_assoc ($result);
  1452. if ($CONF['database_type'] == "mysqli") $row = mysqli_fetch_assoc ($result);
  1453. if ($CONF['database_type'] == "pgsql") $row = pg_fetch_assoc ($result);
  1454. return $row;
  1455. }
  1456. //
  1457. // db_delete
  1458. // Action: Deletes a row from a specified table
  1459. // Call: db_delete (string table, string where, string delete)
  1460. //
  1461. function db_delete ($table,$where,$delete)
  1462. {
  1463. $query = "DELETE FROM $table WHERE " . escape_string($where) . "='" . escape_string($delete) . "'";
  1464. $result = db_query ($query);
  1465. if ($result['rows'] >= 1)
  1466. {
  1467. return $result['rows'];
  1468. }
  1469. else
  1470. {
  1471. return true;
  1472. }
  1473. }
  1474. /**
  1475. * db_insert
  1476. * Action: Inserts a row from a specified table
  1477. * Call: db_insert (string table, array values)
  1478. * @param String $table - table name
  1479. * @param array - key/value map of data to insert into the table.
  1480. * @param array (optional) - array of fields to set to now()
  1481. * @return int - number of inserted rows
  1482. */
  1483. function db_insert ($table, $values, $timestamp = array())
  1484. {
  1485. $table = table_by_key ($table);
  1486. foreach(array_keys($values) as $key) {
  1487. $values[$key] = "'" . escape_string($values[$key]) . "'";
  1488. }
  1489. foreach($timestamp as $key) {
  1490. $values[$key] = "now()";
  1491. }
  1492. $sql_values = "(" . implode(",",escape_string(array_keys($values))).") VALUES (".implode(",",$values).")";
  1493. $result = db_query ("INSERT INTO $table $sql_values");
  1494. return $result['rows'];
  1495. }
  1496. /**
  1497. * db_update
  1498. * Action: Updates a specified table
  1499. * Call: db_update (string table, array values, string where)
  1500. * @param String $table - table name
  1501. * @param String - WHERE condition
  1502. * @param array - key/value map of data to insert into the table.
  1503. * @param array (optional) - array of fields to set to now()
  1504. * @return int - number of updated rows
  1505. */
  1506. function db_update ($table, $where, $values, $timestamp = array())
  1507. {
  1508. $table = table_by_key ($table);
  1509. foreach(array_keys($values) as $key) {
  1510. $sql_values[$key] = escape_string($key) . "='" . escape_string($values[$key]) . "'";
  1511. }
  1512. foreach($timestamp as $key) {
  1513. $sql_values[$key] = escape_string($key) . "=now()";
  1514. }
  1515. $sql="UPDATE $table SET ".implode(",",$sql_values)." WHERE $where";
  1516. $result = db_query ($sql);
  1517. return $result['rows'];
  1518. }
  1519. /**
  1520. * db_log
  1521. * Action: Logs actions from admin
  1522. * Call: db_log (string username, string domain, string action, string data)
  1523. * Possible actions are:
  1524. * 'create_alias'
  1525. * 'create_alias_domain'
  1526. * 'create_mailbox'
  1527. * 'delete_alias'
  1528. * 'delete_alias_domain'
  1529. * 'delete_mailbox'
  1530. * 'edit_alias'
  1531. * 'edit_alias_state'
  1532. * 'edit_alias_domain_state'
  1533. * 'edit_mailbox'
  1534. * 'edit_mailbox_state'
  1535. * 'edit_password'
  1536. */
  1537. function db_log ($username,$domain,$action,$data)
  1538. {
  1539. global $CONF;
  1540. global $table_log;
  1541. $REMOTE_ADDR = $_SERVER['REMOTE_ADDR'];
  1542. $action_list = array('create_alias', 'create_alias_domain', 'delete_alias', 'delete_alias_domain', 'edit_alias', 'create_mailbox', 'delete_mailbox', 'edit_mailbox', 'edit_alias_state', 'edit_alias_domain_state', 'edit_mailbox_state', 'edit_password');
  1543. if(!in_array($action, $action_list)) {
  1544. die("Invalid log action : $action"); // could do with something better?
  1545. }
  1546. if ($CONF['logging'] == 'YES')
  1547. {
  1548. $result = db_query ("INSERT INTO $table_log (timestamp,username,domain,action,data) VALUES (NOW(),'$username ($REMOTE_ADDR)','$domain','$action','$data')");
  1549. if ($result['rows'] != 1)
  1550. {
  1551. return false;
  1552. }
  1553. else
  1554. {
  1555. return true;
  1556. }
  1557. }
  1558. }
  1559. //
  1560. // table_by_key
  1561. // Action: Return table name for given key
  1562. // Call: table_by_key (string table_key)
  1563. //
  1564. function table_by_key ($table_key)
  1565. {
  1566. global $CONF;
  1567. $table = $CONF['database_prefix'].$CONF['database_tables'][$table_key];
  1568. if (empty($table)) $table = $table_key;
  1569. return $table;
  1570. }
  1571. /*
  1572. Called after a mailbox has been created in the DBMS.
  1573. Returns: boolean.
  1574. */
  1575. function mailbox_postcreation($username,$domain,$maildir,$quota)
  1576. {
  1577. if (empty($username) || empty($domain) || empty($maildir))
  1578. {
  1579. trigger_error('In '.__FUNCTION__.': empty username, domain and/or maildir parameter',E_USER_ERROR);
  1580. return FALSE;
  1581. }
  1582. global $CONF;
  1583. $confpar='mailbox_postcreation_script';
  1584. if (!isset($CONF[$confpar]) || empty($CONF[$confpar])) return TRUE;
  1585. $cmdarg1=escapeshellarg($username);
  1586. $cmdarg2=escapeshellarg($domain);
  1587. $cmdarg3=escapeshellarg($maildir);
  1588. if ($quota <= 0) $quota = 0;
  1589. $cmdarg4=escapeshellarg($quota);
  1590. $command=$CONF[$confpar]." $cmdarg1 $cmdarg2 $cmdarg3 $cmdarg4";
  1591. $retval=0;
  1592. $output=array();
  1593. $firstline='';
  1594. $firstline=exec($command,$output,$retval);
  1595. if (0!=$retval)
  1596. {
  1597. error_log("Running $command yielded return value=$retval, first line of output=$firstline");
  1598. print '<p>WARNING: Problems running mailbox postcreation script!</p>';
  1599. return FALSE;
  1600. }
  1601. return TRUE;
  1602. }
  1603. /*
  1604. Called after a mailbox has been altered in the DBMS.
  1605. Returns: boolean.
  1606. */
  1607. function mailbox_postedit($username,$domain,$maildir,$quota)
  1608. {
  1609. if (empty($username) || empty($domain) || empty($maildir))
  1610. {
  1611. trigger_error('In '.__FUNCTION__.': empty username, domain and/or maildir parameter',E_USER_ERROR);
  1612. return FALSE;
  1613. }
  1614. global $CONF;
  1615. $confpar='mailbox_postedit_script';
  1616. if (!isset($CONF[$confpar]) || empty($CONF[$confpar])) return TRUE;
  1617. $cmdarg1=escapeshellarg($username);
  1618. $cmdarg2=escapeshellarg($domain);
  1619. $cmdarg3=escapeshellarg($maildir);
  1620. if ($quota <= 0) $quota = 0;
  1621. $cmdarg4=escapeshellarg($quota);
  1622. $command=$CONF[$confpar]." $cmdarg1 $cmdarg2 $cmdarg3 $cmdarg4";
  1623. $retval=0;
  1624. $output=array();
  1625. $firstline='';
  1626. $firstline=exec($command,$output,$retval);
  1627. if (0!=$retval)
  1628. {
  1629. error_log("Running $command yielded return value=$retval, first line of output=$firstline");
  1630. print '<p>WARNING: Problems running mailbox postedit script!</p>';
  1631. return FALSE;
  1632. }
  1633. return TRUE;
  1634. }
  1635. /*
  1636. Called after a mailbox has been deleted in the DBMS.
  1637. Returns: boolean.
  1638. */
  1639. function mailbox_postdeletion($username,$domain)
  1640. {
  1641. global $CONF;
  1642. $confpar='mailbox_postdeletion_script';
  1643. if (!isset($CONF[$confpar]) || empty($CONF[$confpar]))
  1644. {
  1645. return true;
  1646. }
  1647. if (empty($username) || empty($domain))
  1648. {
  1649. print '<p>Warning: empty username and/or domain parameter.</p>';
  1650. return false;
  1651. }
  1652. $cmdarg1=escapeshellarg($username);
  1653. $cmdarg2=escapeshellarg($domain);
  1654. $command=$CONF[$confpar]." $cmdarg1 $cmdarg2";
  1655. $retval=0;
  1656. $output=array();
  1657. $firstline='';
  1658. $firstline=exec($command,$output,$retval);
  1659. if (0!=$retval)
  1660. {
  1661. error_log("Running $command yielded return value=$retval, first line of output=$firstline");
  1662. print '<p>WARNING: Problems running mailbox postdeletion script!</p>';
  1663. return FALSE;
  1664. }
  1665. return TRUE;
  1666. }
  1667. /*
  1668. Called after a domain has been added in the DBMS.
  1669. Returns: boolean.
  1670. */
  1671. function domain_postcreation($domain)
  1672. {
  1673. global $CONF;
  1674. $confpar='domain_postcreation_script';
  1675. if (!isset($CONF[$confpar]) || empty($CONF[$confpar]))
  1676. {
  1677. return true;
  1678. }
  1679. if (empty($domain))
  1680. {
  1681. print '<p>Warning: empty domain parameter.</p>';
  1682. return false;
  1683. }
  1684. $cmdarg1=escapeshellarg($domain);
  1685. $command=$CONF[$confpar]." $cmdarg1";
  1686. $retval=0;
  1687. $output=array();
  1688. $firstline='';
  1689. $firstline=exec($command,$output,$retval);
  1690. if (0!=$retval)
  1691. {
  1692. error_log("Running $command yielded return value=$retval, first line of output=$firstline");
  1693. print '<p>WARNING: Problems running domain postcreation script!</p>';
  1694. return FALSE;
  1695. }
  1696. return TRUE;
  1697. }
  1698. /*
  1699. Called after a domain has been deleted in the DBMS.
  1700. Returns: boolean.
  1701. */
  1702. function domain_postdeletion($domain)
  1703. {
  1704. global $CONF;
  1705. $confpar='domain_postdeletion_script';
  1706. if (!isset($CONF[$confpar]) || empty($CONF[$confpar]))
  1707. {
  1708. return true;
  1709. }
  1710. if (empty($domain))
  1711. {
  1712. print '<p>Warning: empty domain parameter.</p>';
  1713. return false;
  1714. }
  1715. $cmdarg1=escapeshellarg($domain);
  1716. $command=$CONF[$confpar]." $cmdarg1";
  1717. $retval=0;
  1718. $output=array();
  1719. $firstline='';
  1720. $firstline=exec($command,$output,$retval);
  1721. if (0!=$retval)
  1722. {
  1723. error_log("Running $command yielded return value=$retval, first line of output=$firstline");
  1724. print '<p>WARNING: Problems running domain postdeletion script!</p>';
  1725. return FALSE;
  1726. }
  1727. return TRUE;
  1728. }
  1729. /*
  1730. Called after an alias_domain has been deleted in the DBMS.
  1731. Returns: boolean.
  1732. */
  1733. function alias_domain_postdeletion($alias_domain)
  1734. {
  1735. global $CONF;
  1736. $confpar='alias_domain_postdeletion_script';
  1737. if (!isset($CONF[$confpar]) || empty($CONF[$confpar]))
  1738. {
  1739. return true;
  1740. }
  1741. if (empty($alias_domain))
  1742. {
  1743. print '<p>Warning: empty alias_domain parameter.</p>';
  1744. return false;
  1745. }
  1746. $cmdarg1=escapeshellarg($alias_domain);
  1747. $command=$CONF[$confpar]." $cmdarg1";
  1748. $retval=0;
  1749. $output=array();
  1750. $firstline='';
  1751. $firstline=exec($command,$output,$retval);
  1752. if (0!=$retval)
  1753. {
  1754. error_log("Running $command yielded return value=$retval, first line of output=$firstline");
  1755. print '<p>WARNING: Problems running alias_domain postdeletion script!</p>';
  1756. return FALSE;
  1757. }
  1758. return TRUE;
  1759. }
  1760. /*
  1761. Called by mailbox_postcreation() after a mailbox has been
  1762. created. Immediately returns, unless configuration indicates
  1763. that one or more sub-folders should be created.
  1764. Triggers E_USER_ERROR if configuration error is detected.
  1765. If IMAP login fails, the problem is logged to the system log
  1766. (such as /var/log/httpd/error_log), and the function returns
  1767. FALSE.
  1768. Returns FALSE on all other errors, or TRUE if everything
  1769. succeeds.
  1770. Doesn't clean up, if only some of the folders could be
  1771. created.
  1772. */
  1773. function create_mailbox_subfolders($login,$cleartext_password)
  1774. {
  1775. global $CONF;
  1776. if (empty($login))
  1777. {
  1778. trigger_error('In '.__FUNCTION__.': empty $login',E_USER_ERROR);
  1779. return FALSE;
  1780. }
  1781. if (!isset($CONF['create_mailbox_subdirs']) || empty($CONF['create_mailbox_subdirs'])) return TRUE;
  1782. if (!is_array($CONF['create_mailbox_subdirs']))
  1783. {
  1784. trigger_error('create_mailbox_subdirs must be an array',E_USER_ERROR);
  1785. return FALSE;
  1786. }
  1787. if (!isset($CONF['create_mailbox_subdirs_host']) || empty($CONF['create_mailbox_subdirs_host']))
  1788. {
  1789. trigger_error('An IMAP/POP server host ($CONF["create_mailbox_subdirs_host"]) must be configured, if sub-folders are to be created',E_USER_ERROR);
  1790. return FALSE;
  1791. }
  1792. $s_host=$CONF['create_mailbox_subdirs_host'];
  1793. $s_prefix=$CONF['create_mailbox_subdirs_prefix'];
  1794. $s_options='';
  1795. $s_port='';
  1796. if (
  1797. isset($CONF['create_mailbox_subdirs_hostoptions'])
  1798. && !empty($CONF['create_mailbox_subdirs_hostoptions'])
  1799. ) {
  1800. if (!is_array($CONF['create_mailbox_subdirs_hostoptions']))
  1801. {
  1802. trigger_error('The $CONF["create_mailbox_subdirs_hostoptions"] parameter must be an array',E_USER_ERROR);
  1803. return FALSE;
  1804. }
  1805. foreach ($CONF['create_mailbox_subdirs_hostoptions'] as $o)
  1806. {
  1807. $s_options.='/'.$o;
  1808. }
  1809. }
  1810. if (isset($CONF['create_mailbox_subdirs_hostport']) && !empty($CONF['create_mailbox_subdirs_hostport']))
  1811. {
  1812. $s_port=$CONF['create_mailbox_subdirs_hostport'];
  1813. if (intval($s_port)!=$s_port)
  1814. {
  1815. trigger_error('The $CONF["create_mailbox_subdirs_hostport"] parameter must be an integer',E_USER_ERROR);
  1816. return FALSE;
  1817. }
  1818. $s_port=':'.$s_port;
  1819. }
  1820. $s='{'.$s_host.$s_port.$s_options.'}';
  1821. sleep(1); # give the mail triggering the mailbox creation a chance to do its job
  1822. $i=@imap_open($s,$login,$cleartext_password);
  1823. if (FALSE==$i)
  1824. {
  1825. error_log('Could not log into IMAP/POP server: '.imap_last_error());
  1826. return FALSE;
  1827. }
  1828. foreach($CONF['create_mailbox_subdirs'] as $f)
  1829. {
  1830. $f='{'.$s_host.'}'.$s_prefix.$f;
  1831. $res=imap_createmailbox($i,$f);
  1832. if (!$res) {
  1833. @imap_close($i);
  1834. return FALSE;
  1835. }
  1836. @imap_subscribe($i,$f);
  1837. }
  1838. @imap_close($i);
  1839. return TRUE;
  1840. }
  1841. //
  1842. // gen_show_status
  1843. // Action: Return a string of colored &nbsp;'s that indicate
  1844. // the if an alias goto has an error or is sent to
  1845. // addresses list in show_custom_domains
  1846. // Call: gen_show_status (string alias_address)
  1847. //
  1848. function gen_show_status ($show_alias)
  1849. {
  1850. global $CONF, $table_alias;
  1851. $stat_string = "";
  1852. $stat_goto = "";
  1853. $stat_result = db_query ("SELECT goto FROM $table_alias WHERE address='$show_alias'");
  1854. if ($stat_result['rows'] > 0)
  1855. {
  1856. $row = db_row ($stat_result['result']);
  1857. $stat_goto = $row[0];
  1858. }
  1859. // UNDELIVERABLE CHECK
  1860. if ( $CONF['show_undeliverable'] == 'YES' )
  1861. {
  1862. $gotos=array();
  1863. $gotos=explode(',',$stat_goto);
  1864. $undel_string="";
  1865. //make sure this alias goes somewhere known
  1866. $stat_ok = 1;
  1867. while ( ($g=array_pop($gotos)) && $stat_ok )
  1868. {
  1869. $stat_catchall = substr($g,strpos($g,"@"));
  1870. $stat_delimiter = "";
  1871. if (!empty($CONF['recipient_delimiter'])) {
  1872. $delimiter = preg_quote($CONF['recipient_delimiter'], "/");
  1873. $stat_delimiter = preg_replace('/' .$delimiter. '[^' .$delimiter. ']*@/', "@", $g);
  1874. $stat_delimiter = "OR address = '$stat_delimiter'";
  1875. }
  1876. $stat_result = db_query ("SELECT address FROM $table_alias WHERE address = '$g' OR address = '$stat_catchall' $stat_delimiter");
  1877. if ($stat_result['rows'] == 0)
  1878. {
  1879. $stat_ok = 0;
  1880. }
  1881. if ( $stat_ok == 0 )
  1882. {
  1883. $stat_domain = substr($g,strpos($g,"@")+1);
  1884. $stat_vacdomain = substr($stat_domain,strpos($stat_domain,"@")+1);
  1885. if ( $stat_vacdomain == $CONF['vacation_domain'] )
  1886. {
  1887. $stat_ok = 1;
  1888. break;
  1889. }
  1890. for ($i=0; $i < sizeof($CONF['show_undeliverable_exceptions']);$i++)
  1891. {
  1892. if ( $stat_domain == $CONF['show_undeliverable_exceptions'][$i] )
  1893. {
  1894. $stat_ok = 1;
  1895. break;
  1896. }
  1897. }
  1898. }
  1899. } // while
  1900. if ( $stat_ok == 0 )
  1901. {
  1902. $stat_string .= "<span style='background-color:" . $CONF['show_undeliverable_color'] .
  1903. "'>" . $CONF['show_status_text'] . "</span>&nbsp;";
  1904. }
  1905. else
  1906. {
  1907. $stat_string .= $CONF['show_status_text'] . "&nbsp;";
  1908. }
  1909. }
  1910. else
  1911. {
  1912. $stat_string .= $CONF['show_status_text'] . "&nbsp;";
  1913. }
  1914. // POP/IMAP CHECK
  1915. if ( $CONF['show_popimap'] == 'YES' )
  1916. {
  1917. $stat_delimiter = "";
  1918. if (!empty($CONF['recipient_delimiter'])) {
  1919. $delimiter = preg_quote($CONF['recipient_delimiter'], "/");
  1920. $stat_delimiter = preg_replace('/' .$delimiter. '[^' .$delimiter. '@]*@/', "@", $stat_goto);
  1921. $stat_delimiter = ',' . $stat_delimiter;
  1922. }
  1923. //if the address passed in appears in its own goto field, its POP/IMAP
  1924. if ( preg_match ('/,' . $show_alias . ',/', ',' . $stat_goto . $stat_delimiter . ',') )
  1925. {
  1926. $stat_string .= "<span style='background-color:" . $CONF['show_popimap_color'] .
  1927. "'>" . $CONF['show_status_text'] . "</span>&nbsp;";
  1928. }
  1929. else
  1930. {
  1931. $stat_string .= $CONF['show_status_text'] . "&nbsp;";
  1932. }
  1933. }
  1934. // CUSTOM DESTINATION CHECK
  1935. if ( count($CONF['show_custom_domains']) > 0 )
  1936. {
  1937. for ($i = 0; $i < sizeof ($CONF['show_custom_domains']); $i++)
  1938. {
  1939. if (preg_match ('/^.*' . $CONF['show_custom_domains'][$i] . '.*$/', $stat_goto))
  1940. {
  1941. $stat_string .= "<span style='background-color:" . $CONF['show_custom_colors'][$i] .
  1942. "'>" . $CONF['show_status_text'] . "</span>&nbsp;";
  1943. }
  1944. else
  1945. {
  1946. $stat_string .= $CONF['show_status_text'] . "&nbsp;";
  1947. }
  1948. }
  1949. }
  1950. else
  1951. {
  1952. $stat_string .= ";&nbsp;";
  1953. }
  1954. // $stat_string .= "<span style='background-color:green'> &nbsp; </span> &nbsp;" .
  1955. // "<span style='background-color:blue'> &nbsp; </span> &nbsp;";
  1956. return $stat_string;
  1957. }
  1958. /*
  1959. Called by create-admin.php and setup.php
  1960. Returns:
  1961. array(
  1962. 'error' => 0, # 0 on success, otherwise > 0
  1963. 'tMessage' => '', # success / failure message
  1964. 'pAdminCreate_admin_username_text' => '', # help text / error message for username
  1965. 'pAdminCreate_admin_password_text' => '' # error message for username
  1966. )
  1967. */
  1968. function create_admin($fUsername, $fPassword, $fPassword2, $fDomains, $no_generate_password=0)
  1969. {
  1970. global $PALANG;
  1971. global $CONF;
  1972. $error = 0;
  1973. $tMessage = '';
  1974. $pAdminCreate_admin_username_text = '';
  1975. $pAdminCreate_admin_password_text = '';
  1976. if (!check_email ($fUsername))
  1977. {
  1978. $error = 1;
  1979. $pAdminCreate_admin_username_text = $PALANG['pAdminCreate_admin_username_text_error1'];
  1980. }
  1981. if (empty ($fUsername) or admin_exist ($fUsername))
  1982. {
  1983. $error = 1;
  1984. $pAdminCreate_admin_username_text = $PALANG['pAdminCreate_admin_username_text_error2'];
  1985. }
  1986. if (empty ($fPassword) or empty ($fPassword2) or ($fPassword != $fPassword2))
  1987. {
  1988. if (empty ($fPassword) and empty ($fPassword2) and $CONF['generate_password'] == "YES" && $no_generate_password == 0)
  1989. {
  1990. $fPassword = generate_password ();
  1991. }
  1992. else
  1993. {
  1994. $error = 1;
  1995. $pAdminCreate_admin_username_text = $PALANG['pAdminCreate_admin_username_text'];
  1996. $pAdminCreate_admin_password_text = $PALANG['pAdminCreate_admin_password_text_error'];
  1997. }
  1998. }
  1999. if ($error != 1)
  2000. {
  2001. $password = pacrypt($fPassword);
  2002. $pAdminCreate_admin_username_text = $PALANG['pAdminCreate_admin_username_text'];
  2003. $result = db_query ("INSERT INTO " . table_by_key('admin') . " (username,password,created,modified) VALUES ('$fUsername','$password',NOW(),NOW())");
  2004. if ($result['rows'] != 1)
  2005. {
  2006. $tMessage = $PALANG['pAdminCreate_admin_result_error'] . "<br />($fUsername)<br />";
  2007. }
  2008. else
  2009. {
  2010. if (!empty ($fDomains[0]))
  2011. {
  2012. for ($i = 0; $i < sizeof ($fDomains); $i++)
  2013. {
  2014. $domain = $fDomains[$i];
  2015. $result = db_query ("INSERT INTO " . table_by_key ('domain_admins') . " (username,domain,created) VALUES ('$fUsername','$domain',NOW())");
  2016. }
  2017. }
  2018. $tMessage = $PALANG['pAdminCreate_admin_result_success'] . "<br />($fUsername";
  2019. if ($CONF['generate_password'] == "YES" && $no_generate_password == 0)
  2020. {
  2021. $tMessage .= " / $fPassword)</br />";
  2022. }
  2023. else
  2024. {
  2025. if ($CONF['show_password'] == "YES" && $no_generate_password == 0)
  2026. {
  2027. $tMessage .= " / $fPassword)</br />";
  2028. }
  2029. else
  2030. {
  2031. $tMessage .= ")</br />";
  2032. }
  2033. }
  2034. }
  2035. }
  2036. # TODO: should we log creation, editing and deletion of admins?
  2037. # Note: needs special handling in viewlog, because domain is empty
  2038. # db_log ($SESSID_USERNAME, '', 'create_admin', "$fUsername");
  2039. return array(
  2040. $error,
  2041. $tMessage,
  2042. $pAdminCreate_admin_username_text,
  2043. $pAdminCreate_admin_password_text
  2044. );
  2045. }
  2046. /*
  2047. Convert $CONF['whatever'] to boolean
  2048. (obviously only useful for settings that can be YES or NO)
  2049. Returns: TRUE (on YES/yes) or FALSE (on NO/no/not set/unknown value)
  2050. */
  2051. function boolconf($setting) {
  2052. global $CONF;
  2053. if (!isset($CONF[$setting])) { # not set
  2054. # TODO: show/log error message on unknown settings?
  2055. return false;
  2056. } elseif (strtoupper($CONF[$setting]) == 'YES') { # YES
  2057. return true;
  2058. } else { # NO, unknown value
  2059. # TODO: show/log error message on unknown value?
  2060. return false;
  2061. }
  2062. }
  2063. $table_admin = table_by_key ('admin');
  2064. $table_alias = table_by_key ('alias');
  2065. $table_alias_domain = table_by_key ('alias_domain');
  2066. $table_domain = table_by_key ('domain');
  2067. $table_domain_admins = table_by_key ('domain_admins');
  2068. $table_log = table_by_key ('log');
  2069. $table_mailbox = table_by_key ('mailbox');
  2070. $table_vacation = table_by_key ('vacation');
  2071. $table_vacation_notification = table_by_key('vacation_notification');
  2072. $table_quota = table_by_key ('quota');
  2073. /* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */