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= "";
91 var $skipTagging= FALSE;
93 /*!
94 \brief Used standard values
96 dn
97 */
98 var $dn= "";
99 var $uid= "";
100 var $sn= "";
101 var $givenName= "";
102 var $acl= "*none*";
103 var $dialog= FALSE;
105 /* attribute list for save action */
106 var $attributes= array();
107 var $objectclasses= array();
108 var $new= TRUE;
109 var $saved_attributes= array();
111 /* This can be set to render the tabulators in another stylesheet */
112 var $pl_notify= FALSE;
114 /*! \brief plugin constructor
116 If 'dn' is set, the node loads the given 'dn' from LDAP
118 \param dn Distinguished name to initialize plugin from
119 \sa plugin()
120 */
121 function plugin ($config, $dn= NULL, $parent= NULL)
122 {
123 /* Configuration is fine, allways */
124 $this->config= $config;
125 $this->dn= $dn;
127 /* Handle new accounts, don't read information from LDAP */
128 if ($dn == "new"){
129 return;
130 }
132 /* Get LDAP descriptor */
133 $ldap= $this->config->get_ldap_link();
134 if ($dn != NULL){
136 /* Load data to 'attrs' and save 'dn' */
137 if ($parent != NULL){
138 $this->attrs= $parent->attrs;
139 } else {
140 $ldap->cat ($dn);
141 $this->attrs= $ldap->fetch();
142 }
144 /* Copy needed attributes */
145 foreach ($this->attributes as $val){
146 $found= array_key_ics($val, $this->attrs);
147 if ($found != ""){
148 $this->$val= $this->attrs["$found"][0];
149 }
150 }
152 /* gosaUnitTag loading... */
153 if (isset($this->attrs['gosaUnitTag'][0])){
154 $this->gosaUnitTag= $this->attrs['gosaUnitTag'][0];
155 }
157 /* Set the template flag according to the existence of objectClass
158 gosaUserTemplate */
159 if (isset($this->attrs['objectClass'])){
160 if (in_array ("gosaUserTemplate", $this->attrs['objectClass'])){
161 $this->is_template= TRUE;
162 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,
163 "found", "Template check");
164 }
165 }
167 /* Is Account? */
168 error_reporting(0);
169 $found= TRUE;
170 foreach ($this->objectclasses as $obj){
171 if (preg_match('/top/i', $obj)){
172 continue;
173 }
174 if (!isset($this->attrs['objectClass']) || !in_array_ics ($obj, $this->attrs['objectClass'])){
175 $found= FALSE;
176 break;
177 }
178 }
179 error_reporting(E_ALL);
180 if ($found){
181 $this->is_account= TRUE;
182 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,
183 "found", "Object check");
184 }
186 /* Prepare saved attributes */
187 $this->saved_attributes= $this->attrs;
188 foreach ($this->saved_attributes as $index => $value){
189 if (preg_match('/^[0-9]+$/', $index)){
190 unset($this->saved_attributes[$index]);
191 continue;
192 }
193 if (!in_array($index, $this->attributes) && $index != "objectClass"){
194 unset($this->saved_attributes[$index]);
195 continue;
196 }
197 if ($this->saved_attributes[$index]["count"] == 1){
198 $tmp= $this->saved_attributes[$index][0];
199 unset($this->saved_attributes[$index]);
200 $this->saved_attributes[$index]= $tmp;
201 continue;
202 }
204 unset($this->saved_attributes["$index"]["count"]);
205 }
206 }
208 /* Save initial account state */
209 $this->initially_was_account= $this->is_account;
210 }
212 /*! \brief execute plugin
214 Generates the html output for this node
215 */
216 function execute()
217 {
218 # This one is empty currently. Fabian - please fill in the docu code
219 $_SESSION['current_class_for_help'] = get_class($this);
220 /* Reset Lock message POST/GET check array, to prevent perg_match errors*/
221 $_SESSION['LOCK_VARS_TO_USE'] =array();
222 }
224 /*! \brief execute plugin
225 Removes object from parent
226 */
227 function remove_from_parent()
228 {
229 /* include global link_info */
230 $ldap= $this->config->get_ldap_link();
232 /* Get current objectClasses in order to add the required ones */
233 $ldap->cat($this->dn);
234 $tmp= $ldap->fetch ();
235 if (isset($tmp['objectClass'])){
236 $oc= $tmp['objectClass'];
237 } else {
238 $oc= array("count" => 0);
239 }
241 /* Remove objectClasses from entry */
242 $ldap->cd($this->dn);
243 $this->attrs= array();
244 $this->attrs['objectClass']= array();
245 for ($i= 0; $i<$oc["count"]; $i++){
246 if (!in_array_ics($oc[$i], $this->objectclasses)){
247 $this->attrs['objectClass'][]= $oc[$i];
248 }
249 }
251 /* Unset attributes from entry */
252 foreach ($this->attributes as $val){
253 $this->attrs["$val"]= array();
254 }
256 /* Unset account info */
257 $this->is_account= FALSE;
259 /* Do not write in plugin base class, this must be done by
260 children, since there are normally additional attribs,
261 lists, etc. */
262 /*
263 $ldap->modify($this->attrs);
264 */
265 }
268 /* Save data to object */
269 function save_object()
270 {
271 /* Save values to object */
272 foreach ($this->attributes as $val){
273 if (chkacl ($this->acl, "$val") == "" && isset ($_POST["$val"])){
274 /* Check for modifications */
275 if ((get_magic_quotes_gpc()) && !is_array($_POST["$val"])) {
276 $data= stripcslashes($_POST["$val"]);
277 } else {
278 $data= $this->$val = $_POST["$val"];
279 }
280 if ($this->$val != $data){
281 $this->is_modified= TRUE;
282 }
284 /* Okay, how can I explain this fix ...
285 * In firefox, disabled option fields aren't selectable ... but in IE you can select these fileds.
286 * So IE posts these 'unselectable' option, with value = chr(194)
287 * chr(194) seems to be the in between the ...option> </option.. because there is no value=".." specified in these option fields
288 * This was added for W3c compliance, but now causes these ... ldap errors ...
289 * So we set these Fields to ""; a normal empty string, and we can check these values in plugin::check() again ...
290 */
291 if(isset($data[0]) && $data[0] == chr(194)) {
292 $data = "";
293 }
294 $this->$val= $data;
295 }
296 }
297 }
300 /* Save data to LDAP, depending on is_account we save or delete */
301 function save()
302 {
303 /* include global link_info */
304 $ldap= $this->config->get_ldap_link();
306 /* Start with empty array */
307 $this->attrs= array();
309 /* Get current objectClasses in order to add the required ones */
310 $ldap->cat($this->dn);
312 $tmp= $ldap->fetch ();
314 if (isset($tmp['objectClass'])){
315 $oc= $tmp["objectClass"];
316 $this->new= FALSE;
317 } else {
318 $oc= array("count" => 0);
319 $this->new= TRUE;
320 }
322 /* Load (minimum) attributes, add missing ones */
323 $this->attrs['objectClass']= $this->objectclasses;
324 for ($i= 0; $i<$oc["count"]; $i++){
325 if (!in_array_ics($oc[$i], $this->objectclasses)){
326 $this->attrs['objectClass'][]= $oc[$i];
327 }
328 }
330 /* Copy standard attributes */
331 foreach ($this->attributes as $val){
332 if ($this->$val != ""){
333 $this->attrs["$val"]= $this->$val;
334 } elseif (!$this->new) {
335 $this->attrs["$val"]= array();
336 }
337 }
339 /* Handle tagging */
340 $this->tag_attrs(&$this->attrs);
341 }
344 function cleanup()
345 {
346 foreach ($this->attrs as $index => $value){
348 /* Convert arrays with one element to non arrays, if the saved
349 attributes are no array, too */
350 if (is_array($this->attrs[$index]) &&
351 count ($this->attrs[$index]) == 1 &&
352 isset($this->saved_attributes[$index]) &&
353 !is_array($this->saved_attributes[$index])){
355 $tmp= $this->attrs[$index][0];
356 $this->attrs[$index]= $tmp;
357 }
359 /* Remove emtpy arrays if they do not differ */
360 if (is_array($this->attrs[$index]) &&
361 count($this->attrs[$index]) == 0 &&
362 !isset($this->saved_attributes[$index])){
364 unset ($this->attrs[$index]);
365 continue;
366 }
368 /* Remove single attributes that do not differ */
369 if (!is_array($this->attrs[$index]) &&
370 isset($this->saved_attributes[$index]) &&
371 !is_array($this->saved_attributes[$index]) &&
372 $this->attrs[$index] == $this->saved_attributes[$index]){
374 unset ($this->attrs[$index]);
375 continue;
376 }
378 /* Remove arrays that do not differ */
379 if (is_array($this->attrs[$index]) &&
380 isset($this->saved_attributes[$index]) &&
381 is_array($this->saved_attributes[$index])){
383 if (!array_differs($this->attrs[$index],$this->saved_attributes[$index])){
384 unset ($this->attrs[$index]);
385 continue;
386 }
387 }
388 }
390 /* Update saved attributes and ensure that next cleanups will be successful too */
391 foreach($this->attrs as $name => $value){
392 $this->saved_attributes[$name] = $value;
393 }
394 }
396 /* Check formular input */
397 function check()
398 {
399 $message= array();
401 /* Skip if we've no config object */
402 if (!isset($this->config)){
403 return $message;
404 }
406 /* Find hooks entries for this class */
407 $command= search_config($this->config->data['MENU'], get_class($this), "CHECK");
408 if ($command == "" && isset($this->config->data['TABS'])){
409 $command= search_config($this->config->data['TABS'], get_class($this), "CHECK");
410 }
412 if ($command != ""){
414 if (!check_command($command)){
415 $message[]= sprintf(_("Command '%s', specified as CHECK hook for plugin '%s' doesn't seem to exist."), $command,
416 get_class($this));
417 } else {
419 /* Generate "ldif" for check hook */
420 $ldif= "dn: $this->dn\n";
422 /* ... objectClasses */
423 foreach ($this->objectclasses as $oc){
424 $ldif.= "objectClass: $oc\n";
425 }
427 /* ... attributes */
428 foreach ($this->attributes as $attr){
429 if ($this->$attr == ""){
430 continue;
431 }
432 if (is_array($this->$attr)){
433 foreach ($this->$attr as $val){
434 $ldif.= "$attr: $val\n";
435 }
436 } else {
437 $ldif.= "$attr: ".$this->$attr."\n";
438 }
439 }
441 /* Append empty line */
442 $ldif.= "\n";
444 /* Feed "ldif" into hook and retrieve result*/
445 $descriptorspec = array( 0 => array("pipe", "r"), 1 => array("pipe", "w"), 2 => array("pipe", "w"));
446 $fh= proc_open($command, $descriptorspec, $pipes);
447 if (is_resource($fh)) {
448 fwrite ($pipes[0], $ldif);
449 fclose($pipes[0]);
451 $result= stream_get_contents($pipes[1]);
452 if ($result != ""){
453 $message[]= $result;
454 }
456 fclose($pipes[1]);
457 fclose($pipes[2]);
458 proc_close($fh);
459 }
460 }
462 }
464 return ($message);
465 }
467 /* Adapt from template, using 'dn' */
468 function adapt_from_template($dn)
469 {
470 /* Include global link_info */
471 $ldap= $this->config->get_ldap_link();
473 /* Load requested 'dn' to 'attrs' */
474 $ldap->cat ($dn);
475 $this->attrs= $ldap->fetch();
477 /* Walk through attributes */
478 foreach ($this->attributes as $val){
480 if (isset($this->attrs["$val"][0])){
482 /* If attribute is set, replace dynamic parts:
483 %sn, %givenName and %uid. Fill these in our local variables. */
484 $value= $this->attrs["$val"][0];
486 foreach (array("sn", "givenName", "uid") as $repl){
487 if (preg_match("/%$repl/i", $value)){
488 $value= preg_replace ("/%$repl/i", $this->parent->$repl, $value);
489 }
490 }
491 $this->$val= $value;
492 }
493 }
495 /* Is Account? */
496 $found= TRUE;
497 foreach ($this->objectclasses as $obj){
498 if (preg_match('/top/i', $obj)){
499 continue;
500 }
501 if (!in_array_ics ($obj, $this->attrs['objectClass'])){
502 $found= FALSE;
503 break;
504 }
505 }
506 if ($found){
507 $this->is_account= TRUE;
508 }
509 }
511 /* Indicate whether a password change is needed or not */
512 function password_change_needed()
513 {
514 return FALSE;
515 }
517 /* Show header message for tab dialogs */
518 function show_header($button_text, $text, $disabled= FALSE)
519 {
520 $state = "disabled";
521 if($this->is_account && $this->acl == "#all#"){
522 $state= "";
523 }elseif(!$this->is_account && chkacl($this->acl,"create") == ""){
524 $state= "";
525 }
527 if ($disabled == TRUE){
528 $state= "disabled";
529 }
531 $display= "<table summary=\"\" width=\"100%\"><tr>\n<td colspan=2><p><b>$text</b></p>\n";
532 $display.= "<input type=submit value=\"$button_text\" name=\"modify_state\" ".$state.">".
533 "<p class=\"seperator\"> </p></td></tr></table>";
535 return($display);
536 }
538 function postcreate($add_attrs= array())
539 {
540 /* Find postcreate entries for this class */
541 $command= search_config($this->config->data['MENU'], get_class($this), "POSTCREATE");
542 if ($command == "" && isset($this->config->data['TABS'])){
543 $command= search_config($this->config->data['TABS'], get_class($this), "POSTCREATE");
544 }
546 if ($command != ""){
548 /* Additional attributes */
549 foreach ($add_attrs as $name => $value){
550 $command= preg_replace("/%$name( |$)/", "$value ", $command);
551 }
553 /* Walk through attribute list */
554 foreach ($this->attributes as $attr){
555 if (!is_array($this->$attr)){
556 $command= preg_replace("/%$attr( |$)/", $this->$attr." ", $command);
557 }
558 }
559 $command= preg_replace("/%dn( |$)/", $this->dn." ", $command);
561 if (check_command($command)){
562 @DEBUG (DEBUG_SHELL, __LINE__, __FUNCTION__, __FILE__,
563 $command, "Execute");
565 exec($command);
566 } else {
567 $message= sprintf(_("Command '%s', specified as POSTCREATE for plugin '%s' doesn't seem to exist."), $command, get_class($this));
568 print_red ($message);
569 }
570 }
571 }
573 function postmodify($add_attrs= array())
574 {
575 /* Find postcreate entries for this class */
576 $command= search_config($this->config->data['MENU'], get_class($this), "POSTMODIFY");
577 if ($command == "" && isset($this->config->data['TABS'])){
578 $command= search_config($this->config->data['TABS'], get_class($this), "POSTMODIFY");
579 }
581 if ($command != ""){
583 /* Additional attributes */
584 foreach ($add_attrs as $name => $value){
585 $command= preg_replace("/%$name( |$)/", "$value ", $command);
586 }
588 /* Walk through attribute list */
589 foreach ($this->attributes as $attr){
590 if (!is_array($this->$attr)){
591 $command= preg_replace("/%$attr( |$)/", $this->$attr." ", $command);
592 }
593 }
594 $command= preg_replace("/%dn( |$)/", $this->dn." ", $command);
596 if (check_command($command)){
597 @DEBUG (DEBUG_SHELL, __LINE__, __FUNCTION__, __FILE__,
598 $command, "Execute");
600 exec($command);
601 } else {
602 $message= sprintf(_("Command '%s', specified as POSTMODIFY for plugin '%s' doesn't seem to exist."), $command, get_class($this));
603 print_red ($message);
604 }
605 }
606 }
608 function postremove($add_attrs= array())
609 {
610 /* Find postremove entries for this class */
611 $command= search_config($this->config->data['MENU'], get_class($this), "POSTREMOVE");
612 if ($command == "" && isset($this->config->data['TABS'])){
613 $command= search_config($this->config->data['TABS'], get_class($this), "POSTREMOVE");
614 }
616 if ($command != ""){
618 /* Additional attributes */
619 foreach ($add_attrs as $name => $value){
620 $command= preg_replace("/%$name( |$)/", "$value ", $command);
621 }
623 /* Walk through attribute list */
624 foreach ($this->attributes as $attr){
625 if (!is_array($this->$attr)){
626 $command= preg_replace("/%$attr( |$)/", $this->$attr." ", $command);
627 }
628 }
629 $command= preg_replace("/%dn( |$)/", $this->dn." ", $command);
631 if (check_command($command)){
632 @DEBUG (DEBUG_SHELL, __LINE__, __FUNCTION__, __FILE__,
633 $command, "Execute");
635 exec($command);
636 } else {
637 $message= sprintf(_("Command '%s', specified as POSTREMOVE for plugin '%s' doesn't seem to exist."), $command, get_class($this));
638 print_red ($message);
639 }
640 }
641 }
643 /* Create unique DN */
644 function create_unique_dn($attribute, $base)
645 {
646 $ldap= $this->config->get_ldap_link();
647 $base= preg_replace("/^,*/", "", $base);
649 /* Try to use plain entry first */
650 $dn= "$attribute=".$this->$attribute.",$base";
651 $ldap->cat ($dn, array('dn'));
652 if (!$ldap->fetch()){
653 return ($dn);
654 }
656 /* Look for additional attributes */
657 foreach ($this->attributes as $attr){
658 if ($attr == $attribute || $this->$attr == ""){
659 continue;
660 }
662 $dn= "$attribute=".$this->$attribute."+$attr=".$this->$attr.",$base";
663 $ldap->cat ($dn, array('dn'));
664 if (!$ldap->fetch()){
665 return ($dn);
666 }
667 }
669 /* None found */
670 return ("none");
671 }
673 function rebind($ldap, $referral)
674 {
675 $credentials= LDAP::get_credentials($referral, $this->config->current['REFERRAL']);
676 if (ldap_bind($ldap, $credentials['ADMIN'], $credentials['PASSWORD'])) {
677 $this->error = "Success";
678 $this->hascon=true;
679 $this->reconnect= true;
680 return (0);
681 } else {
682 $this->error = "Could not bind to " . $credentials['ADMIN'];
683 return NULL;
684 }
685 }
687 /* This is a workaround function. */
688 function copy($src_dn, $dst_dn)
689 {
690 /* Rename dn in possible object groups */
691 $ldap= $this->config->get_ldap_link();
692 $ldap->search('(&(objectClass=gosaGroupOfNames)(member='.@LDAP::prepare4filter($src_dn).'))',
693 array('cn'));
694 while ($attrs= $ldap->fetch()){
695 $og= new ogroup($this->config, $ldap->getDN());
696 unset($og->member[$src_dn]);
697 $og->member[$dst_dn]= $dst_dn;
698 $og->save ();
699 }
701 $ldap->cat($dst_dn);
702 $attrs= $ldap->fetch();
703 if (count($attrs)){
704 trigger_error("Trying to overwrite ".@LDAP::fix($dst_dn).", which already exists.",
705 E_USER_WARNING);
706 return (FALSE);
707 }
709 $ldap->cat($src_dn);
710 $attrs= $ldap->fetch();
711 if (!count($attrs)){
712 trigger_error("Trying to move ".@LDAP::fix($src_dn).", which does not seem to exist.",
713 E_USER_WARNING);
714 return (FALSE);
715 }
717 /* Grummble. This really sucks. PHP ldap doesn't support rdn stuff. */
718 $ds= ldap_connect($this->config->current['SERVER']);
719 ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
720 if (function_exists("ldap_set_rebind_proc") && isset($this->config->current['REFERRAL'])) {
721 ldap_set_rebind_proc($ds, array(&$this, "rebind"));
722 }
724 $r=ldap_bind($ds,$this->config->current['ADMIN'], $this->config->current['PASSWORD']);
725 error_reporting (0);
726 $sr=ldap_read($ds, @LDAP::fix($src_dn), "objectClass=*");
728 /* Fill data from LDAP */
729 $new= array();
730 if ($sr) {
731 $ei=ldap_first_entry($ds, $sr);
732 if ($ei) {
733 foreach($attrs as $attr => $val){
734 if ($info = ldap_get_values_len($ds, $ei, $attr)){
735 for ($i= 0; $i<$info['count']; $i++){
736 if ($info['count'] == 1){
737 $new[$attr]= $info[$i];
738 } else {
739 $new[$attr][]= $info[$i];
740 }
741 }
742 }
743 }
744 }
745 }
747 /* close conncetion */
748 error_reporting (E_ALL);
749 ldap_unbind($ds);
751 /* Adapt naming attribute */
752 $dst_name= preg_replace("/^([^=]+)=.*$/", "\\1", $dst_dn);
753 $dst_val = preg_replace("/^[^=]+=([^,+]+).*,.*$/", "\\1", $dst_dn);
754 $new[$dst_name]= @LDAP::fix($dst_val);
756 /* Check if this is a department.
757 * If it is a dep. && there is a , override in his ou
758 * change \2C to , again, else this entry can't be saved ...
759 */
760 if((isset($new['ou'])) &&( preg_match("/\\,/",$new['ou']))){
761 $new['ou'] = preg_replace("/\\\\,/",",",$new['ou']);
762 }
764 /* Save copy */
765 $ldap->connect();
766 $ldap->cd($this->config->current['BASE']);
768 $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $dst_dn));
770 /* FAIvariable=.../..., cn=..
771 could not be saved, because the attribute FAIvariable was different to
772 the dn FAIvariable=..., cn=... */
773 if(in_array_ics("FAIdebconfInfo",$new['objectClass'])){
774 $new['FAIvariable'] = $ldap->fix($new['FAIvariable']);
775 }
776 $ldap->cd($dst_dn);
777 $ldap->add($new);
779 if ($ldap->error != "Success"){
780 trigger_error("Trying to save $dst_dn failed.",
781 E_USER_WARNING);
782 return(FALSE);
783 }
785 return (TRUE);
786 }
789 function move($src_dn, $dst_dn)
790 {
792 /* Do not copy if only upper- lowercase has changed */
793 if(strtolower($src_dn) == strtolower($dst_dn)){
794 return(TRUE);
795 }
797 /* Copy source to destination */
798 if (!$this->copy($src_dn, $dst_dn)){
799 return (FALSE);
800 }
802 /* Delete source */
803 $ldap= $this->config->get_ldap_link();
804 $ldap->rmdir($src_dn);
805 if ($ldap->error != "Success"){
806 trigger_error("Trying to delete $src_dn failed.",
807 E_USER_WARNING);
808 return (FALSE);
809 }
811 return (TRUE);
812 }
815 /* Move/Rename complete trees */
816 function recursive_move($src_dn, $dst_dn)
817 {
818 /* Check if the destination entry exists */
819 $ldap= $this->config->get_ldap_link();
821 /* Check if destination exists - abort */
822 $ldap->cat($dst_dn, array('dn'));
823 if ($ldap->fetch()){
824 trigger_error("recursive_move $dst_dn already exists.",
825 E_USER_WARNING);
826 return (FALSE);
827 }
829 /* Perform a search for all objects to be moved */
830 $objects= array();
831 $ldap->cd($src_dn);
832 $ldap->search("(objectClass=*)", array("dn"));
833 while($attrs= $ldap->fetch()){
834 $dn= $attrs['dn'];
835 $objects[$dn]= strlen($dn);
836 }
838 /* Sort objects by indent level */
839 asort($objects);
840 reset($objects);
842 /* Copy objects from small to big indent levels by replacing src_dn by dst_dn */
843 foreach ($objects as $object => $len){
844 $src= $object;
845 $dst= preg_replace("/$src_dn$/", "$dst_dn", $object);
846 if (!$this->copy($src, $dst)){
847 return (FALSE);
848 }
849 }
851 /* Remove src_dn */
852 $ldap->cd($src_dn);
853 $ldap->recursive_remove();
854 return (TRUE);
855 }
858 function handle_post_events($mode, $add_attrs= array())
859 {
860 switch ($mode){
861 case "add":
862 $this->postcreate($add_attrs);
863 break;
865 case "modify":
866 $this->postmodify($add_attrs);
867 break;
869 case "remove":
870 $this->postremove($add_attrs);
871 break;
872 }
873 }
876 function saveCopyDialog(){
877 }
880 function getCopyDialog(){
881 return(array("string"=>"","status"=>""));
882 }
885 function PrepareForCopyPaste($source){
886 $todo = $this->attributes;
887 if(isset($this->CopyPasteVars)){
888 $todo = array_merge($todo,$this->CopyPasteVars);
889 }
890 $todo[] = "is_account";
891 foreach($todo as $var){
892 if (isset($source->$var)){
893 $this->$var= $source->$var;
894 }
895 }
896 }
899 function tag_attrs($at, $dn= "", $tag= "", $show= false)
900 {
901 /* Skip tagging?
902 If this is called from departmentGeneric, we have to skip this
903 tagging procedure.
904 */
905 if($this->skipTagging){
906 return;
907 }
909 /* No dn? Self-operation... */
910 if ($dn == ""){
911 $dn= $this->dn;
913 /* No tag? Find it yourself... */
914 if ($tag == ""){
915 $len= strlen($dn);
917 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, "No tag for $dn - looking for one...", "Tagging");
918 $relevant= array();
919 foreach ($this->config->adepartments as $key => $ntag){
921 /* This one is bigger than our dn, its not relevant... */
922 if ($len <= strlen($key)){
923 continue;
924 }
926 /* This one matches with the latter part. Break and don't fix this entry */
927 if (preg_match('/(^|,)'.normalizePreg($key).'$/', $dn)){
928 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, "DEBUG: Possibly relevant: $key", "Tagging");
929 $relevant[strlen($key)]= $ntag;
930 continue;
931 }
933 }
935 /* If we've some relevant tags to set, just get the longest one */
936 if (count($relevant)){
937 ksort($relevant);
938 $tmp= array_keys($relevant);
939 $idx= end($tmp);
940 $tag= $relevant[$idx];
941 $this->gosaUnitTag= $tag;
942 }
943 }
944 }
946 /* Remove tags that may already be here... */
947 remove_objectClass("gosaAdministrativeUnitTag", &$at);
948 if (isset($at['gosaUnitTag'])){
949 unset($at['gosaUnitTag']);
950 }
952 /* Set tag? */
953 if ($tag != ""){
954 add_objectClass("gosaAdministrativeUnitTag", &$at);
955 $at['gosaUnitTag']= $tag;
956 }
957 }
960 function handle_object_tagging($dn= "", $tag= "", $show= false)
961 {
962 //FIXME: How to optimize this? We have at least two
963 // LDAP accesses per object. It would be a good
964 // idea to have it integrated.
966 /* No dn? Self-operation... */
967 if ($dn == ""){
968 $dn= $this->dn;
970 /* No tag? Find it yourself... */
971 if ($tag == ""){
972 $len= strlen($dn);
974 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, "No tag for $dn - looking for one...", "Tagging");
975 $relevant= array();
976 foreach ($this->config->adepartments as $key => $ntag){
978 /* This one is bigger than our dn, its not relevant... */
979 if ($len <= strlen($key)){
980 continue;
981 }
983 /* This one matches with the latter part. Break and don't fix this entry */
984 if (preg_match('/(^|,)'.normalizePreg($key).'$/', $dn)){
985 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, "DEBUG: Possibly relevant: $key", "Tagging");
986 $relevant[strlen($key)]= $ntag;
987 continue;
988 }
990 }
992 /* If we've some relevant tags to set, just get the longest one */
993 if (count($relevant)){
994 ksort($relevant);
995 $tmp= array_keys($relevant);
996 $idx= end($tmp);
997 $tag= $relevant[$idx];
998 $this->gosaUnitTag= $tag;
999 }
1000 }
1001 }
1004 /* Set tag? */
1005 if ($tag != ""){
1006 /* Set objectclass and attribute */
1007 $ldap= $this->config->get_ldap_link();
1008 $ldap->cat($dn, array('gosaUnitTag', 'objectClass'));
1009 $attrs= $ldap->fetch();
1010 if(isset($attrs['gosaUnitTag'][0]) && $attrs['gosaUnitTag'][0] == $tag){
1011 if ($show) {
1012 echo sprintf(_("Object '%s' is already tagged"), @LDAP::fix($dn))."<br>";
1013 flush();
1014 }
1015 return;
1016 }
1017 if (count($attrs)){
1018 if ($show){
1019 echo sprintf(_("Adding tag (%s) to object '%s'"), $tag, @LDAP::fix($dn))."<br>";
1020 flush();
1021 }
1022 $nattrs= array("gosaUnitTag" => $tag);
1023 $nattrs['objectClass']= array();
1024 for ($i= 0; $i<$attrs['objectClass']['count']; $i++){
1025 $oc= $attrs['objectClass'][$i];
1026 if ($oc != "gosaAdministrativeUnitTag"){
1027 $nattrs['objectClass'][]= $oc;
1028 }
1029 }
1030 $nattrs['objectClass'][]= "gosaAdministrativeUnitTag";
1031 $ldap->cd($dn);
1032 $ldap->modify($nattrs);
1033 show_ldap_error($ldap->get_error(), _("Handle object tagging failed"));
1034 } else {
1035 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, "Not tagging ($tag) $dn - seems to have moved away", "Tagging");
1036 }
1038 } else {
1039 /* Remove objectclass and attribute */
1040 $ldap= $this->config->get_ldap_link();
1041 $ldap->cat($dn, array('gosaUnitTag', 'objectClass'));
1042 $attrs= $ldap->fetch();
1043 if (isset($attrs['objectClass']) && !in_array_ics("gosaAdministrativeUnitTag", $attrs['objectClass'])){
1044 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, "$dn is not tagged", "Tagging");
1045 return;
1046 }
1047 if (count($attrs)){
1048 if ($show){
1049 echo sprintf(_("Removing tag from object '%s'"), @LDAP::fix($dn))."<br>";
1050 flush();
1051 }
1052 $nattrs= array("gosaUnitTag" => array());
1053 $nattrs['objectClass']= array();
1054 for ($i= 0; $i<$attrs['objectClass']['count']; $i++){
1055 $oc= $attrs['objectClass'][$i];
1056 if ($oc != "gosaAdministrativeUnitTag"){
1057 $nattrs['objectClass'][]= $oc;
1058 }
1059 }
1060 $ldap->cd($dn);
1061 $ldap->modify($nattrs);
1062 show_ldap_error($ldap->get_error(), _("Handle object tagging failed"));
1063 } else {
1064 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, "Not removing tag ($tag) $dn - seems to have moved away", "Tagging");
1065 }
1066 }
1068 }
1071 /* Add possibility to stop remove process */
1072 function allow_remove()
1073 {
1074 $reason= "";
1075 return $reason;
1076 }
1078 }
1079 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1080 ?>