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.

566 lines
21 KiB

  1. #!/usr/bin/php
  2. <?php
  3. /**
  4. * Command-line code generation utility to automate administrator tasks.
  5. *
  6. * Shell dispatcher class
  7. *
  8. * PHP versions 4 and 5
  9. *
  10. * CakePHP(tm) : Rapid Development Framework <http://www.cakephp.org/>
  11. * Copyright 2005-2008, Cake Software Foundation, Inc.
  12. * 1785 E. Sahara Avenue, Suite 490-204
  13. * Las Vegas, Nevada 89104
  14. * Modified for Postfixadmin by Valkum
  15. *
  16. * Copyright 2010
  17. *
  18. * Licensed under The MIT License
  19. * Redistributions of files must retain the above copyright notice.
  20. *
  21. * @filesource
  22. * @copyright Copyright 2005-2008, Cake Software Foundation, Inc.
  23. * @link http://postfixadmin.sourceforge.net/ Postfixadmin on Sourceforge
  24. * @package postfixadmin
  25. * @subpackage -
  26. * @since -
  27. * @version $Revision$
  28. * @modifiedby $LastChangedBy$
  29. * @lastmodified $Date$
  30. * @license http://www.opensource.org/licenses/mit-license.php The MIT License
  31. */
  32. class PostfixAdmin {
  33. /**
  34. * Version
  35. *
  36. * @var string
  37. * @access protected
  38. */
  39. var $version ='0.2';
  40. /**
  41. * Standard input stream.
  42. *
  43. * @var filehandle
  44. * @access public
  45. */
  46. var $stdin;
  47. /**
  48. * Standard output stream.
  49. *
  50. * @var filehandle
  51. * @access public
  52. */
  53. var $stdout;
  54. /**
  55. * Standard error stream.
  56. *
  57. * @var filehandle
  58. * @access public
  59. */
  60. var $stderr;
  61. /**
  62. * Contains command switches parsed from the command line.
  63. *
  64. * @var array
  65. * @access public
  66. */
  67. var $params = array();
  68. /**
  69. * Contains arguments parsed from the command line.
  70. *
  71. * @var array
  72. * @access public
  73. */
  74. var $args = array();
  75. /**
  76. * The file name of the shell that was invoked.
  77. *
  78. * @var string
  79. * @access public
  80. */
  81. var $shell = null;
  82. /**
  83. * The class name of the shell that was invoked.
  84. *
  85. * @var string
  86. * @access public
  87. */
  88. var $shellClass = null;
  89. /**
  90. * The command called if public methods are available.
  91. *
  92. * @var string
  93. * @access public
  94. */
  95. var $shellCommand = null;
  96. /**
  97. * The path locations of shells.
  98. *
  99. * @var array
  100. * @access public
  101. */
  102. var $shellPaths = array();
  103. /**
  104. * The path to the current shell location.
  105. *
  106. * @var string
  107. * @access public
  108. */
  109. var $shellPath = null;
  110. /**
  111. * The name of the shell in camelized.
  112. *
  113. * @var string
  114. * @access public
  115. */
  116. var $shellName = null;
  117. /**
  118. * Constructor
  119. *
  120. * @param array $args the argv.
  121. */
  122. function __construct($args = array()) {
  123. set_time_limit(0);
  124. $this->__initConstants();
  125. $this->parseParams($args);
  126. $this->__initEnvironment();
  127. /*$this->dispatch();
  128. die("\n");*/
  129. }
  130. /**
  131. * Defines core configuration.
  132. *
  133. * @access private
  134. */
  135. function __initConstants() {
  136. if (function_exists('ini_set')) {
  137. ini_set('display_errors', '1');
  138. ini_set('error_reporting', E_ALL);
  139. ini_set('html_errors', false);
  140. ini_set('implicit_flush', true);
  141. ini_set('max_execution_time', 0);
  142. }
  143. define('DS', DIRECTORY_SEPARATOR);
  144. define('PHP5', (PHP_VERSION >= 5));
  145. define('CORE_INCLUDE_PATH', dirname(__FILE__));
  146. define('CORE_PATH', dirname(CORE_INCLUDE_PATH) ); # CORE_INCLUDE_PATH/../
  147. if(!defined('POSTFIXADMIN')) { # already defined if called from setup.php
  148. define('POSTFIXADMIN', 1); # checked in included files
  149. }
  150. }
  151. /**
  152. * Defines current working environment.
  153. *
  154. * @access private
  155. */
  156. function __initEnvironment() {
  157. $this->stdin = fopen('php://stdin', 'r');
  158. $this->stdout = fopen('php://stdout', 'w');
  159. $this->stderr = fopen('php://stderr', 'w');
  160. if (!$this->__bootstrap()) {
  161. $this->stderr("");
  162. $this->stderr("Unable to load.");
  163. $this->stderr("\tMake sure /config.inc.php exists in " . PATH);
  164. exit();
  165. }
  166. if (basename(__FILE__) != basename($this->args[0])) {
  167. $this->stderr("\nCakePHP Console: ");
  168. $this->stderr('Warning: the dispatcher may have been loaded incorrectly, which could lead to unexpected results...');
  169. if ($this->getInput('Continue anyway?', array('y', 'n'), 'y') == 'n') {
  170. exit();
  171. }
  172. }
  173. $this->shiftArgs();
  174. }
  175. /**
  176. * Initializes the environment and loads the Cake core.
  177. *
  178. * @return boolean Success.
  179. * @access private
  180. */
  181. function __bootstrap() {
  182. if ($this->params['webroot'] != '' ) {
  183. define('PATH', $this->params['webroot'] );
  184. } else {
  185. define('PATH', CORE_PATH);
  186. }
  187. if (!file_exists(PATH)) {
  188. $this->stderr( PATH . " don't exists");
  189. return false;
  190. }
  191. $includes = array(
  192. PATH.'/config.inc.php',
  193. PATH.'/functions.inc.php',
  194. PATH.'/common.php',
  195. CORE_INCLUDE_PATH.'/inflector.php',
  196. );
  197. foreach ($includes as $inc) {
  198. if (!require_once($inc)) {
  199. $this->stderr("Failed to load {$inc}");
  200. return false;
  201. }
  202. }
  203. return true;
  204. }
  205. /**
  206. * Dispatches a CLI request
  207. *
  208. * @access public
  209. */
  210. function dispatch() {
  211. $CONF = Config::read('all');
  212. if (isset($this->args[0])) {
  213. $plugin = null;
  214. $shell = $this->args[0];
  215. if (strpos($shell, '.') !== false) {
  216. list($plugin, $shell) = explode('.', $this->args[0]);
  217. }
  218. $this->shell = $shell;
  219. $this->shiftArgs();
  220. $this->shellName = Inflector::camelize($this->shell);
  221. $this->shellClass = 'PostfixAdmin'.$this->shellName;
  222. if ($this->shell == 'help') {
  223. $this->help();
  224. } else {
  225. $loaded = false;
  226. $paths = array();
  227. if ($plugin !== null) {
  228. $pluginPaths = Config::read('pluginPaths');
  229. $count = count($pluginPaths);
  230. for ($i = 0; $i < $count; $i++) {
  231. $paths[] = $pluginPaths[$i] . $plugin . DS . 'vendors' . DS . 'shells' . DS;
  232. }
  233. }
  234. $paths[] = CORE_INCLUDE_PATH . DS . "shells" . DS;
  235. $this->shellPaths = $paths;
  236. foreach ($this->shellPaths as $path) {
  237. $this->shellPath = $path . $this->shell . ".php";
  238. if (file_exists($this->shellPath)) {
  239. $loaded = true;
  240. break;
  241. }
  242. }
  243. if ($loaded) {
  244. if (!class_exists('Shell')) {
  245. require CORE_INCLUDE_PATH . DS . "shells" . DS . 'shell.php';
  246. }
  247. require $this->shellPath;
  248. if (class_exists($this->shellClass)) {
  249. $command = null;
  250. if (isset($this->args[0])) {
  251. $command = $this->args[0];
  252. }
  253. $this->shellCommand = $command;
  254. $shell = new $this->shellClass($this);
  255. if (strtolower(get_parent_class($shell)) == 'shell') {
  256. $shell->initialize();
  257. $shell->loadTasks();
  258. foreach ($shell->taskNames as $task) {
  259. if (strtolower(get_parent_class($shell)) == 'shell') {
  260. $shell->{$task}->initialize();
  261. $shell->{$task}->loadTasks();
  262. }
  263. }
  264. $task = Inflector::camelize($command);
  265. if (in_array($task, $shell->taskNames)) {
  266. $this->shiftArgs();
  267. $shell->{$task}->startup();
  268. if (isset($this->args[0]) && $this->args[0] == 'help') {
  269. if (method_exists($shell->{$task}, 'help')) {
  270. $shell->{$task}->help();
  271. exit();
  272. } else {
  273. $this->help();
  274. }
  275. }
  276. $shell->{$task}->execute();
  277. return;
  278. }
  279. }
  280. $classMethods = get_class_methods($shell);
  281. $privateMethod = $missingCommand = false;
  282. if ((in_array($command, $classMethods) || in_array(strtolower($command), $classMethods)) && strpos($command, '_', 0) === 0) {
  283. $privateMethod = true;
  284. }
  285. if (!in_array($command, $classMethods) && !in_array(strtolower($command), $classMethods)) {
  286. $missingCommand = true;
  287. }
  288. $protectedCommands = array(
  289. 'initialize','in','out','err','hr',
  290. 'createfile', 'isdir','copydir','object','tostring',
  291. 'requestaction','log','cakeerror', 'shelldispatcher',
  292. '__initconstants','__initenvironment','__construct',
  293. 'dispatch','__bootstrap','getinput','stdout','stderr','parseparams','shiftargs'
  294. );
  295. if (in_array(strtolower($command), $protectedCommands)) {
  296. $missingCommand = true;
  297. }
  298. if ($missingCommand && method_exists($shell, 'main')) {
  299. $shell->startup();
  300. $shell->main();
  301. } elseif (!$privateMethod && method_exists($shell, $command)) {
  302. $this->shiftArgs();
  303. $shell->startup();
  304. $shell->{$command}();
  305. } else {
  306. $this->stderr("Unknown {$this->shellName} command '$command'.\nFor usage, try 'cake {$this->shell} help'.\n\n");
  307. }
  308. } else {
  309. $this->stderr('Class '.$this->shellClass.' could not be loaded');
  310. }
  311. } else {
  312. $this->help();
  313. }
  314. }
  315. } else {
  316. $this->help();
  317. }
  318. }
  319. /**
  320. * Prompts the user for input, and returns it.
  321. *
  322. * @param string $prompt Prompt text.
  323. * @param mixed $options Array or string of options.
  324. * @param string $default Default input value.
  325. * @return Either the default value, or the user-provided input.
  326. * @access public
  327. */
  328. function getInput($prompt, $options = null, $default = null) {
  329. if (!is_array($options)) {
  330. $print_options = '';
  331. } else {
  332. $print_options = '(' . implode('/', $options) . ')';
  333. }
  334. if ($default == null) {
  335. $this->stdout($prompt . " $print_options \n" . '> ', false);
  336. } else {
  337. $this->stdout($prompt . " $print_options \n" . "[$default] > ", false);
  338. }
  339. $result = fgets($this->stdin);
  340. if ($result === false){
  341. exit;
  342. }
  343. $result = trim($result);
  344. if ($default != null && empty($result)) {
  345. return $default;
  346. }
  347. return $result;
  348. }
  349. /**
  350. * Outputs to the stdout filehandle.
  351. *
  352. * @param string $string String to output.
  353. * @param boolean $newline If true, the outputs gets an added newline.
  354. * @access public
  355. */
  356. function stdout($string, $newline = true) {
  357. if ($newline) {
  358. fwrite($this->stdout, $string . "\n");
  359. } else {
  360. fwrite($this->stdout, $string);
  361. }
  362. }
  363. /**
  364. * Outputs to the stderr filehandle.
  365. *
  366. * @param string $string Error text to output.
  367. * @access public
  368. */
  369. function stderr($string) {
  370. fwrite($this->stderr, 'Error: '. $string . "\n");
  371. }
  372. /**
  373. * Parses command line options
  374. *
  375. * @param array $params Parameters to parse
  376. * @access public
  377. */
  378. function parseParams($params) {
  379. $this->__parseParams($params);
  380. $defaults = array('webroot' => CORE_PATH);
  381. $params = array_merge($defaults, array_intersect_key($this->params, $defaults));
  382. $isWin = array_filter(array_map('strpos', $params, array('\\')));
  383. $params = str_replace('\\', '/', $params);
  384. if (!empty($matches[0]) || !empty($isWin)) {
  385. $params = str_replace('/', '\\', $params);
  386. }
  387. $this->params = array_merge($this->params, $params);
  388. }
  389. /**
  390. * Helper for recursively paraing params
  391. *
  392. * @return array params
  393. * @access private
  394. */
  395. function __parseParams($params) {
  396. $count = count($params);
  397. for ($i = 0; $i < $count; $i++) {
  398. if (isset($params[$i])) {
  399. if ($params[$i]{0} === '-') {
  400. $key = substr($params[$i], 1);
  401. $this->params[$key] = true;
  402. unset($params[$i]);
  403. if (isset($params[++$i])) {
  404. if ($params[$i]{0} !== '-') {
  405. $this->params[$key] = str_replace('"', '', $params[$i]);
  406. unset($params[$i]);
  407. } else {
  408. $i--;
  409. $this->__parseParams($params);
  410. }
  411. }
  412. } else {
  413. $this->args[] = $params[$i];
  414. unset($params[$i]);
  415. }
  416. }
  417. }
  418. }
  419. /**
  420. * Removes first argument and shifts other arguments up
  421. *
  422. * @return boolean False if there are no arguments
  423. * @access public
  424. */
  425. function shiftArgs() {
  426. if (empty($this->args)) {
  427. return false;
  428. }
  429. unset($this->args[0]);
  430. $this->args = array_values($this->args);
  431. return true;
  432. }
  433. function help() {
  434. $this->stdout("\nWelcome to Postfixadmin-CLI v" . $this->version);
  435. $this->stdout("---------------------------------------------------------------");
  436. $this->stdout("Options:");
  437. $this->stdout(" -webroot: " . $this->params['webroot']);
  438. $this->stdout("");
  439. $this->stdout("Changing Paths:");
  440. $this->stdout("your webroot should be the same as your postfixadmin path");
  441. $this->stdout("to change your path use the '-webroot' param.");
  442. $this->stdout("Example: -webroot r/absolute/path/to/postfixadmin");
  443. $this->stdout("\nAvailable Commands:");
  444. foreach ($this->commands() AS $command => $desc) {
  445. if (is_array($desc)) {
  446. $this->stdout($command . ":");
  447. foreach($desc AS $command2 => $desc2) {
  448. $this->stdout(sprintf("%-20s %s", " ".$command2 .": ", $desc2));
  449. }
  450. $this->stdout("");
  451. } else {
  452. $this->stdout(sprintf("%-20s %s", $command .": ", $desc));
  453. }
  454. }
  455. $this->stdout("\nTo run a command, type 'postfixadmin-cli command [args]'");
  456. $this->stdout("To get help on a specific command, type 'postfixadmin-cli command help'");
  457. exit();
  458. }
  459. /**
  460. * Removes first argument and shifts other arguments up
  461. *
  462. * @return array List of commands
  463. * @access public
  464. */
  465. function commands() {
  466. return array(
  467. 'mailbox' => array(
  468. 'add'=> 'Adds a new mailbox.',
  469. 'update'=> 'Updates a mailbox.',
  470. 'delete' => 'Deletes a mailbox.',
  471. 'pw' => 'Changes the PW for a mailbox.',
  472. ),
  473. 'alias' => array(
  474. 'add' => 'Adds a new alias.',
  475. 'update' => 'Updates a alias.',
  476. 'delete' => 'Deletes a alias.',
  477. ),
  478. 'version' => 'Prints version of Postfixadmin and Postfixadmin-CLI'
  479. );
  480. }
  481. }
  482. define ("POSTFIXADMIN_CLI", 1);
  483. $dispatcher = new PostfixAdmin($argv);
  484. $CONF = Config::read('all');
  485. //bugfix shitty globals and OOP.....
  486. #$table_admin = table_by_key ('admin');
  487. $table_alias = table_by_key ('alias');
  488. #$table_alias_domain = table_by_key ('alias_domain');
  489. $table_domain = table_by_key ('domain');
  490. $table_domain_admins = table_by_key ('domain_admins');
  491. $table_log = table_by_key ('log');
  492. $table_mailbox = table_by_key ('mailbox');
  493. $table_vacation = table_by_key ('vacation');
  494. $table_vacation_notification = table_by_key('vacation_notification');
  495. $table_quota = table_by_key ('quota');
  496. $table_quota2 = table_by_key ('quota2');
  497. $dispatcher->dispatch();
  498. ?>