1<?php
2/**
3 * Wiki farm SOAP server
4 *
5 * @license  GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author   Etienne MELEARD <etienne.meleard@cru.fr>
7 * @desc     Handle SOAP requests
8 */
9
10/**
11 * Specific handler to gather errors
12 */
13class SOAP_errorHandler {
14	var $errors = array();
15
16	function __construct() {}
17
18	function getErrors() {
19		return array_values($this->errors);
20	}
21}
22
23/**
24 * Class that handles SOAP requests
25 */
26class farmSOAP {
27	private $server = null;
28
29	/**
30	 * @param $s reference to the SOAP handler
31	 */
32	function __construct($s) {
33		$this->server = $s;
34	}
35
36	/**
37	 * Identify remote application and process SOAP requests
38	 * @return array returned from service call
39	 */
40	function authenticateRemoteAppAndRun() {
41		$args = func_get_args();
42		if(count($args) < 3) return array();
43
44		// get call args
45		$appname = $args[0];
46		$apppwd = $args[1];
47		$service = $args[2];
48
49		if($appname == '' || $apppwd == '' || $service == '') return array();
50
51		$serviceargs = isset($args[3]) ? (is_array($args[3]) ? $args[3] : array($args[3])) : array();
52
53		// identify app
54		$app = $this->getApp($appname);
55		if(!$app) return array();
56		if(bin2hex(mhash(1, $apppwd)) != $app['pwd']) return array();
57
58		// check rights
59		if(!isset($app['allowed'][$service])) return array();
60		if(!method_exists($this, 'service_'.$service)) return array();
61
62		// call and return
63		foreach($app['allowed'][$service] as $k => $v) {
64			if(is_array($v)) {
65				if(!in_array($serviceargs[$k], $v)) $serviceargs[$k] = reset($v);
66			}else $serviceargs[$k] = $v;
67		}
68		return call_user_func(array($this, 'service_'.$service), $serviceargs);
69	}
70
71	/**
72	 * Check whether an application is in the trust list and gather its rights
73	 * @param $name application name
74	 * @return application descriptor
75	 */
76	function getApp($name) {
77		foreach(explode("\n\n", preg_replace('`<\?php[^?]+\?>\s*`i', '', file_get_contents('./trusted_apps.php'))) as $a) {
78			$app = array();
79			foreach(explode("\n", trim($a)) as $f) {
80				if(preg_match('`^(name|pwd)\s*=\s*([^#]+)(#.*)?$`i', trim($f), $m)) $app[$m[1]] = trim($m[2]);
81				if(preg_match('`^allowed\s*=\s*([^#]+)(#.*)?$`i', trim($f), $m)) {
82					$app['allowed'] = array();
83					$list = trim($m[1]);
84					while(preg_match('`^([^(,]+)(\(([^)]+)\))?(\s*,\s*(.*))?$`', $list, $m)) {
85						$sname = trim($m[1]);
86						$ovr = trim($m[3]);
87						$list = isset($m[5]) ? trim($m[5]) : '';
88
89						$app['allowed'][$sname] = array();
90						if($ovr != '') {
91							foreach(array_map('trim', explode(',', $ovr)) as $o) {
92								$o = array_map('trim', explode('=', $o));
93								if(count($o) == 1) {
94									$app['allowed'][$sname][$o[0]] = true;
95								}elseif(count($o) == 2) {
96									if(preg_match('`^\[[^]]+\]$`', $o[1])) $o[1] = array_map('trim', explode(',', substr($o[1], 1, -1)));
97									elseif(preg_match('`^[0-9]+$`', $o[1])) $o[1] = (int)$o[1];
98									elseif(preg_match('`^[0-9]+\.[0-9]+$`', $o[1])) $o[1] = (float)$o[1];
99									elseif(preg_match('`^(true|false)$`i', $o[1])) $o[1] = (strtolower($o[1]) == 'true');
100									elseif(preg_match('`^null$`i', $o[1])) $o[1] = null;
101									$app['allowed'][$sname][$o[0]] = $o[1];
102								}
103							}
104						}
105					}
106				}
107			}
108			if(isset($app['name']) && $app['name'] == $name) return $app;
109		}
110		return null;
111	}
112
113	/*
114	 *==========*
115	 * SERVICES *
116	 *==========*
117	 */
118
119	/**
120	 * Simple service that returns args to check app auth & passed args
121	 * @param $args SOAP arguments
122	 * @return stuff
123	 */
124	function service_test($args) {
125		return array('appauth' => 'ok', 'args' => $args);
126	}
127
128	/**
129	 * Service that creates an animal
130	 * @param $args SOAP arguments
131	 * @return success indicator and errors, also contains accepted name if successful (only different from original if it contained funky characters)
132	 */
133	function service_animalCreate($args) {
134		$name = isset($args['name']) ? $args['name'] : '';
135		$template = isset($args['template']) ? $args['template'] : '';
136		$host = isset($args['host']) ? $args['host'] : ''; // only used if farm is in virtual mode
137		$eh = new SOAP_errorHandler();
138		if($n = dokuwiki_farm_animal::createNew($name, $template, $host, $eh)) {
139			return array('success' => true, 'name' => $n);
140		}else return array('success' => false, 'errors' => $eh->getErrors());
141	}
142
143	/**
144	 * Service that deletes an animal
145	 * @param $args SOAP arguments
146	 * @return success indicator
147	 */
148	function service_animalDelete($args) {
149		$name = isset($args['name']) ? $args['name'] :  reset($args);
150		if(!dokuwiki_farm_animal::exists($name)) return array('success' => false);
151		$a = new dokuwiki_farm_animal($name);
152		return array('success' => $a->delete());
153	}
154
155	/**
156	 * Service that returns animal's status (existence/state)
157	 * @param $args SOAP arguments
158	 * @return animal status
159	 */
160	function service_animalExists($args) {
161		$name = isset($args['name']) ? $args['name'] : reset($args);
162		if(!dokuwiki_farm_animal::exists($args['name'])) return array('exists' => 0);
163		$a = new dokuwiki_farm_animal($args['name']);
164		return array(
165			'exists' => 1,
166			'status' => $a->getStatus(),
167			'locked' => $a->getLockState()
168		);
169	}
170
171	/**
172	 * Service that changes the status of an animal
173	 * @param $args SOAP arguments
174	 * @return success indicator
175	 */
176	function service_animalStatus($args) {
177		$name = isset($args['name']) ? $args['name'] : '';
178		$status = isset($args['status']) ? $args['status'] : '';
179		if($name == '' || in_array($status, array('open', 'maintenance', 'closed', 'abuse'))) return array();
180		if(!dokuwiki_farm_animal::exists($name)) return array();
181		$a = new dokuwiki_farm_animal($name);
182		return array('success' => $a->setMetadata('status', $status));
183	}
184
185	/**
186	 * Service that changes the lock state of an animal
187	 * @param $args SOAP arguments
188	 * @return success indicator
189	 */
190	function service_animalLockState($args) {
191		$name = isset($args['name']) ? $args['name'] : '';
192		$lockstate = isset($args['lockstate']) ? $args['lockstate'] : '';
193		if($name == '' || in_array($lockstate, array('', 'none', 'edits', 'admin', 'all'))) return array();
194		if(!dokuwiki_farm_animal::exists($name)) return array();
195		$a = new dokuwiki_farm_animal($name);
196		return array('success' => $a->setMetadata('lockstate', $lockstate));
197	}
198
199	/**
200	 * Service that returns animals list
201	 * @param $args SOAP arguments
202	 * @return animal list
203	 */
204	function service_animalsList($args) {
205		return array_map(create_function('$a', 'return array(\'name\' => $a->getName(), \'url\' => $a->getUrl());'), dokuwiki_farm_animal::listAnimals());
206	}
207}
208
209// Loads farm config and register SOAP handler, if no POST data then prints wsdl
210if(!defined('DOKU_CONF')) {
211	define('DOKU_FARM_SOAPCONTEXT', true);
212	ini_set('soap.wsdl_cache_enabled', '0');
213
214	if(!@file_exists('config.php')) die('No config found');
215
216	$farmconf = array();
217	include 'config.php';
218
219	if(!isset($farmconf['enablesoap'])) die();
220	if(!$farmconf['enablesoap']) die();
221
222	include 'animal.class.php';
223
224	$wsdl = $farmconf['farmfsroot'].'farm.wsdl';
225	$trace = 0;
226	$soap_version = SOAP_1_1;
227
228	if($_SERVER['REQUEST_METHOD'] == 'POST') {
229		try {
230			$server = new SoapServer($wsdl,  array('trace' => $trace, 'soap_version' => $soap_version));
231			$server->setClass('farmSOAP', $server);
232			$server->handle();
233		}catch(Exception $e) {
234			die($e->getMessage());
235		}
236	}else echo @file_get_contents($wsdl);
237}
238