1 <?php
2 /*
3 This code is part of GOsa (https://gosa.gonicus.de)
4 Copyright (C) 2003 Cajus Pollmeier
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
21 /*! \brief The plugin base class
22 \author Cajus Pollmeier <pollmeier@gonicus.de>
23 \version 2.00
24 \date 24.07.2003
26 This is the base class for all plugins. It can be used standalone or
27 can be included by the tabs class. All management should be done
28 within this class. Extend your plugins from this class.
29 */
31 class plugin
32 {
33 /*!
34 \brief Reference to parent object
36 This variable is used when the plugin is included in tabs
37 and keeps reference to the tab class. Communication to other
38 tabs is possible by 'name'. So the 'fax' plugin can ask the
39 'userinfo' plugin for the fax number.
41 \sa tab
42 */
43 var $parent= NULL;
45 /*!
46 \brief Configuration container
48 Access to global configuration
49 */
50 var $config= NULL;
52 /*!
53 \brief Mark plugin as account
55 Defines whether this plugin is defined as an account or not.
56 This has consequences for the plugin to be saved from tab
57 mode. If it is set to 'FALSE' the tab will call the delete
58 function, else the save function. Should be set to 'TRUE' if
59 the construtor detects a valid LDAP object.
61 \sa plugin::plugin()
62 */
63 var $is_account= FALSE;
64 var $initially_was_account= FALSE;
66 /*!
67 \brief Mark plugin as template
69 Defines whether we are creating a template or a normal object.
70 Has conseqences on the way execute() shows the formular and how
71 save() puts the data to LDAP.
73 \sa plugin::save() plugin::execute()
74 */
75 var $is_template= FALSE;
76 var $ignore_account= FALSE;
77 var $is_modified= FALSE;
79 /*!
80 \brief Represent temporary LDAP data
82 This is only used internally.
83 */
84 var $attrs= array();
86 /* Keep set of conflicting plugins */
87 var $conflicts= array();
89 /* Save unit tags */
90 var $gosaUnitTag= "";
92 /*!
93 \brief Used standard values
95 dn
96 */
97 var $dn= "";
98 var $uid= "";
99 var $sn= "";
100 var $givenName= "";
101 var $acl= "*none*";
102 var $dialog= FALSE;
104 /* attribute list for save action */
105 var $attributes= array();
106 var $objectclasses= array();
107 var $new= TRUE;
108 var $saved_attributes= array();
110 /*! \brief plugin constructor
112 If 'dn' is set, the node loads the given 'dn' from LDAP
114 \param dn Distinguished name to initialize plugin from
115 \sa plugin()
116 */
117 function plugin ($config, $dn= NULL)
118 {
119 /* Configuration is fine, allways */
120 $this->config= $config;
121 $this->dn= $dn;
123 /* Handle new accounts, don't read information from LDAP */
124 if ($dn == "new"){
125 return;
126 }
128 /* Get LDAP descriptor */
129 $ldap= $this->config->get_ldap_link();
130 if ($dn != NULL){
132 /* Load data to 'attrs' and save 'dn' */
133 $ldap->cat ($dn);
134 $this->attrs= $ldap->fetch();
136 /* Copy needed attributes */
137 foreach ($this->attributes as $val){
138 $found= array_key_ics($val, $this->attrs);
139 if ($found != ""){
140 $this->$val= $this->attrs["$found"][0];
141 }
142 }
144 /* gosaUnitTag loading... */
145 if (isset($this->attrs['gosaUnitTag'][0])){
146 $this->gosaUnitTag= $this->attrs['gosaUnitTag'][0];
147 }
149 /* Set the template flag according to the existence of objectClass
150 gosaUserTemplate */
151 if (isset($this->attrs['objectClass'])){
152 if (in_array ("gosaUserTemplate", $this->attrs['objectClass'])){
153 $this->is_template= TRUE;
154 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,
155 "found", "Template check");
156 }
157 }
159 /* Is Account? */
160 error_reporting(0);
161 $found= TRUE;
162 foreach ($this->objectclasses as $obj){
163 if (preg_match('/top/i', $obj)){
164 continue;
165 }
166 if (!isset($this->attrs['objectClass']) || !in_array_ics ($obj, $this->attrs['objectClass'])){
167 $found= FALSE;
168 break;
169 }
170 }
171 error_reporting(E_ALL);
172 if ($found){
173 $this->is_account= TRUE;
174 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,
175 "found", "Object check");
176 }
178 /* Prepare saved attributes */
179 $this->saved_attributes= $this->attrs;
180 foreach ($this->saved_attributes as $index => $value){
181 if (preg_match('/^[0-9]+$/', $index)){
182 unset($this->saved_attributes[$index]);
183 continue;
184 }
185 if (!in_array($index, $this->attributes) && $index != "objectClass"){
186 unset($this->saved_attributes[$index]);
187 continue;
188 }
189 if ($this->saved_attributes[$index]["count"] == 1){
190 $tmp= $this->saved_attributes[$index][0];
191 unset($this->saved_attributes[$index]);
192 $this->saved_attributes[$index]= $tmp;
193 continue;
194 }
196 unset($this->saved_attributes["$index"]["count"]);
197 }
198 }
200 /* Save initial account state */
201 $this->initially_was_account= $this->is_account;
202 }
204 /*! \brief execute plugin
206 Generates the html output for this node
207 */
208 function execute()
209 {
210 # This one is empty currently. Fabian - please fill in the docu code
211 $_SESSION['current_class_for_help'] = get_class($this);
212 /* Reset Lock message POST/GET check array, to prevent perg_match errors*/
213 $_SESSION['LOCK_VARS_TO_USE'] =array();
214 }
216 /*! \brief execute plugin
217 Removes object from parent
218 */
219 function remove_from_parent()
220 {
221 /* include global link_info */
222 $ldap= $this->config->get_ldap_link();
224 /* Get current objectClasses in order to add the required ones */
225 $ldap->cat($this->dn);
226 $tmp= $ldap->fetch ();
227 if (isset($tmp['objectClass'])){
228 $oc= $tmp['objectClass'];
229 } else {
230 $oc= array("count" => 0);
231 }
233 /* Remove objectClasses from entry */
234 $ldap->cd($this->dn);
235 $this->attrs= array();
236 $this->attrs['objectClass']= array();
237 for ($i= 0; $i<$oc["count"]; $i++){
238 if (!in_array_ics($oc[$i], $this->objectclasses)){
239 $this->attrs['objectClass'][]= $oc[$i];
240 }
241 }
243 /* Unset attributes from entry */
244 foreach ($this->attributes as $val){
245 $this->attrs["$val"]= array();
246 }
248 /* Unset account info */
249 $this->is_account= FALSE;
251 /* Do not write in plugin base class, this must be done by
252 children, since there are normally additional attribs,
253 lists, etc. */
254 /*
255 $ldap->modify($this->attrs);
256 */
257 }
260 /* Save data to object */
261 function save_object()
262 {
263 /* Save values to object */
264 foreach ($this->attributes as $val){
265 if (chkacl ($this->acl, "$val") == "" && isset ($_POST["$val"])){
266 /* Check for modifications */
267 if (get_magic_quotes_gpc()) {
268 $data= stripcslashes($_POST["$val"]);
269 } else {
270 $data= $this->$val = $_POST["$val"];
271 }
272 if ($this->$val != $data){
273 $this->is_modified= TRUE;
274 }
276 /* Okay, how can I explain this fix ...
277 * In firefox, disabled option fields aren't selectable ... but in IE you can select these fileds.
278 * So IE posts these 'unselectable' option, with value = chr(194)
279 * chr(194) seems to be the in between the ...option> </option.. because there is no value=".." specified in these option fields
280 * This was added for W3c compliance, but now causes these ... ldap errors ...
281 * So we set these Fields to ""; a normal empty string, and we can check these values in plugin::check() again ...
282 */
283 if(isset($data[0]) && $data[0] == chr(194)) {
284 $data = "";
285 }
286 $this->$val= $data;
287 }
288 }
289 }
292 /* Save data to LDAP, depending on is_account we save or delete */
293 function save()
294 {
295 /* include global link_info */
296 $ldap= $this->config->get_ldap_link();
298 /* Start with empty array */
299 $this->attrs= array();
301 /* Get current objectClasses in order to add the required ones */
302 $ldap->cat($this->dn);
304 $tmp= $ldap->fetch ();
306 if (isset($tmp['objectClass'])){
307 $oc= $tmp["objectClass"];
308 $this->new= FALSE;
309 } else {
310 $oc= array("count" => 0);
311 $this->new= TRUE;
312 }
314 /* Load (minimum) attributes, add missing ones */
315 $this->attrs['objectClass']= $this->objectclasses;
316 for ($i= 0; $i<$oc["count"]; $i++){
317 if (!in_array_ics($oc[$i], $this->objectclasses)){
318 $this->attrs['objectClass'][]= $oc[$i];
319 }
320 }
322 /* Copy standard attributes */
323 foreach ($this->attributes as $val){
324 if ($this->$val != ""){
325 $this->attrs["$val"]= $this->$val;
326 } elseif (!$this->new) {
327 $this->attrs["$val"]= array();
328 }
329 }
331 }
334 function cleanup()
335 {
336 foreach ($this->attrs as $index => $value){
338 /* Convert arrays with one element to non arrays, if the saved
339 attributes are no array, too */
340 if (is_array($this->attrs[$index]) &&
341 count ($this->attrs[$index]) == 1 &&
342 isset($this->saved_attributes[$index]) &&
343 !is_array($this->saved_attributes[$index])){
345 $tmp= $this->attrs[$index][0];
346 $this->attrs[$index]= $tmp;
347 }
349 /* Remove emtpy arrays if they do not differ */
350 if (is_array($this->attrs[$index]) &&
351 count($this->attrs[$index]) == 0 &&
352 !isset($this->saved_attributes[$index])){
354 unset ($this->attrs[$index]);
355 continue;
356 }
358 /* Remove single attributes that do not differ */
359 if (!is_array($this->attrs[$index]) &&
360 isset($this->saved_attributes[$index]) &&
361 !is_array($this->saved_attributes[$index]) &&
362 $this->attrs[$index] == $this->saved_attributes[$index]){
364 unset ($this->attrs[$index]);
365 continue;
366 }
368 /* Remove arrays that do not differ */
369 if (is_array($this->attrs[$index]) &&
370 isset($this->saved_attributes[$index]) &&
371 is_array($this->saved_attributes[$index])){
373 if (!array_differs($this->attrs[$index],$this->saved_attributes[$index])){
374 unset ($this->attrs[$index]);
375 continue;
376 }
377 }
378 }
379 }
381 /* Check formular input */
382 function check()
383 {
384 $message= array();
386 /* Skip if we've no config object */
387 if (!isset($this->config)){
388 return $message;
389 }
391 /* Find hooks entries for this class */
392 $command= search_config($this->config->data['MENU'], get_class($this), "CHECK");
393 if ($command == "" && isset($this->config->data['TABS'])){
394 $command= search_config($this->config->data['TABS'], get_class($this), "CHECK");
395 }
397 if ($command != ""){
399 if (!check_command($command)){
400 $message[]= sprintf(_("Command '%s', specified as CHECK hook for plugin '%s' doesn't seem to exist."), $command,
401 get_class($this));
402 } else {
404 /* Generate "ldif" for check hook */
405 $ldif= "dn: $this->dn\n";
407 /* ... objectClasses */
408 foreach ($this->objectclasses as $oc){
409 $ldif.= "objectClass: $oc\n";
410 }
412 /* ... attributes */
413 foreach ($this->attributes as $attr){
414 if ($this->$attr == ""){
415 continue;
416 }
417 if (is_array($this->$attr)){
418 foreach ($this->$attr as $val){
419 $ldif.= "$attr: $val\n";
420 }
421 } else {
422 $ldif.= "$attr: ".$this->$attr."\n";
423 }
424 }
426 /* Append empty line */
427 $ldif.= "\n";
429 /* Feed "ldif" into hook and retrieve result*/
430 $descriptorspec = array( 0 => array("pipe", "r"), 1 => array("pipe", "w"), 2 => array("pipe", "w"));
431 $fh= proc_open($command, $descriptorspec, $pipes);
432 if (is_resource($fh)) {
433 fwrite ($pipes[0], $ldif);
434 fclose($pipes[0]);
436 $result= stream_get_contents($pipes[1]);
437 if ($result != ""){
438 $message[]= $result;
439 }
441 fclose($pipes[1]);
442 fclose($pipes[2]);
443 proc_close($fh);
444 }
445 }
447 }
449 return ($message);
450 }
452 /* Adapt from template, using 'dn' */
453 function adapt_from_template($dn)
454 {
455 /* Include global link_info */
456 $ldap= $this->config->get_ldap_link();
458 /* Load requested 'dn' to 'attrs' */
459 $ldap->cat ($dn);
460 $this->attrs= $ldap->fetch();
462 /* Walk through attributes */
463 foreach ($this->attributes as $val){
465 if (isset($this->attrs["$val"][0])){
467 /* If attribute is set, replace dynamic parts:
468 %sn, %givenName and %uid. Fill these in our local variables. */
469 $value= $this->attrs["$val"][0];
471 foreach (array("sn", "givenName", "uid") as $repl){
472 if (preg_match("/%$repl/i", $value)){
473 $value= preg_replace ("/%$repl/i", $this->parent->$repl, $value);
474 }
475 }
476 $this->$val= $value;
477 }
478 }
480 /* Is Account? */
481 $found= TRUE;
482 foreach ($this->objectclasses as $obj){
483 if (preg_match('/top/i', $obj)){
484 continue;
485 }
486 if (!in_array_ics ($obj, $this->attrs['objectClass'])){
487 $found= FALSE;
488 break;
489 }
490 }
491 if ($found){
492 $this->is_account= TRUE;
493 }
494 }
496 /* Indicate whether a password change is needed or not */
497 function password_change_needed()
498 {
499 return FALSE;
500 }
502 /* Show header message for tab dialogs */
503 function show_header($button_text, $text, $disabled= FALSE)
504 {
505 if ($disabled == TRUE){
506 $state= "disabled";
507 } else {
508 $state= "";
509 }
510 $display= "<table summary=\"\" width=\"100%\"><tr>\n<td colspan=2><p><b>$text</b></p>\n";
511 $display.= "<input type=submit value=\"$button_text\" name=\"modify_state\" ".
512 chkacl($this->acl, "all")." ".$state.
513 "><p class=\"seperator\"> </p></td></tr></table>";
515 return($display);
516 }
518 function postcreate($add_attrs= array())
519 {
520 /* Find postcreate entries for this class */
521 $command= search_config($this->config->data['MENU'], get_class($this), "POSTCREATE");
522 if ($command == "" && isset($this->config->data['TABS'])){
523 $command= search_config($this->config->data['TABS'], get_class($this), "POSTCREATE");
524 }
526 if ($command != ""){
527 /* Walk through attribute list */
528 foreach ($this->attributes as $attr){
529 if (!is_array($this->$attr)){
530 $command= preg_replace("/%$attr/", $this->$attr, $command);
531 }
532 }
533 $command= preg_replace("/%dn/", $this->dn, $command);
535 /* Additional attributes */
536 foreach ($add_attrs as $name => $value){
537 $command= preg_replace("/%$name/", $value, $command);
538 }
540 if (check_command($command)){
541 @DEBUG (DEBUG_SHELL, __LINE__, __FUNCTION__, __FILE__,
542 $command, "Execute");
544 exec($command);
545 } else {
546 $message= sprintf(_("Command '%s', specified as POSTCREATE for plugin '%s' doesn't seem to exist."), $command, get_class($this));
547 print_red ($message);
548 }
549 }
550 }
552 function postmodify($add_attrs= array())
553 {
554 /* Find postcreate entries for this class */
555 $command= search_config($this->config->data['MENU'], get_class($this), "POSTMODIFY");
556 if ($command == "" && isset($this->config->data['TABS'])){
557 $command= search_config($this->config->data['TABS'], get_class($this), "POSTMODIFY");
558 }
560 if ($command != ""){
561 /* Walk through attribute list */
562 foreach ($this->attributes as $attr){
563 if (!is_array($this->$attr)){
564 $command= preg_replace("/%$attr/", $this->$attr, $command);
565 }
566 }
567 $command= preg_replace("/%dn/", $this->dn, $command);
569 /* Additional attributes */
570 foreach ($add_attrs as $name => $value){
571 $command= preg_replace("/%$name/", $value, $command);
572 }
574 if (check_command($command)){
575 @DEBUG (DEBUG_SHELL, __LINE__, __FUNCTION__, __FILE__,
576 $command, "Execute");
578 exec($command);
579 } else {
580 $message= sprintf(_("Command '%s', specified as POSTMODIFY for plugin '%s' doesn't seem to exist."), $command, get_class($this));
581 print_red ($message);
582 }
583 }
584 }
586 function postremove($add_attrs= array())
587 {
588 /* Find postremove entries for this class */
589 $command= search_config($this->config->data['MENU'], get_class($this), "POSTREMOVE");
590 if ($command == "" && isset($this->config->data['TABS'])){
591 $command= search_config($this->config->data['TABS'], get_class($this), "POSTREMOVE");
592 }
594 if ($command != ""){
595 /* Walk through attribute list */
596 foreach ($this->attributes as $attr){
597 if (!is_array($this->$attr)){
598 $command= preg_replace("/%$attr/", $this->$attr, $command);
599 }
600 }
601 $command= preg_replace("/%dn/", $this->dn, $command);
603 /* Additional attributes */
604 foreach ($add_attrs as $name => $value){
605 $command= preg_replace("/%$name/", $value, $command);
606 }
608 if (check_command($command)){
609 @DEBUG (DEBUG_SHELL, __LINE__, __FUNCTION__, __FILE__,
610 $command, "Execute");
612 exec($command);
613 } else {
614 $message= sprintf(_("Command '%s', specified as POSTREMOVE for plugin '%s' doesn't seem to exist."), $command, get_class($this));
615 print_red ($message);
616 }
617 }
618 }
620 /* Create unique DN */
621 function create_unique_dn($attribute, $base)
622 {
623 $ldap= $this->config->get_ldap_link();
624 $base= preg_replace("/^,*/", "", $base);
626 /* Try to use plain entry first */
627 $dn= "$attribute=".$this->$attribute.",$base";
628 $ldap->cat ($dn, array('dn'));
629 if (!$ldap->fetch()){
630 return ($dn);
631 }
633 /* Look for additional attributes */
634 foreach ($this->attributes as $attr){
635 if ($attr == $attribute || $this->$attr == ""){
636 continue;
637 }
639 $dn= "$attribute=".$this->$attribute."+$attr=".$this->$attr.",$base";
640 $ldap->cat ($dn, array('dn'));
641 if (!$ldap->fetch()){
642 return ($dn);
643 }
644 }
646 /* None found */
647 return ("none");
648 }
650 function rebind($ldap, $referral)
651 {
652 $credentials= LDAP::get_credentials($referral, $this->config->current['REFERRAL']);
653 if (ldap_bind($ldap, $credentials['ADMIN'], $credentials['PASSWORD'])) {
654 $this->error = "Success";
655 $this->hascon=true;
656 $this->reconnect= true;
657 return (0);
658 } else {
659 $this->error = "Could not bind to " . $credentials['ADMIN'];
660 return NULL;
661 }
662 }
664 /* This is a workaround function. */
665 function copy($src_dn, $dst_dn)
666 {
667 /* Rename dn in possible object groups */
668 $ldap= $this->config->get_ldap_link();
669 $ldap->search('(&(objectClass=gosaGroupOfNames)(member='.$src_dn.'))',
670 array('cn'));
671 while ($attrs= $ldap->fetch()){
672 $og= new ogroup($this->config, $ldap->getDN());
673 unset($og->member[$src_dn]);
674 $og->member[$dst_dn]= $dst_dn;
675 $og->save ();
676 }
678 $ldap->cat($dst_dn);
679 $attrs= $ldap->fetch();
680 if (count($attrs)){
681 trigger_error("Trying to overwrite $dst_dn, which already exists.",
682 E_USER_WARNING);
683 return (FALSE);
684 }
686 $ldap->cat($src_dn);
687 $attrs= $ldap->fetch();
688 if (!count($attrs)){
689 trigger_error("Trying to move $src_dn, which does not seem to exist.",
690 E_USER_WARNING);
691 return (FALSE);
692 }
694 /* Grummble. This really sucks. PHP ldap doesn't support rdn stuff. */
695 $ds= ldap_connect($this->config->current['SERVER']);
696 ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
697 if (function_exists("ldap_set_rebind_proc") && isset($this->config->current['REFERRAL'])) {
698 ldap_set_rebind_proc($ds, array(&$this, "rebind"));
699 }
701 $r=ldap_bind($ds,$this->config->current['ADMIN'], $this->config->current['PASSWORD']);
702 error_reporting (0);
703 $sr=ldap_read($ds, $ldap->fix($src_dn), "objectClass=*");
705 /* Fill data from LDAP */
706 $new= array();
707 if ($sr) {
708 $ei=ldap_first_entry($ds, $sr);
709 if ($ei) {
710 foreach($attrs as $attr => $val){
711 if ($info = ldap_get_values_len($ds, $ei, $attr)){
712 for ($i= 0; $i<$info['count']; $i++){
713 if ($info['count'] == 1){
714 $new[$attr]= $info[$i];
715 } else {
716 $new[$attr][]= $info[$i];
717 }
718 }
719 }
720 }
721 }
722 }
724 /* close conncetion */
725 error_reporting (E_ALL);
726 ldap_unbind($ds);
728 /* Adapt naming attribute */
729 $dst_name= preg_replace("/^([^=]+)=.*$/", "\\1", $dst_dn);
730 $dst_val = preg_replace("/^[^=]+=([^,+]+).*,.*$/", "\\1", $dst_dn);
731 $new[$dst_name]= $dst_val;
733 /* Check if this is a department.
734 * If it is a dep. && there is a , override in his ou
735 * change \2C to , again, else this entry can't be saved ...
736 */
737 if((isset($new['ou'])) &&( preg_match("/\\\\2C/",$new['ou']))){
738 $new['ou'] = preg_replace("/\\\\2C/",",",$new['ou']);
739 }
741 /* Save copy */
742 $ldap->connect();
743 $ldap->cd($this->config->current['BASE']);
745 $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $dst_dn));
747 /* FAIvariable=.../..., cn=..
748 could not be saved, because the attribute FAIvariable was different to
749 the dn FAIvariable=..., cn=... */
750 if(in_array_ics("FAIdebconfInfo",$new['objectClass'])){
751 $new['FAIvariable'] = $ldap->fix($new['FAIvariable']);
752 }
753 $ldap->cd($dst_dn);
754 $ldap->add($new);
756 if ($ldap->error != "Success"){
757 trigger_error("Trying to save $dst_dn failed.",
758 E_USER_WARNING);
759 return(FALSE);
760 }
762 return (TRUE);
763 }
766 function move($src_dn, $dst_dn)
767 {
768 /* Copy source to destination */
769 if (!$this->copy($src_dn, $dst_dn)){
770 return (FALSE);
771 }
773 /* Delete source */
774 $ldap= $this->config->get_ldap_link();
775 $ldap->rmdir($src_dn);
776 if ($ldap->error != "Success"){
777 trigger_error("Trying to delete $src_dn failed.",
778 E_USER_WARNING);
779 return (FALSE);
780 }
782 return (TRUE);
783 }
786 /* Move/Rename complete trees */
787 function recursive_move($src_dn, $dst_dn)
788 {
789 /* Check if the destination entry exists */
790 $ldap= $this->config->get_ldap_link();
792 /* Check if destination exists - abort */
793 $ldap->cat($dst_dn, array('dn'));
794 if ($ldap->fetch()){
795 trigger_error("recursive_move $dst_dn already exists.",
796 E_USER_WARNING);
797 return (FALSE);
798 }
800 /* Perform a search for all objects to be moved */
801 $objects= array();
802 $ldap->cd($src_dn);
803 $ldap->search("(objectClass=*)", array("dn"));
804 while($attrs= $ldap->fetch()){
805 $dn= $attrs['dn'];
806 $objects[$dn]= strlen($dn);
807 }
809 /* Sort objects by indent level */
810 asort($objects);
811 reset($objects);
813 /* Copy objects from small to big indent levels by replacing src_dn by dst_dn */
814 foreach ($objects as $object => $len){
815 $src= $object;
816 $dst= preg_replace("/$src_dn$/", "$dst_dn", $object);
817 if (!$this->copy($src, $dst)){
818 return (FALSE);
819 }
820 }
822 /* Remove src_dn */
823 $ldap->cd($src_dn);
824 $ldap->recursive_remove();
825 return (TRUE);
826 }
829 function handle_post_events($mode, $add_attrs= array())
830 {
831 switch ($mode){
832 case "add":
833 $this->postcreate($add_attrs);
834 break;
836 case "modify":
837 $this->postmodify($add_attrs);
838 break;
840 case "remove":
841 $this->postremove($add_attrs);
842 break;
843 }
844 }
847 function saveCopyDialog(){
848 }
851 function getCopyDialog(){
852 return(array("string"=>"","status"=>""));
853 }
856 function PrepareForCopyPaste($source){
857 $todo = $this->attributes;
858 if(isset($this->CopyPasteVars)){
859 $todo = array_merge($todo,$this->CopyPasteVars);
860 }
861 $todo[] = "is_account";
862 foreach($todo as $var){
863 $this->$var = $source->$var;
864 }
865 }
868 function handle_object_tagging($dn= "", $tag= "", $show= false)
869 {
870 //FIXME: How to optimize this? We have at least two
871 // LDAP accesses per object. It would be a good
872 // idea to have it integrated.
874 /* No dn? Self-operation... */
875 if ($dn == ""){
876 $dn= $this->dn;
878 /* No tag? Find it yourself... */
879 if ($tag == ""){
880 $len= strlen($dn);
882 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, "No tag for $dn - looking for one...", "Tagging");
883 $relevant= array();
884 foreach ($this->config->adepartments as $key => $ntag){
886 /* This one is bigger than our dn, its not relevant... */
887 if ($len <= strlen($key)){
888 continue;
889 }
891 /* This one matches with the latter part. Break and don't fix this entry */
892 if (preg_match('/(^|,)'.normalizePreg($key).'$/', $dn)){
893 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, "DEBUG: Possibly relevant: $key", "Tagging");
894 $relevant[strlen($key)]= $ntag;
895 continue;
896 }
898 }
900 /* If we've some relevant tags to set, just get the longest one */
901 if (count($relevant)){
902 ksort($relevant);
903 $tmp= array_keys($relevant);
904 $idx= end($tmp);
905 $tag= $relevant[$idx];
906 $this->gosaUnitTag= $tag;
907 }
908 }
909 }
912 /* Set tag? */
913 if ($tag != ""){
914 /* Set objectclass and attribute */
915 $ldap= $this->config->get_ldap_link();
916 $ldap->cat($dn, array('gosaUnitTag', 'objectClass'));
917 $attrs= $ldap->fetch();
918 if(isset($attrs['gosaUnitTag'][0]) && $attrs['gosaUnitTag'][0] == $tag){
919 if ($show) {
920 echo sprintf(_("Object '%s' is already tagged"), @LDAP::fix($dn))."<br>";
921 flush();
922 }
923 return;
924 }
925 if (count($attrs)){
926 if ($show){
927 echo sprintf(_("Adding tag (%s) to object '%s'"), $tag, @LDAP::fix($dn))."<br>";
928 flush();
929 }
930 $nattrs= array("gosaUnitTag" => $this->gosaUnitTag);
931 $nattrs['objectClass']= array();
932 for ($i= 0; $i<$attrs['objectClass']['count']; $i++){
933 $oc= $attrs['objectClass'][$i];
934 if ($oc != "gosaAdministrativeUnitTag"){
935 $nattrs['objectClass'][]= $oc;
936 }
937 }
938 $nattrs['objectClass'][]= "gosaAdministrativeUnitTag";
939 $ldap->cd($dn);
940 $ldap->modify($nattrs);
941 show_ldap_error($ldap->get_error(), _("Handle object tagging failed"));
942 } else {
943 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, "Not tagging ($tag) $dn - seems to have moved away", "Tagging");
944 }
946 } else {
947 /* Remove objectclass and attribute */
948 $ldap= $this->config->get_ldap_link();
949 $ldap->cat($dn, array('gosaUnitTag', 'objectClass'));
950 $attrs= $ldap->fetch();
951 if (isset($attrs['objectClass']) && !in_array_ics("gosaAdministrativeUnitTag", $attrs['objectClass'])){
952 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, "$dn is not tagged", "Tagging");
953 return;
954 }
955 if (count($attrs)){
956 if ($show){
957 echo sprintf(_("Removing tag from object '%s'"), @LDAP::fix($dn))."<br>";
958 flush();
959 }
960 $nattrs= array("gosaUnitTag" => array());
961 $nattrs['objectClass']= array();
962 for ($i= 0; $i<$attrs['objectClass']['count']; $i++){
963 $oc= $attrs['objectClass'][$i];
964 if ($oc != "gosaAdministrativeUnitTag"){
965 $nattrs['objectClass'][]= $oc;
966 }
967 }
968 $ldap->cd($dn);
969 $ldap->modify($nattrs);
970 show_ldap_error($ldap->get_error(), _("Handle object tagging failed"));
971 } else {
972 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, "Not removing tag ($tag) $dn - seems to have moved away", "Tagging");
973 }
974 }
976 }
979 /* Add possibility to stop remove process */
980 function allow_remove()
981 {
982 $reason= "";
983 return $reason;
984 }
987 /* Create a snapshot of the current object */
988 function create_snapshot($type= "snapshot", $description= "")
989 {
990 $ldap= $this->config->get_ldap_link();
992 if ($ldap->dn_exists($this->$dn)){
993 $data= preg_replace('/^dn:.*\n/', '', $ldap->gen_ldif($this->dn));
994 $target= array();
995 $target['objectClass']= array("top", "gosaObjectSnapshot");
996 $target['gosaSnapshotData']= gzcompress($data, 6);
997 $target['gosaSnapshotType']= $type;
998 list($usec, $sec)= explode(" ", microtime());
999 $target['gosaShapshotTimestamp']= preg_replace("/\./", "", $sec.$usec);
1000 $target['gosaShapshotDN']= $this->dn;
1001 print_a($target);
1002 }
1003 }
1005 }
1006 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1007 ?>