1 <?php
2 /*
4 This code is part of GOsa (https://gosa.gonicus.de)
5 Copyright (C) 2008 Fabian Hickert
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 Function overview:
24 __construct - Create a new deamon handle.
25 connect - Connect to deamon socket.
26 disconnect - Disconnect from socket.
27 set_error - Sets a new error.
28 is_error - Returns TRUE if there was an error.
29 get_error - Returns the last error or "".
30 get_queued_entries - Returns all queued entries, with limitations.
31 ids_exist - Checks if the given id exists.
32 get_entries_by_id - Returns a set of entries.
33 id_exists - Checks if a set entries exists.
34 get_entry_by_id - Returns a single entry.
35 remove_entries - Remove a set of entries.
36 remove_entry - Removes a single entry.
37 update_entries - Updates a set of entries.
38 xml_to_array - XML to Array.
39 number_of_queued_entries - Returns the number of currently queued entries.
40 */
42 class gosaSupportDaemon
43 {
44 private $s_host = "";
45 private $i_port = 0;
46 private $s_encryption_key = "";
48 private $o_sock = NULL;
49 private $f_timeout = 2;
50 private $s_error = "";
51 private $b_error = FALSE;
53 private $is_connected = FALSE;
56 /*! \brief Creates a new gosaSupportDaemon object.
57 @param string Host The Host where the deamon is running on.
58 @param integer Port The port which the deamon use.
59 @param string Key The encryption string.
60 @param boolean Connect Directly connect to deamon socket.
61 @param float Timeout The timelimit for all socket actions.
62 */
63 public function __construct($connect=TRUE,$timeout=0.2)
64 {
65 #FIXME: bad idea about referencing global variables from within classes
66 global $config;
68 # load from config, store statically
69 if (isset($config->current['GOSA_SI'])){
71 if ($this->s_host == ""){
72 $this->s_host= preg_replace("/^.*@([^:]+):.*$/", "$1", $config->current['GOSA_SI']);
73 $this->i_port= preg_replace("/^.*@[^:]+:(.*)$/", "$1", $config->current['GOSA_SI']);
74 $this->s_encryption_key = preg_replace("/^(.*)@[^:]+:.*$/", "$1", $config->current['GOSA_SI']);
75 }
77 $this->f_timeout = $timeout;
78 if($connect){
79 $this->connect();
80 }
81 }
82 }
85 /*! \brief Establish deamon connection.
86 @return boolean Returns true if the connection was succesfully established.
87 */
88 public function connect()
89 {
90 $this->o_sock = new Socket_Client($this->s_host,$this->i_port,TRUE,$this->f_timeout);
91 if($this->o_sock->connected()){
92 $this->o_sock->setEncryptionKey($this->s_encryption_key);
93 $this->is_connected = TRUE;
94 }else{
95 $this->error = $this->o_sock->get_error();
96 $this->disconnect();
97 }
98 return($this->is_connected);
99 }
102 /*! \brief Disconnect from gosa deamon.
103 */
104 public function disconnect()
105 {
106 $this->o_sock->close();
107 $this->is_connected = FALSE;
108 }
111 /*! \brief Sets an error message, which can be returned with get_error().
112 @param string The Error message,
113 */
114 private function set_error($str)
115 {
116 $this->b_error = TRUE;
117 $this->s_error = $str;
118 }
121 /*! \brief Checks if an error occured.
122 @return boolean returns TRUE or FALSE, whether there is an error or not.
123 */
124 public function is_error()
125 {
126 return($this->b_error);
127 }
130 /*! \brief Returns the last error.
131 @return Returns the last error.
132 */
133 public function get_error()
134 {
135 return($this->s_error);
136 }
139 /*! \brief Returns an array containing all queued entries.
140 @return Array All queued entries as an array.
141 */
142 public function get_queued_entries($from=0,$to=10,$sort="timestamp DESC")
143 {
144 $this->b_error = FALSE;
145 $this->s_error = "";
146 $ret = array();
148 $xml_msg = "<xml>
149 <header>gosa_query_jobdb</header>
150 <where>
151 <clause>
152 <phrase>
153 <operator>ne</operator>
154 <HEADERTAG>*</HEADERTAG>
155 </phrase>
156 </clause>
157 </where>
158 <orderby>".$sort."</orderby>
159 <limit>
160 <from>".$from."</from>
161 <to>".$to."</to>
162 </limit>
163 </xml>";
165 if($this->connect()){
166 $this->o_sock->write($xml_msg);
167 $str = trim($this->o_sock->read());
168 $entries = $this->xml_to_array($str);
169 if(isset($entries['XML']) && is_array($entries['XML'])){
171 /* Check if returned values represent a valid answer */
172 if($entries['XML']['HEADER'] == "answer"){
174 /* Unset header tags */
175 foreach(array("HEADER","SOURCE","TARGET") as $type){
176 unset($entries['XML'][$type]);
177 }
178 $ret = $entries;
179 }
180 }
181 }
183 return($ret);
184 }
187 /*! \brief Checks if the given ids are used queue ids.
188 @param Array The ids we want to check..
189 @return Array An array containing all ids as index and TRUE/FALSE as value.
190 */
191 public function ids_exist($ids)
192 {
193 if(!is_array($ids)){
194 trigger_error("Requires an array as parameter.");
195 return;
196 }
197 $this->b_error = FALSE;
198 $this->s_error = "";
200 $ret = array();
202 $xml_msg = "<xml>
203 <header>gosa_query_jobdb</header>
204 <where>
205 <clause>
206 <connector>or</connector>";
207 foreach($ids as $id){
208 $xml_msg .= "<phrase>
209 <operator>eq</operator>
210 <id>".$id."</id>
211 </phrase>";
212 }
213 $xml_msg .= "</clause>
214 </where>
215 </xml>";
217 if($this->connect()){
218 $this->o_sock->write($xml_msg);
219 $str = trim($this->o_sock->read());
220 $entries = $this->xml_to_array($str);
221 if(isset($entries['XML']) && is_array($entries['XML'])){
222 foreach($entries['XML'] as $entry){
223 if(isset($entry['ID'])){
224 $ret[] = $entry['ID'];
225 }
226 }
227 }
228 }
229 return($ret);
230 }
233 /*! \brief Returns an entry containing all requested ids.
234 @param Array The IDs of the entries we want to return.
235 @return Array Of the requested entries.
236 */
237 public function get_entries_by_id($ids)
238 {
239 if(!is_array($ids)){
240 trigger_error("Requires an array as parameter.");
241 return;
242 }
243 $this->b_error = FALSE;
244 $this->s_error = "";
246 $ret = array();
248 $xml_msg = "<xml>
249 <header>gosa_query_jobdb</header>
250 <where>
251 <clause>
252 <connector>or</connector>";
253 foreach($ids as $id){
254 $xml_msg .= "<phrase>
255 <operator>eq</operator>
256 <id>".$id."</id>
257 </phrase>";
258 }
259 $xml_msg .= "</clause>
260 </where>
261 </xml>";
263 if($this->connect()){
264 $this->o_sock->write($xml_msg);
265 $str = trim($this->o_sock->read());
266 $entries = $this->xml_to_array($str);
267 if(isset($entries['XML'])){
268 foreach($entries['XML'] as $name => $entry){
269 if(preg_match("/^ANSWER[0-9]*$/",$name)){
270 $ret[$name] = $entry;
271 }
272 }
273 }
274 }
275 return($ret);
276 }
279 /*! \brief Checks if the given id is in use.
280 @param Integer The ID of the entry.
281 @return Boolean TRUE if entry exists.
282 */
283 public function id_exists($id)
284 {
285 if(!is_numeric($id)){
286 trigger_error("Requires an integer as parameter.");
287 return;
288 }
290 $this->b_error = FALSE;
291 $this->s_error = "";
292 $xml_msg = "<xml>
293 <header>gosa_query_jobdb</header>
294 <where>
295 <clause>
296 <phrase>
297 <operator>eq</operator>
298 <id>".$id."</id>
299 </phrase>
300 </clause>
301 </where>
302 </xml>";
304 if($this->connect()){
305 $this->o_sock->write($xml_msg);
306 $str = trim($this->o_sock->read());
307 $entries = $this->xml_to_array($str);
308 if( isset($entries['XML']['HEADER']) &&
309 $entries['XML']['HEADER']=="answer" &&
310 isset($entries['XML']['ANSWER1'])){
311 return(TRUE);
312 }
313 }
314 return(FALSE);
315 }
318 /*! \brief Returns an entry from the gosaSupportQueue
319 @param Integer The ID of the entry we want to return.
320 @return Array Of the requested entry.
321 */
322 public function get_entry_by_id($id)
323 {
324 if(!is_numeric($id)){
325 trigger_error("Requires an integer as parameter.");
326 return;
327 }
329 $this->b_error = FALSE;
330 $this->s_error = "";
331 $ret = array();
332 $xml_msg = "<xml>
333 <header>gosa_query_jobdb</header>
334 <where>
335 <clause>
336 <phrase>
337 <operator>eq</operator>
338 <id>".$id."</id>
339 </phrase>
340 </clause>
341 </where>
342 </xml>";
343 if($this->connect()){
344 $this->o_sock->write($xml_msg);
345 $str = trim($this->o_sock->read());
346 $entries = $this->xml_to_array($str);
347 if( isset($entries['XML']['HEADER']) &&
348 $entries['XML']['HEADER']=="answer" &&
349 isset($entries['XML']['ANSWER1'])){
350 $ret = $entries['XML']['ANSWER1'];
351 }
352 }
353 return($ret);
354 }
357 /*! \brief Removes a set of entries from the GOsa support queue.
358 @param Array The IDs to remove.
359 @return Boolean True on success.
360 */
361 public function remove_entries($ids)
362 {
363 if(!is_array($ids)){
364 trigger_error("Requires an array as parameter.");
365 return;
366 }
367 $this->b_error = FALSE;
368 $this->s_error = "";
370 $ret = array();
372 $xml_msg = "<xml>
373 <header>gosa_delete_jobdb_entry</header>
374 <where>
375 <clause>
376 <connector>or</connector>";
377 foreach($ids as $id){
378 $xml_msg .= "<phrase>
379 <operator>eq</operator>
380 <id>".$id."</id>
381 </phrase>";
382 }
383 $xml_msg .= "</clause>
384 </where>
385 </xml>";
386 $this->b_error = FALSE;
387 $this->s_error = "";
389 if($this->connect()){
390 $this->o_sock->write($xml_msg);
391 $str = $this->o_sock->read();
392 $entries = $this->xml_to_array($str);
393 if(isset($entries['XML'])){
394 return(TRUE);
395 }
396 }
397 return(FALSE);
398 }
402 /*! \brief Removes an entry from the GOsa support queue.
403 @param Integer The ID of the entry we want to remove.
404 @return Boolean True on success.
405 */
406 public function remove_entry($id)
407 {
408 $this->b_error = FALSE;
409 $this->s_error = "";
411 $xml_msg = "<xml>
412 <header>gosa_delete_jobdb_entry</header>
413 <where>
414 <clause>
415 <phrase>
416 <operator>eq</operator>
417 <id>".$id."</id>
418 </phrase>
419 </clause>
420 </where>
421 </xml>";
422 if($this->connect()){
423 $this->o_sock->write($xml_msg);
424 $str = $this->o_sock->read();
425 $entries = $this->xml_to_array($str);
426 if(isset($entries['XML'])){
427 return(TRUE);
428 }
429 }
430 return(FALSE);
431 }
434 /*! \brief Parses the given xml string into an array
435 @param String XML string
436 @return Array Returns an array containing the xml structure.
437 */
438 public function xml_to_array($xml)
439 {
440 $params = array();
441 $level = array();
442 $parser = xml_parser_create_ns();
443 xml_parse_into_struct($parser, $xml, $vals, $index);
445 $err_id = xml_get_error_code($parser);
446 if($err_id){
447 xml_parser_free($parser);
448 }else{
449 xml_parser_free($parser);
451 foreach ($vals as $xml_elem) {
452 if ($xml_elem['type'] == 'open') {
453 if (array_key_exists('attributes',$xml_elem)) {
454 list($level[$xml_elem['level']],$extra) = array_values($xml_elem['attributes']);
455 } else {
456 $level[$xml_elem['level']] = $xml_elem['tag'];
457 }
458 }
459 if ($xml_elem['type'] == 'complete') {
460 $start_level = 1;
461 $php_stmt = '$params';
462 while($start_level < $xml_elem['level']) {
463 $php_stmt .= '[$level['.$start_level.']]';
464 $start_level++;
465 }
466 $php_stmt .= '[$xml_elem[\'tag\']] = $xml_elem[\'value\'];';
467 @eval($php_stmt);
468 }
469 }
470 }
472 if(!isset($params['XML'])){
473 if (!array_key_exists('XML', $params)){
474 $this->set_error(_("Could not parse XML."));
475 }
476 $params = array("COUNT" => 0);
477 }
479 return($params);
480 }
483 /*! \brief Updates an entry with a set of new values,
484 @param Integer The ID of the entry, we want to update.
485 @param Array The variables to update.
486 @return Boolean Returns TRUE on success.
487 */
488 public function update_entries($ids,$entry)
489 {
490 $this->b_error = FALSE;
491 $this->s_error = "";
492 if(!is_array($ids)){
493 trigger_error("Requires an array as first parameter.");
494 return;
495 }
497 if(!is_array($entry)){
498 trigger_error("Requires an array as second parameter.");
499 return;
500 }
502 $attr = "";
503 foreach($entry as $name => $entry){
504 $attr.="<".strtolower($name).">".$entry."</".strtolower($name).">\n";
505 }
506 $xml_msg = "<xml>
507 <header>gosa_update_status_jobdb_entry</header>
508 <where>
509 <clause>
510 <connector>or</connector>";
511 foreach($ids as $id){
512 $xml_msg .= "<phrase>
513 <operator>eq</operator>
514 <id>".$id."</id>
515 </phrase>";
516 }
517 $xml_msg .= "</clause>
518 </where>
519 <update>
520 ".$attr."
521 </update>
522 </xml>";
523 if($this->connect()){
524 $this->o_sock->write($xml_msg);
525 $str = trim($this->o_sock->read());
526 $entries = $this->xml_to_array($str);
527 if(isset($entries['XML'])){
528 return(TRUE);
529 }
530 }
531 return(FALSE);
532 }
535 /*! \brief Returns the number of currently queued objects.
536 @return Integer
537 */
538 public function number_of_queued_entries()
539 {
540 $xml_msg ="<xml><header>gosa_count_jobdb</header></xml>";
541 $this->connect();
542 if($this->connect()){
543 $this->o_sock->write($xml_msg);
544 $str = trim($this->o_sock->read());
545 $entries = $this->xml_to_array($str);
546 if(isset($entries['XML'])){
547 return($entries['XML']['COUNT']);
548 }
549 }
550 return(-1);
551 }
554 /*! \brief Returns an array containing all queued entries.
555 @return Array All queued entries as an array.
556 */
557 public function _send($data, $answer_expected= FALSE)
558 {
559 $this->b_error = FALSE;
560 $this->s_error = "";
561 $ret = array();
563 if($this->connect()){
564 $this->o_sock->write($data);
565 if ($answer_expected){
566 $str = trim($this->o_sock->read());
567 $entries = $this->xml_to_array($str);
568 if(isset($entries['XML']) && is_array($entries['XML'])){
569 $ret = $entries;
570 }
571 }
572 }
573 return($ret);
574 }
577 static function send($header, $to, $data= array())
578 {
579 $xml_message= "";
581 /* Get communication object */
582 $d= new gosaSupportDaemon(TRUE,10);
584 /* Prepare data */
585 foreach ($data as $key => $value){
586 $xml_message.= "<$key>$value</$key>";
587 }
589 return $d->_send("<xml><header>$header</header><source>GOSA</source><target>$to</target>".$xml_message."</xml>");
590 }
593 static function ping($target)
594 {
595 if (tests::is_mac($target)){
596 /* Get communication object */
597 $d= new gosaSupportDaemon(TRUE,0.5);
599 $answer= $d->_send("<xml><header>gosa_ping</header><source>GOSA</source><target>$target</target></xml>", TRUE);
600 return (count($answer) ? TRUE:FALSE);
601 }
603 return (FALSE);
604 }
606 }
608 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
609 ?>