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