SF.net SVN: postfixadmin:[831] trunk
Brought to you by:
christian_boltz,
gingerdog
From: <va...@us...> - 2010-05-23 14:17:14
|
Revision: 831 http://postfixadmin.svn.sourceforge.net/postfixadmin/?rev=831&view=rev Author: valkum Date: 2010-05-23 14:17:07 +0000 (Sun, 23 May 2010) Log Message: ----------- * Added my PostfixAdmin CLI based on PostfixAdmin 2.4 * Changed 'smpt_mail' to use php comformer hostname php_uname("n"); * Added function getRemoteAddr for db_log. If $_SERVER is not set Remote Addr should be localhost. See php-cli doc. Modified Paths: -------------- trunk/functions.inc.php trunk/languages/de.lang trunk/languages/en.lang Added Paths: ----------- trunk/scripts/ trunk/scripts/common.php trunk/scripts/inflector.php trunk/scripts/models-ext/ trunk/scripts/models-ext/AliasHandler.php trunk/scripts/models-ext/DomainHandler.php trunk/scripts/models-ext/UserHandler.php trunk/scripts/postfixadmin-cli trunk/scripts/postfixadmin-cli.php trunk/scripts/shells/ trunk/scripts/shells/alias.php trunk/scripts/shells/domain.php trunk/scripts/shells/shell.php trunk/scripts/shells/user.php Modified: trunk/functions.inc.php =================================================================== --- trunk/functions.inc.php 2010-05-18 21:12:19 UTC (rev 830) +++ trunk/functions.inc.php 2010-05-23 14:17:07 UTC (rev 831) @@ -1362,7 +1362,8 @@ global $CONF; $smtpd_server = $CONF['smtp_server']; $smtpd_port = $CONF['smtp_port']; - $smtp_server = $_SERVER["SERVER_NAME"]; + //$smtp_server = $_SERVER["SERVER_NAME"]; + $smtp_server = php_uname("n"); $errno = "0"; $errstr = "0"; $timeout = "30"; @@ -1736,12 +1737,15 @@ * Action: Logs actions from admin * Call: db_log (string username, string domain, string action, string data) * Possible actions are: + * 'create_domain' * 'create_alias' * 'create_alias_domain' * 'create_mailbox' + * 'delete_domain' * 'delete_alias' * 'delete_alias_domain' * 'delete_mailbox' + * 'edit_domain' * 'edit_alias' * 'edit_alias_state' * 'edit_alias_domain_state' @@ -1753,9 +1757,9 @@ { global $CONF; global $table_log; - $REMOTE_ADDR = $_SERVER['REMOTE_ADDR']; + $REMOTE_ADDR = getRemoteAddr(); - $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'); + $action_list = array( 'create_domain', 'create_alias', 'create_alias_domain','delete_domain', 'delete_alias', 'delete_alias_domain','edit_domain', 'edit_alias', 'create_mailbox', 'delete_mailbox', 'edit_mailbox', 'edit_alias_state', 'edit_alias_domain_state', 'edit_mailbox_state', 'edit_password'); if(!in_array($action, $action_list)) { die("Invalid log action : $action"); // could do with something better? @@ -2350,6 +2354,12 @@ } +function getRemoteAddr() { + $REMOTE_ADDR = 'localhost'; + if (isset($_SERVER['REMOTE_ADDR'])) + $REMOTE_ADDR = $_SERVER['REMOTE_ADDR']; + return $REMOTE_ADDR; +} Modified: trunk/languages/de.lang =================================================================== --- trunk/languages/de.lang 2010-05-18 21:12:19 UTC (rev 830) +++ trunk/languages/de.lang 2010-05-23 14:17:07 UTC (rev 831) @@ -194,6 +194,9 @@ $PALANG['pViewlog_action'] = 'Aktion'; $PALANG['pViewlog_data'] = 'Daten'; +$PALANG['pViewlog_action_create_domain'] = 'Domain erstellen'; +$PALANG['pViewlog_action_edit_domain'] = 'Domain bearbeiten'; +$PALANG['pViewlog_action_delete_domain'] = 'Domain löschen'; $PALANG['pViewlog_action_create_mailbox'] = 'Mailbox erstellen'; $PALANG['pViewlog_action_delete_mailbox'] = 'Mailbox löschen'; $PALANG['pViewlog_action_edit_mailbox'] = 'Mailbox bearbeiten'; Modified: trunk/languages/en.lang =================================================================== --- trunk/languages/en.lang 2010-05-18 21:12:19 UTC (rev 830) +++ trunk/languages/en.lang 2010-05-23 14:17:07 UTC (rev 831) @@ -196,6 +196,9 @@ $PALANG['pViewlog_action'] = 'Action'; $PALANG['pViewlog_data'] = 'Data'; +$PALANG['pViewlog_action_create_domain'] = 'create domain'; +$PALANG['pViewlog_action_delete_domain'] = 'delete domain'; +$PALANG['pViewlog_action_edit_domain'] = 'edit domain'; $PALANG['pViewlog_action_create_mailbox'] = 'create mailbox'; $PALANG['pViewlog_action_delete_mailbox'] = 'delete mailbox'; $PALANG['pViewlog_action_edit_mailbox'] = 'edit mailbox'; Added: trunk/scripts/common.php =================================================================== --- trunk/scripts/common.php (rev 0) +++ trunk/scripts/common.php 2010-05-23 14:17:07 UTC (rev 831) @@ -0,0 +1,389 @@ +<?php +/** + * Postfix Admin + * + * LICENSE + * This source file is subject to the GPL license that is bundled with + * this package in the file LICENSE.TXT. + * + * Further details on the project are available at : + * http://www.postfixadmin.com or http://postfixadmin.sf.net + * + * @version $Id: common.php 733 2009-10-20 19:25:20Z christian_boltz $ + * @license GNU GPL v2 or later. + * + * File: common.php + * All pages should include this file - which itself sets up the necessary + * environment and ensures other functions are loaded. + */ + + + +$incpath = PATH; +(ini_get('magic_quotes_gpc') ? ini_set('magic_quotes_runtime', '0') : '1'); +(ini_get('magic_quotes_gpc') ? ini_set('magic_quotes_sybase', '0') : '1'); + +if(ini_get('register_globals') == 'on') { + die("Please turn off register_globals; edit your php.ini"); +} +require_once("$incpath/variables.inc.php"); +/* +if(!is_file("$incpath/config.inc.php")) { + die("config.inc.php is missing!"); +} +require_once("$incpath/config.inc.php"); +*/ +if(isset($CONF['configured'])) { + if($CONF['configured'] == FALSE) { + die("Please edit config.inc.php - change \$CONF['configured'] to true after setting your database settings"); + } +} + +/* +require_once("$incpath/languages/language.php"); +require_once("$incpath/functions.inc.php"); +require_once("$incpath/languages/en.lang"); +*/ +/** + * @param string $class + * __autoload implementation, for use with spl_autoload_register(). + */ +function postfixadmin_autoload2($class) { + $PATH = CORE_INCLUDE_PATH.'/models-ext/' . $class . '.php'; + + if(is_file($PATH)) { + require_once($PATH); + return true; + } + return false; +} +spl_autoload_register('postfixadmin_autoload2'); + + + + +/** + * Convenience method for strtolower(). + * + * @param string $str String to lowercase + * @return string Lowercased string + */ + function low($str) { + return strtolower($str); + } +/** + * Convenience method for strtoupper(). + * + * @param string $str String to uppercase + * @return string Uppercased string + */ + function up($str) { + return strtoupper($str); + } +/** + * Convenience method for str_replace(). + * + * @param string $search String to be replaced + * @param string $replace String to insert + * @param string $subject String to search + * @return string Replaced string + */ + function r($search, $replace, $subject) { + return str_replace($search, $replace, $subject); + } +/** + * Print_r convenience function, which prints out <PRE> tags around + * the output of given array. Similar to debug(). + * + * @see debug() + * @param array $var Variable to print out + * @param boolean $showFrom If set to true, the method prints from where the function was called + */ + function pr($var) { + if (Configure::read() > 0) { + echo "<pre>"; + print_r($var); + echo "</pre>"; + } + } + + + + +class Config { +/** + * Determine if $__objects cache should be wrote + * + * @var boolean + * @access private + */ + var $__cache = false; +/** + * Holds and key => value array of objects type + * + * @var array + * @access private + */ + var $__objects = array(); + +/** + * Return a singleton instance of Configure. + * + * @return Configure instance + * @access public + */ + + function &getInstance() { + static $instance = array(); + if (!$instance) { + $instance[0] =& new Config(); + //$instance[0]->__loadBootstrap($boot); + } + return $instance[0]; + } +/** + * Used to write a dynamic var in the Configure instance. + * + * Usage + * Configure::write('One.key1', 'value of the Configure::One[key1]'); + * Configure::write(array('One.key1' => 'value of the Configure::One[key1]')); + * Configure::write('One', array('key1'=>'value of the Configure::One[key1]', 'key2'=>'value of the Configure::One[key2]'); + * Configure::write(array('One.key1' => 'value of the Configure::One[key1]', 'One.key2' => 'value of the Configure::One[key2]')); + * + * @param array $config Name of var to write + * @param mixed $value Value to set for var + * @return void + * @access public + */ + function write($config, $value = null) { + $_this =& Config::getInstance(); + + if (!is_array($config)) { + $config = array($config => $value); + } + + foreach ($config as $names => $value) { + $name = $_this->__configVarNames($names); + + switch (count($name)) { + case 3: + $_this->{$name[0]}[$name[1]][$name[2]] = $value; + break; + case 2: + $_this->{$name[0]}[$name[1]] = $value; + break; + case 1: + $_this->{$name[0]} = $value; + break; + } + } + + } + +/** + * Used to read Configure::$var + * + * Usage + * Configure::read('Name'); will return all values for Name + * Configure::read('Name.key'); will return only the value of Configure::Name[key] + * + * @param string $var Variable to obtain + * @return string value of Configure::$var + * @access public + */ + function read($var) { + $_this =& Config::getInstance(); + + if ($var === 'all') { + $return = array(); + foreach ($_this AS $key =>$var) { + $return[$key] = $var; + } + return $return; + } + + $name = $_this->__configVarNames($var); + + switch (count($name)) { + case 3: + if (isset($_this->{$name[0]}[$name[1]][$name[2]])) { + return $_this->{$name[0]}[$name[1]][$name[2]]; + } + break; + case 2: + if (isset($_this->{$name[0]}[$name[1]])) { + return $_this->{$name[0]}[$name[1]]; + } + break; + case 1: + if (isset($_this->{$name[0]})) { + return $_this->{$name[0]}; + } + break; + } + return null; + } + + + function getAll() { + $output = $this->config; + return $output; + } +/** + * Checks $name for dot notation to create dynamic Configure::$var as an array when needed. + * + * @param mixed $name Name to split + * @return array Name separated in items through dot notation + * @access private + */ + function __configVarNames($name) { + if (is_string($name)) { + if (strpos($name, ".")) { + return explode(".", $name); + } + return array($name); + } + return $name; + } + +} + +class Lang { +/** + * Determine if $__objects cache should be wrote + * + * @var boolean + * @access private + */ + var $__cache = false; +/** + * Holds and key => value array of objects type + * + * @var array + * @access private + */ + var $__objects = array(); + +/** + * Return a singleton instance of Configure. + * + * @return Configure instance + * @access public + */ + + function &getInstance() { + static $instance = array(); + if (!$instance) { + $instance[0] =& new Config(); + //$instance[0]->__loadBootstrap($boot); + } + return $instance[0]; + } +/** + * Used to write a dynamic var in the Configure instance. + * + * Usage + * Configure::write('One.key1', 'value of the Configure::One[key1]'); + * Configure::write(array('One.key1' => 'value of the Configure::One[key1]')); + * Configure::write('One', array('key1'=>'value of the Configure::One[key1]', 'key2'=>'value of the Configure::One[key2]'); + * Configure::write(array('One.key1' => 'value of the Configure::One[key1]', 'One.key2' => 'value of the Configure::One[key2]')); + * + * @param array $config Name of var to write + * @param mixed $value Value to set for var + * @return void + * @access public + */ + function write($config, $value = null) { + $_this =& Config::getInstance(); + + if (!is_array($config)) { + $config = array($config => $value); + } + + foreach ($config as $names => $value) { + $name = $_this->__configVarNames($names); + + switch (count($name)) { + case 3: + $_this->{$name[0]}[$name[1]][$name[2]] = $value; + break; + case 2: + $_this->{$name[0]}[$name[1]] = $value; + break; + case 1: + $_this->{$name[0]} = $value; + break; + } + } + + } + +/** + * Used to read Configure::$var + * + * Usage + * Configure::read('Name'); will return all values for Name + * Configure::read('Name.key'); will return only the value of Configure::Name[key] + * + * @param string $var Variable to obtain + * @return string value of Configure::$var + * @access public + */ + function read($var) { + $_this =& Config::getInstance(); + + if ($var === 'all') { + $return = array(); + foreach ($_this AS $key =>$var) { + $return[$key] = $var; + } + return $return; + } + + $name = $_this->__configVarNames($var); + + switch (count($name)) { + case 3: + if (isset($_this->{$name[0]}[$name[1]][$name[2]])) { + return $_this->{$name[0]}[$name[1]][$name[2]]; + } + break; + case 2: + if (isset($_this->{$name[0]}[$name[1]])) { + return $_this->{$name[0]}[$name[1]]; + } + break; + case 1: + if (isset($_this->{$name[0]})) { + return $_this->{$name[0]}; + } + break; + } + return null; + } + + + function getAll() { + $output = $this->config; + return $output; + } +/** + * Checks $name for dot notation to create dynamic Configure::$var as an array when needed. + * + * @param mixed $name Name to split + * @return array Name separated in items through dot notation + * @access private + */ + function __configVarNames($name) { + if (is_string($name)) { + if (strpos($name, ".")) { + return explode(".", $name); + } + return array($name); + } + return $name; + } + +} + +/* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */ Added: trunk/scripts/inflector.php =================================================================== --- trunk/scripts/inflector.php (rev 0) +++ trunk/scripts/inflector.php 2010-05-23 14:17:07 UTC (rev 831) @@ -0,0 +1,151 @@ +<?php +/** + * -. + * + * Used by Cake's naming conventions throughout the framework. + * + * PHP versions 4 and 5 + * + * CakePHP(tm) : Rapid Development Framework <http://www.cakephp.org/> + * Copyright 2005-2008, Cake Software Foundation, Inc. + * 1785 E. Sahara Avenue, Suite 490-204 + * Las Vegas, Nevada 89104 + * Modified for Postfixadmin by Valkum + * + * Copyright 2010 + * + * Licensed under The MIT License + * Redistributions of files must retain the above copyright notice. + * + * @filesource + * @copyright Copyright 2005-2008, Cake Software Foundation, Inc. + * @link http://postfixadmin.sourceforge.net/ Postfixadmin on Sourceforge + * @package postfixadmin + * @subpackage - + * @since - + * @version $Revision$ + * @modifiedby $LastChangedBy$ + * @lastmodified $Date$ + * @license http://www.opensource.org/licenses/mit-license.php The MIT License + */ +class Inflector { +/** + * Returns given $lower_case_and_underscored_word as a CamelCased word. + * + * @param string $lower_case_and_underscored_word Word to camelize + * @return string Camelized word. LikeThis. + * @access public + * @static + */ + function camelize($lowerCaseAndUnderscoredWord) { + $replace = str_replace(" ", "", ucwords(str_replace("_", " ", $lowerCaseAndUnderscoredWord))); + return $replace; + } +/** + * Returns an underscore-syntaxed ($like_this_dear_reader) version of the $camel_cased_word. + * + * @param string $camel_cased_word Camel-cased word to be "underscorized" + * @return string Underscore-syntaxed version of the $camel_cased_word + * @access public + * @static + */ + function underscore($camelCasedWord) { + $replace = strtolower(preg_replace('/(?<=\\w)([A-Z])/', '_\\1', $camelCasedWord)); + return $replace; + } +/** + * Returns a human-readable string from $lower_case_and_underscored_word, + * by replacing underscores with a space, and by upper-casing the initial characters. + * + * @param string $lower_case_and_underscored_word String to be made more readable + * @return string Human-readable string + * @access public + * @static + */ + function humanize($lowerCaseAndUnderscoredWord) { + $replace = ucwords(str_replace("_", " ", $lowerCaseAndUnderscoredWord)); + return $replace; + } +/** + * Returns corresponding table name for given $class_name. ("posts" for the model class "Post"). + * + * @param string $class_name Name of class to get database table name for + * @return string Name of the database table for given class + * @access public + * @static + */ + function tableize($className) { + $replace = Inflector::pluralize(Inflector::underscore($className)); + return $replace; + } +/** + * Returns Cake model class name ("Post" for the database table "posts".) for given database table. + * + * @param string $tableName Name of database table to get class name for + * @return string Class name + * @access public + * @static + */ + function classify($tableName) { + $replace = Inflector::camelize(Inflector::singularize($tableName)); + return $replace; + } +/** + * Returns camelBacked version of a string. + * + * @param string $string + * @return string in variable form + * @access public + * @static + */ + function variable($string) { + $string = Inflector::camelize(Inflector::underscore($string)); + $replace = strtolower(substr($string, 0, 1)); + $variable = preg_replace('/\\w/', $replace, $string, 1); + return $variable; + } +/** + * Returns a string with all spaces converted to $replacement and non word characters removed. + * + * @param string $string + * @param string $replacement + * @return string + * @access public + * @static + */ + function slug($string, $replacement = '_') { + if (!class_exists('String')) { + require LIBS . 'string.php'; + } + $map = array( + '/à|á|å|â/' => 'a', + '/è|é|ê|ẽ|ë/' => 'e', + '/ì|í|î/' => 'i', + '/ò|ó|ô|ø/' => 'o', + '/ù|ú|ů|û/' => 'u', + '/ç/' => 'c', + '/ñ/' => 'n', + '/ä|æ/' => 'ae', + '/ö/' => 'oe', + '/ü/' => 'ue', + '/Ä/' => 'Ae', + '/Ü/' => 'Ue', + '/Ö/' => 'Oe', + '/ß/' => 'ss', + '/[^\w\s]/' => ' ', + '/\\s+/' => $replacement, + String::insert('/^[:replacement]+|[:replacement]+$/', array('replacement' => preg_quote($replacement, '/'))) => '', + ); + $string = preg_replace(array_keys($map), array_values($map), $string); + return $string; + } +} +/** + * Enclose a string for preg matching. + * + * @param string $string String to enclose + * @return string Enclosed string + */ + function __enclose($string) { + return '(?:' . $string . ')'; + } Added: trunk/scripts/models-ext/AliasHandler.php =================================================================== --- trunk/scripts/models-ext/AliasHandler.php (rev 0) +++ trunk/scripts/models-ext/AliasHandler.php 2010-05-23 14:17:07 UTC (rev 831) @@ -0,0 +1,189 @@ +<?php + +/** + * Handlers User level alias actions - e.g. add alias, get aliases, update etc. + */ +class AliasHandler { + + private $username = null; + + /** + * @param string $username + */ + public function __construct($username) { + $this->username = $username; + } + + /** + * @return array - list of email addresses the user's mail is forwarded to. + * (may be an empty list, especially if $CONF['alias_control'] is turned off... + * @param boolean - by default we don't return special addresses (e.g. vacation and mailbox alias); pass in true here if you wish to. + */ + public function get($all=false) { + $username = escape_string($this->username); + $table_alias = table_by_key('alias'); + + $sql = "SELECT * FROM $table_alias WHERE address='$username'"; + $result = db_query($sql); + if($result['rows'] == 1) { + $row = db_array ($result['result']); + // At the moment Postfixadmin stores aliases in it's database in a comma seperated list; this may change one day. + $list = explode(',', $row['goto']); + if($all) { + return $list; + } + + $new_list = array(); + /* if !$all, remove vacation & mailbox aliases */ + foreach($list as $address) { + if($address != '' ) { + if($this->is_vacation_address($address) || $this->is_mailbox_alias($address)) { + } + else { + $new_list[] = $address; + } + } + } + $list = $new_list; + return $list; + } + return array(); + } + + /** + * @param string $address + * @param string $username + * @return boolean true if the username is an alias for the mailbox AND we have alias_control turned off. + */ + public function is_mailbox_alias($address) { + global $CONF; + $username = $this->username; + if($address == $username) { + return true; + } + return false; + } + + /** + * @param string $address + * @return boolean true if the address contains the vacation domain + */ + public function is_vacation_address($address) { + global $CONF; + if($CONF['vacation'] == 'YES') { + if(stripos($address, '@' . $CONF['vacation_domain'])) { + return true; + } + } + return false; + } + /** + * @return boolean true on success + * @param string $username + * @param array $addresses - list of aliases to set for the user. + * @param string flags - forward_and_store or remote_only or '' + * @param boolean $vacation_persist - set to false to stop the vacation address persisting across updates + * Set the user's aliases to those provided. If $addresses ends up being empty the alias record is removed. + */ + public function update($addresses, $flags = '', $vacation_persist=true) { + // find out if the user is on vacation or not; if they are, + // then the vacation alias needs adding to the db (as we strip it out in the get method) + // likewise with the alias_control address. + + $valid_flags = array('', 'forward_and_store', 'remote_only'); + if(!in_array($flags, $valid_flags)) { + die("Invalid flag passed into update()... : $flag - valid options are :" . implode(',', $valid_flags)); + } + $addresses = array_unique($addresses); + + $original = $this->get(true); + $tmp = preg_split('/@/', $this->username); + $domain = $tmp[1]; + + foreach($original as $address) { + if($vacation_persist) { + if($this->is_vacation_address($address)) { + $addresses[] = $address; + } + } + if($flags != 'remote_only') { + if($this->is_mailbox_alias($address)) { + $addresses[] = $address; + } + } + } + $addresses = array_unique($addresses); + + $new_list = array(); + if($flags == 'remote_only') { + foreach($addresses as $address) { + // strip out our username... if it's in the list given. + if($address != $this->username) { + $new_list[] = $address; + } + } + $addresses = $new_list; + } + + if($flags == 'forward_and_store') { + if(!in_array($this->username, $addresses)) { + $addresses[] = $this->username; + } + } + $new_list = array(); + foreach($addresses as $address) { + if($address != '') { + $new_list[] = $address; + } + } + $addresses = array_unique($new_list); + $username = escape_string($this->username); + $goto = escape_string(implode(',', $addresses)); + $table_alias = table_by_key('alias'); + if(sizeof($addresses) == 0) { + $sql = "DELETE FROM $table_alias WHERE address = '$username'"; + } + if($this->hasAliasRecord() == false) { + $true = db_get_boolean(True); + $sql = "INSERT INTO $table_alias (address, goto, domain, created, modified, active) VALUES ('$username', '$goto', '$domain', NOW(), NOW(), '$true')"; + } + else { + $sql = "UPDATE $table_alias SET goto = '$goto', modified = NOW() WHERE address = '$username'"; + } + $result = db_query($sql); + if($result['rows'] != 1) { + return false; + } + db_log($username, $domain, 'edit_alias', "$username -> $goto"); + return true; + } + + /** + * Determine whether a local delivery address is present. This is + * stores as an alias with the same name as the mailbox name (username) + * @return boolean true if local delivery is enabled + */ + public function hasStoreAndForward() { + $aliases = $this->get(true); + if(in_array($this->username, $aliases)) { + return true; + } + return false; + } + + /** + * @return boolean true if the user has an alias record (i.e row in alias table); else false. + */ + public function hasAliasRecord() { + $username = escape_string($this->username); + $table_alias = table_by_key('alias'); + $sql = "SELECT * FROM $table_alias WHERE address = '$username'"; + $result = db_query($sql); + if($result['rows'] == 1) { + return true; + } + return false; + } +} + +/* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */ Added: trunk/scripts/models-ext/DomainHandler.php =================================================================== --- trunk/scripts/models-ext/DomainHandler.php (rev 0) +++ trunk/scripts/models-ext/DomainHandler.php 2010-05-23 14:17:07 UTC (rev 831) @@ -0,0 +1,78 @@ +<?php + +/** + * Handlers User level alias actions - e.g. add alias, get aliases, update etc. + */ +class DomainHandler { + + private $username = null; + + + public $errormsg = array(); + /** + * @param string $username + */ + public function __construct($username) { + $this->username = $username; + } + + public function getTransports() { + return Config::read('transport_options'); + } + + public function getTransport($id) { + $transports = Config::read('transport_options'); + return $transports[$id-1]; + } + + public function add($domain, $desc, $a, $m, $t, $q, $default, $backup){ + + $table_domain = table_by_key('domain'); + $table_alias = table_by_key('alias'); + + + ($backup == true) ? $backup = db_get_boolean(true) : $backup = db_get_boolean(false); + + $arr = array( + 'domain' => $domain, + 'description' => $desc, + 'aliases' => $a, + 'mailboxes' => $m, + 'maxquota' => $q, + 'transport' => $this->getTransport($t), + 'backupmx' => $backup, + ); + + $result = db_insert($table_domain, $arr, array('created', 'modified') ); + if ($result != 1) + { + $this->errormsg[] = Lang::read('pAdminCreate_domain_result_error') . "\n($domain)\n"; + return 1; + } + else + { + if ($default) + { + foreach (Config::read('default_aliases') as $address=>$goto) + { + $address = $address . "@" . $domain; + $arr = array( + 'address' => $address, + 'goto' => $goto, + 'domain' => $domain, + ); + $result = db_insert ($table_alias, $arr, array('created', 'modified') ); + } + } + $tMessage = Lang::read('pAdminCreate_domain_result_success') . "<br />($domain)</br />"; + } + if (!domain_postcreation($domain)) + { + $tMessage = Lang::read('pAdminCreate_domain_error'); + } + db_log($this->username, $domain, 'create_domain', ""); + return 0; + } +} + +/* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */ Added: trunk/scripts/models-ext/UserHandler.php =================================================================== --- trunk/scripts/models-ext/UserHandler.php (rev 0) +++ trunk/scripts/models-ext/UserHandler.php 2010-05-23 14:17:07 UTC (rev 831) @@ -0,0 +1,308 @@ +<?php + +/** + * Simple class to represent a user. + */ +class UserHandler { + + protected $username = null; + + public $errormsg = array(); + + public function __construct($username) { + $this->username = strtolower($username); + + + } + + /** + * @return boolean true on success; false on failure + * @param string $username + * @param string $old_password + * @param string $new_passwords + * + * All passwords need to be plain text; they'll be hashed appropriately + * as per the configuration in config.inc.php + */ + public function change_pw($new_password, $old_password, $match = true) { + global $config; + $username = $this->username; + $tmp = preg_split ('/@/', $username); + $domain = $tmp[1]; + + $username = escape_string($username); + $table_mailbox = table_by_key('mailbox'); + + $new_db_password = escape_string(pacrypt($new_password)); + + if ($match == true) { + $active = db_get_boolean(True); + $result = db_query("SELECT * FROM $table_mailbox WHERE username='$username' AND active='$active'"); + $result = $result['result']; + if ($new_db_password != $result['password']) { + $this->errormsg[] = 'Passwords do not Match'; + return 1; + } + } + + $set = array( + 'password' => $new_db_password + ); + + $result = db_update('mailbox', 'username=\''.$username.'\'', $set, array('modified') ); + + db_log ('CONSOLE', $domain, 'edit_password', "$username"); + if ($result != 1) { + $this->errormsg[] = Lang::read('pEdit_mailbox_result_error'); + return 1; + } + + return 0; + + } + + /** + * Attempt to log a user in. + * @param string $username + * @param string $password + * @return boolean true on successful login (i.e. password matches etc) + */ + public static function login($username, $password) { + global $config; + $username = escape_string($username); + + $table_mailbox = table_by_key('mailbox'); + $active = db_get_boolean(True); + $query = "SELECT password FROM $table_mailbox WHERE username='$username' AND active='$active'"; + + $result = db_query ($query); + if ($result['rows'] == 1) + { + $row = db_array ($result['result']); + $crypt_password = pacrypt ($password, $row['password']); + + if($row['password'] == $crypt_password) { + return true; + } + } + return false; + } +/** + * Add mailbox + * @param password string password of account + * @param gen boolean + * @param name string + * + */ + public function add($password, $name = '', $quota = 0, $active = true, $mail = true ) { + global $config; + $username = $this->username; + $tmp = preg_split ('/@/', $username); + $domain = $tmp[1]; + $address = escape_string($username); + $username = $tmp[0]; + + $table_mailbox = table_by_key('mailbox'); + $table_alias = table_by_key('alias'); + + $active = db_get_boolean($active); + + if(!check_mailbox ($domain)) { + $this->errormsg[] = Lang::read('pCreate_mailbox_username_text_error3'); + return 1; + } + $result = db_query ("SELECT * FROM $table_alias WHERE address='$address'"); + if ($result['rows'] == 1){ + $this->errormsg[] = Lang::read('pCreate_mailbox_username_text_error2'); + return 1; + } + + + $plain = $password; + $password = pacrypt ($password); + + if ( preg_match("/^dovecot:/", Config::read('encrypt')) ) { + $split_method = preg_split ('/:/', Config::read('encrypt')); + $method = strtoupper($split_method[1]); + $password = '{' . $method . '}' . $password; + } + + if (Config::read('domain_path') == "YES") + { + if (Config::read('domain_in_mailbox') == "YES") + { + $maildir = $domain . "/" . $address . "/"; + } + else + { + $maildir = $domain . "/" . $username . "/"; + } + } + else + { + $maildir = $address . "/"; + } + + $quota = multiply_quota ($quota); + + + if ('pgsql'== Config::read('database_type')) + { + db_query('BEGIN'); + } + + //$result = db_query ("INSERT INTO $table_alias (address,goto,domain,created,modified,active) VALUES ('$address','$address','$domain',NOW(),NOW(),'$active')"); + $arr = array( + 'address' => $address, + 'goto' => $address, + 'domain' => $domain, + 'active' => $active, + ); + + $result = db_insert($table_alias, $arr, array('created', 'modified') ); + if ($result != 1) + { + $this->errormsg[] = Lang::read('pAlias_result_error') . "\n($address -> $address)\n"; + return 1; + } + + // apparently uppercase usernames really confuse some IMAP clients. + $local_part = ''; + if(preg_match('/^(.*)@/', $address, $matches)) { + $local_part = $matches[1]; + } + + //$result = db_query ("INSERT INTO $table_mailbox (username,password,name,maildir,local_part,quota,domain,created,modified,active) VALUES ('$username','$password','$name','$maildir','$local_part','$quota','$domain',NOW(),NOW(),'$active')"); + + + $arr2 = array( + 'username' => $address, + 'password' => $password, + 'name' => $name, + 'maildir' => $maildir, + 'local_part' => $local_part, + 'quota' => $quota, + 'domain' => $domain, + 'active' => $active, + ); + $result = db_insert($table_mailbox, $arr2, array('created', 'modified') ); + if ($result != 1 || !mailbox_postcreation($address,$domain,$maildir, $quota)) + { + $this->errormsg[] = Lang::read('pCreate_mailbox_result_error') . "\n($address)\n"; + db_query('ROLLBACK'); + return 1; + } + else + { + db_query('COMMIT'); + db_log ('CONSOLE', $domain, 'create_mailbox', "$address"); + + + if ($mail == true) + { + $fTo = $address; + $fFrom = Config::read('admin_email'); + $fHeaders = "To: " . $fTo . "\n"; + $fHeaders .= "From: " . $fFrom . "\n"; + + $fHeaders .= "Subject: " . encode_header (Lang::read('pSendmail_subject_text')) . "\n"; + $fHeaders .= "MIME-Version: 1.0\n"; + $fHeaders .= "Content-Type: text/plain; charset=utf-8\n"; + $fHeaders .= "Content-Transfer-Encoding: 8bit\n"; + + $fHeaders .= Config::read('welcome_text'); + + if (!smtp_mail ($fTo, $fFrom, $fHeaders)) + { + $this->errormsg[] = Lang::read('pSendmail_result_error'); + return 1; + } + } + + create_mailbox_subfolders($address,$plain); + + } + return 0; + } + + + + + public function view() { + global $config; + + + + $username = $this->username; + $table_mailbox = table_by_key('mailbox'); + + $result = db_query("SELECT username, name, maildir, quota, local_part, domain, DATE_FORMAT(created, '%d.%m.%y') AS created, DATE_FORMAT(modified, '%d.%m.%y') AS modified, active FROM $table_mailbox WHERE username='$username'"); + if ($result['rows'] != 0) { + $this->return = db_array($result['result']); + return 0; + } + $this->errormsg = $result['error']; + return 1; + } + + public function delete() { + global $config; + $username = $this->username; + $tmp = preg_split ('/@/', $username); + $domain = $tmp[1]; + $username = escape_string($username); + + + + $table_mailbox = table_by_key('mailbox'); + $table_alias = table_by_key('alias'); + $table_vacation = table_by_key('vacation'); + $table_vacation_notification = table_by_key('vacation_notification'); + + if (Config::read('database_type') == "pgsql") db_query('BEGIN'); + /* there may be no aliases to delete */ + $result = db_query("SELECT * FROM $table_alias WHERE address = '$username' AND domain = '$domain'"); + if($result['rows'] == 1) { + //$result = db_query ("DELETE FROM $table_alias WHERE address='$username' AND domain='$domain'"); + $result = db_delete($table_alias, 'address', $username); + db_log ('CONSOLE', $domain, 'delete_alias', $username); + } + + /* is there a mailbox? if do delete it from orbit; it's the only way to be sure */ + $result = db_query ("SELECT * FROM $table_mailbox WHERE username='$username' AND domain='$domain'"); + if ($result['rows'] == 1) + { + //$result = db_query ("DELETE FROM $table_mailbox WHERE username='$username' AND domain='$domain'"); + $result = db_delete($table_mailbox, 'username', $username); + $postdel_res=mailbox_postdeletion($username,$domain); + if ($result != 1 || !$postdel_res) + { + + $tMessage = Lang::read('pDelete_delete_error') . "$username ("; + if ($result['rows']!=1) + { + $tMessage.='mailbox'; + if (!$postdel_res) $tMessage.=', '; + } + if (!$postdel_res) + { + $tMessage.='post-deletion'; + } + $this->errormsg[] = $tMessage.')'; + return 1; + } + db_log ('CONSOLE', $domain, 'delete_mailbox', $username); + } + $result = db_query("SELECT * FROM $table_vacation WHERE email = '$username' AND domain = '$domain'"); + if($result['rows'] == 1) { + //db_query ("DELETE FROM $table_vacation WHERE email='$username' AND domain='$domain'"); + db_delete($table_vacation, 'email', $username); + //db_query ("DELETE FROM $table_vacation_notification WHERE on_vacation ='$username' "); /* should be caught by cascade, if PgSQL */ + db_delete($table_vacation_notification, 'on_vacation', $username); + } + return 0; + } + +} + +/* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */ Added: trunk/scripts/postfixadmin-cli =================================================================== --- trunk/scripts/postfixadmin-cli (rev 0) +++ trunk/scripts/postfixadmin-cli 2010-05-23 14:17:07 UTC (rev 831) @@ -0,0 +1,31 @@ +#!/bin/bash +################################################################################ +# +# Bake is a shell script for running CakePHP bake script +# PHP versions 4 and 5 +# +# CakePHP(tm) : Rapid Development Framework (http://www.cakephp.org) +# Copyright 2005-2007, Cake Software Foundation, Inc. +# +# Licensed under The MIT License +# Redistributions of files must retain the above copyright notice. +# +# @filesource +# @copyright Copyright 2005-2007, Cake Software Foundation, Inc. +# @link http://www.cakefoundation.org/projects/info/cakephp CakePHP(tm) Project +# @package cake +# @subpackage cake.cake.console +# @since CakePHP(tm) v 1.2.0.5012 +# @version $Revision$ +# @modifiedby $LastChangedBy$ +# @lastmodified $Date$ +# @license http://www.opensource.org/licenses/mit-license.php The MIT License +# +################################################################################ +clear + +LIB=${0/%postfixadmin-cli/} + +exec php -q ${LIB}postfixadmin-cli.php "$@" + +exit; \ No newline at end of file Added: trunk/scripts/postfixadmin-cli.php =================================================================== --- trunk/scripts/postfixadmin-cli.php (rev 0) +++ trunk/scripts/postfixadmin-cli.php 2010-05-23 14:17:07 UTC (rev 831) @@ -0,0 +1,580 @@ +#!/usr/bin/php +<?php +/** + * Command-line code generation utility to automate administrator tasks. + * + * Shell dispatcher class + * + * PHP versions 4 and 5 + * + * CakePHP(tm) : Rapid Development Framework <http://www.cakephp.org/> + * Copyright 2005-2008, Cake Software Foundation, Inc. + * 1785 E. Sahara Avenue, Suite 490-204 + * Las Vegas, Nevada 89104 + * Modified for Postfixadmin by Valkum + * + * Copyright 2010 + * + * Licensed under The MIT License + * Redistributions of files must retain the above copyright notice. + * + * @filesource + * @copyright Copyright 2005-2008, Cake Software Foundation, Inc. + * @link http://postfixadmin.sourceforge.net/ Postfixadmin on Sourceforge + * @package postfixadmin + * @subpackage - + * @since - + * @version $Revision$ + * @modifiedby $LastChangedBy$ + * @lastmodified $Date$ + * @license http://www.opensource.org/licenses/mit-license.php The MIT License + */ + + +class PostfixAdmin { +/** + * Version + * + * @var string + * @access protected + */ + var $version ='0.2'; + +/** + * Standard input stream. + * + * @var filehandle + * @access public + */ + var $stdin; +/** + * Standard output stream. + * + * @var filehandle + * @access public + */ + var $stdout; +/** + * Standard error stream. + * + * @var filehandle + * @access public + */ + var $stderr; +/** + * Contains command switches parsed from the command line. + * + * @var array + * @access public + */ + var $params = array(); +/** + * Contains arguments parsed from the command line. + * + * @var array + * @access public + */ + var $args = array(); +/** + * The file name of the shell that was invoked. + * + * @var string + * @access public + */ + var $shell = null; +/** + * The class name of the shell that was invoked. + * + * @var string + * @access public + */ + var $shellClass = null; +/** + * The command called if public methods are available. + * + * @var string + * @access public + */ + var $shellCommand = null; +/** + * The path locations of shells. + * + * @var array + * @access public + */ + var $shellPaths = array(); +/** + * The path to the current shell location. + * + * @var string + * @access public + */ + var $shellPath = null; +/** + * The name of the shell in camelized. + * + * @var string + * @access public + */ + var $shellName = null; +/** + * Constructs this ShellDispatcher instance. + * + * @param array $args the argv. + */ + function PostfixAdmin($args = array()) { + $this->__construct($args); + } +/** + * Constructor + * + * @param array $args the argv. + */ + function __construct($args = array()) { + set_time_limit(0); + $this->__initConstants(); + $this->parseParams($args); + $this->__initEnvironment(); + /*$this->dispatch(); + die("\n");*/ + } +/** + * Defines core configuration. + * + * @access private + */ + function __initConstants() { + if (function_exists('ini_set')) { + ini_set('display_errors', '1'); + ini_set('error_reporting', E_ALL); + ini_set('html_errors', false); + ini_set('implicit_flush', true); + ini_set('max_execution_time', 0); + } + + define('DS', DIRECTORY_SEPARATOR); + define('PHP5', (PHP_VERSION >= 5)); + define('CORE_INCLUDE_PATH', dirname(__FILE__)); + define('CORE_PATH', substr(CORE_INCLUDE_PATH, 0, -8) ); + + if(!defined('POSTFIXADMIN')) { # already defined if called from setup.php + define('POSTFIXADMIN', 1); # checked in included files + } + + + } +/** + * Defines current working environment. + * + * @access private + */ + function __initEnvironment() { + $this->stdin = fopen('php://stdin', 'r'); + $this->stdout = fopen('php://stdout', 'w'); + $this->stderr = fopen('php://stderr', 'w'); + + if (!$this->__bootstrap()) { + $this->stderr(""); + $this->stderr("Unable to load."); + $this->stderr("\tMake sure /config.inc.php exists in " . PATH); + exit(); + } + + + if (basename(__FILE__) != basename($this->args[0])) { + $this->stderr("\nCakePHP Console: "); + $this->stderr('Warning: the dispatcher may have been loaded incorrectly, which could lead to unexpected results...'); + if ($this->getInput('Continue anyway?', array('y', 'n'), 'y') == 'n') { + exit(); + } + } + + $this->shiftArgs(); + + + + } +/** + * Initializes the environment and loads the Cake core. + * + * @return boolean Success. + * @access private + */ + function __bootstrap() { + if ($this->params['webroot'] != '' ) { + define('PATH', $this->params['webroot'] ); + } else { + define('PATH', CORE_PATH); + } + if (!file_exists(PATH)) { + $this->stderr( PATH . " don't exists"); + return false; + + } + $includes = array( + PATH.'/config.inc.php', + PATH.'/languages/language.php', + PATH.'/functions.inc.php', + PATH.'/languages/en.lang', + CORE_INCLUDE_PATH.'/common.php', + CORE_INCLUDE_PATH.'/inflector.php', + ); + + foreach ($includes as $inc) { + if (!require_once($inc)) { + $this->stderr("Failed to load {$inc}"); + return false; + } + } + Config::getInstance(); + Config::write($CONF); + + Lang::getInstance(); + Lang::write($PALANG); + + return true; + } + +/** + * Dispatches a CLI request + * + * @access public + */ + function dispatch() { + $CONF = Config::read('all'); + if (isset($this->args[0])) { + $plugin = null; + $shell = $this->args[0]; + if (strpos($shell, '.') !== false) { + list($plugin, $shell) = explode('.', $this->args[0]); + } + + $this->shell = $shell; + $this->shiftArgs(); + $this->shellName = Inflector::camelize($this->shell); + $this->shellClass = 'PostfixAdmin'.$this->shellName; + + + if ($this->shell == 'help') { + $this->help(); + } else { + $loaded = false; + $paths = array(); + + if ($plugin !== null) { + $pluginPaths = Config::read('pluginPaths'); + $count = count($pluginPaths); + for ($i = 0; $i < $count; $i++) { + $paths[] = $pluginPaths[$i] . $plugin . DS . 'vendors' . DS . 'shells' . DS; + } + } + + + $paths[] = CORE_INCLUDE_PATH . DS . "shells" . DS; + + $this->shellPaths = $paths; + foreach ($this->shellPaths as $path) { + $this->shellPath = $path . $this->shell . ".php"; + if (file_exists($this->shellPath)) { + $loaded = true; + break; + } + } + if ($loaded) { + if (!class_exists('Shell')) { + require CORE_INCLUDE_PATH . DS . "shells" . DS . 'shell.php'; + } + + require $this->shellPath; + if (class_exists($this->shellClass)) { + $command = null; + if (isset($this->args[0])) { + $command = $this->args[0]; + } + $this->shellCommand = $command; + $shell = new $this->shellClass($this); + + if (strtolower(get_parent_class($shell)) == 'shell') { + $shell->initialize(); + $shell->loadTasks(); + + foreach ($shell->taskNames as $task) { + if (strtolower(get_parent_class($shell)) == 'shell') { + $shell->{$task}->initialize(); + $shell->{$task}->loadTasks(); + } + } + + $task = Inflector::camelize($command); + if (in_array($task, $shell->taskNames)) { + $this->shiftArgs(); + $shell->{$task}->startup(); + if (isset($this->args[0]) && $this->args[0] == 'help') { + if (method_exists($shell->{$task}, 'help')) { + $shell->{$task}->help(); + exit(); + } else { + $this->help(); + } + } + $shell->{$task}->execute(); + return; + } + } + + $classMethods = get_class_methods($shell); + + $privateMethod = $missingCommand = false; + if ((in_array($command, $classMethods) || in_array(strtolower($command), $classMethods)) && strpos($command, '_', 0) === 0) { + $privateMethod = true; + } + + if (!in_array($command, $classMethods) && !in_array(strtolower($command), $classMethods)) { + $missingCommand = true; + } + + $protectedCommands = array( + 'initialize','in','out','err','hr', + 'createfile', 'isdir','copydir','object','tostring', + 'requestaction','log','cakeerror', 'shelldispatcher', + '__initconstants','__initenvironment','__construct', + 'dispatch','__bootstrap','getinput','stdout','stderr','parseparams','shiftargs' + ); + + if (in_array(strtolower($command), $protectedCommands)) { + $missingCommand = true; + } + + if ($missingCommand && method_exists($shell, 'main')) { + $shell->startup(); + $shell->main(); + } elseif (!$privateMethod && method_exists($shell, $command)) { + $this->shiftArgs(); + $shell->startup(); + $shell->{$command}(); + } else { + $this->stderr("Unknown {$this->shellName} command '$command'.\nFor usage, try 'cake {$this->shell} help'.\n\n"); + } + } else { + $this->stderr('Class '.$this->shellClass.' could not be loaded'); + } + } else { + $this->help(); + } + } + } else { + $this->help(); + } + } + +/** + * Prompts the user for input, and returns it. + * + * @param string $prompt Prompt text. + * @param mixed $options Array or string of options. + * @param string $default Default input value. + * @return Either the default value, or the user-provided input. + * @access public + */ + function getInp... [truncated message content] |