1 <?php
3 class servDNSeditZoneEntries extends plugin
4 {
5 /* attribute list for save action */
6 var $ignore_account = TRUE;
7 var $attributes = array("cn");
8 var $objectclasses = array("whatever");
10 var $Devices = array();
12 var $zoneName = ""; // ZoneName of currently edited Zone
13 var $reverseName = ""; // ReverseZone of the currently edited Zone
15 var $RecordTypes = array(); // Possible record type.
17 var $disableDialog = false; // Dialog will be disabled, if this zone is new
18 var $cn;
20 function servDNSeditZoneEntries ($config,$dn, $zoneObject)
21 {
22 plugin::plugin ($config, $dn);
24 /* Initialise class
25 */
26 $this->RecordTypes = getDnsRecordTypes();
28 /* Remove nSRecord from listed types */
29 if(isset($this->RecordTypes['nSRecord'])){
30 unset($this->RecordTypes['nSRecord']);
31 }
32 /* Remove nSRecord from listed types */
33 if(isset($this->RecordTypes['pTRRecord'])){
34 unset($this->RecordTypes['pTRRecord']);
35 }
37 $this->dn = "zoneName=".getNameFromMix($zoneObject['InitialzoneName']).",".$dn;
38 $this->zoneName = $zoneObject['InitialzoneName'];
39 $this->reverseName = $zoneObject['InitialReverseZone'];
41 /* Get ldap connection
42 */
43 $ldap = $this->config->get_ldap_link();
44 $ldap->cd($this->config->current['BASE']);
46 /* Get zone content
47 */
48 $ldap->ls("(&(objectClass=dNSZone)(!(relativeDomainName=@)))",$this->dn,array("relativeDomainName"));
50 while($attrs = $ldap->fetch()){
51 $this->Devices[$attrs['relativeDomainName'][0]] = getDNSHostEntries($config,$attrs['relativeDomainName'][0],true);
52 $this->Devices[$attrs['relativeDomainName'][0]]['OrigCn'] = $attrs['relativeDomainName'][0];
53 }
55 $ldap->cat($this->dn,array("objectClass"));
57 $this->disableDialog = true;
58 if(count($this->Devices)|| $ldap->count()){
59 $this->disableDialog = false;
60 }
61 }
63 function execute()
64 {
65 plugin::execute();
67 /* Fill templating stuff */
68 $smarty= get_smarty();
69 $display= "";
71 $table = "";
72 foreach($this->Devices as $key => $dev){
73 $table .= $this->generateRecordConfigurationRow($key);
74 }
76 $smarty->assign("disableDialog",$this->disableDialog);
77 $smarty->assign("table",$table);;
78 $display.= $smarty->fetch(get_template_path('servDNSeditZoneEntries.tpl', TRUE));
79 return($display);
80 }
83 function save_object()
84 {
85 /* Check posts for operations ...
86 */
87 $once = true;
88 $ptr_updates = array();
89 foreach($_POST as $name => $value){
91 /* Add a new Record in given object
92 */
94 $tmp = preg_replace("/^.*_(.*)_.*$/","\\1",$name);
95 $tmp2 = split("\|",$tmp);
97 /* Add new host entry
98 */
99 if((preg_match("/^UserRecord_?/",$name)) && ($once)){
100 $once = false;
101 $entry = getDNSHostEntries($this->config,"",true);
102 $entry['exists'] = true;
103 $entry['zoneName'] = $this->zoneName;
104 $entry['RECORDS'][] = array("type" => "aRecord" , "value"=>"");
105 $this->Devices[_("New entry")] = $entry;
106 }
108 if(count($tmp2) != 2) continue;
110 $Name = base64_decode($tmp2[0]);
111 $RecordID = $tmp2[1];
113 /* Add new REcord
114 */
115 if((preg_match("/^AddRecord_/",$name)) && ($once)){
116 $once = false;
117 $this->Devices[$Name]['RECORDS'][] = $this->Devices[$Name]['RECORDS'][$RecordID];
118 }
120 /* Remove record from given dn
121 */
122 if((preg_match("/^RemoveRecord_/",$name)) && ($once)){
123 $once = false;
124 if(isset($this->Devices[$Name]['RECORDS'][$RecordID])){
125 unset($this->Devices[$Name]['RECORDS'][$RecordID]);
126 }
128 /* Check if there is at least one visible record. Else remove complete entry */
129 $visible = false;
130 foreach($this->Devices[$Name]['RECORDS'] as $rec){
131 if(in_array($rec['type'],$this->RecordTypes)){
132 $visible = true;
133 break;
134 }
135 }
136 if(!$visible && isset($this->Devices[$Name]['RECORDS'])){
137 $this->Devices[$Name]['RECORDS'] = array();
138 }
139 }
140 }
142 /* Possible attributes posted
143 */
144 foreach($_POST as $name => $value){
146 /* Extract informations out of post name
147 */
148 $tmp = preg_replace("/^.*_/","\\1",$name);
149 $tmp2 = split("\|",$tmp);
151 if(count($tmp2) != 2) continue;
153 $Name = base64_decode($tmp2[0]);
154 $RecordID = $tmp2[1];
156 /* Check for value change
157 */
158 if(preg_match("/ValueSelection_/",$name)){
159 if(isset($this->Devices[$Name]['RECORDS'][$RecordID])){
161 /* Update value */
162 $old = $this->Devices[$Name]['RECORDS'][$RecordID]['value'];
163 $this->Devices[$Name]['RECORDS'][$RecordID]['value'] = $value;
165 /* Handle pTRRecord */
166 if(!isset($ptr_updates[$Name]) && $this->Devices[$Name]['RECORDS'][$RecordID]['type'] == "aRecord"){
168 $found = false;
169 $ip = $value;
170 $match = preg_replace("/^[^\/]*+\//","",$this->reverseName);
171 $ip = preg_replace("/^".normalizePreg($match)."/","",$ip);
172 $ip = preg_replace("/^\./","",$ip);
174 foreach($this->Devices[$Name]['RECORDS'] as $key => $dev){
175 if($dev['type'] == "pTRRecord"){
176 $ptr_updates[$Name] = $Name;
177 $this->Devices[$Name]['RECORDS'][$key]['value'] = $ip;
178 $found = true;
179 break;
180 }
181 }
182 if(!$found){
183 $dev = array('type'=> 'pTRRecord', 'value' => $ip);
184 $this->Devices[$Name]['RECORDS'][] = $dev;
185 }
186 }
187 }
188 }
190 /* record type changed
191 */
192 if(preg_match("/^RecordTypeSelection_/",$name)){
193 if(isset($this->Devices[$Name]['RECORDS'][$RecordID])){
194 $this->Devices[$Name]['RECORDS'][$RecordID]['type'] = $value;
195 }
196 }
197 }
199 /* check for renamed entries
200 */
201 foreach($_POST as $name => $value){
203 /* Extract informations out of post name
204 */
205 $tmp = preg_replace("/^.*_/","\\1",$name);
206 $tmp2 = split("\|",$tmp);
208 if(count($tmp2) != 2) continue;
210 $Name = base64_decode($tmp2[0]);
211 $RecordID = $tmp2[1];
213 /* Host renamed
214 */
215 if(preg_match("/RenameHost_/",$name)){
216 if((isset($this->Devices[$Name])) && ($Name != $value)){
218 if(isset($this->Devices[$value])){
219 print_red(sprintf(_("Can't rename '%s' to '%s' there is already an entry with the same name in our zone editing dialog."),$Name,$value));
220 }else{
221 $this->Devices[$value] = $this->Devices[$Name];
222 unset($this->Devices[$Name]);
223 }
224 }
225 }
226 }
227 }
230 /* check something
231 */
232 function check()
233 {
234 /* Call common method to give check the hook */
235 $message= plugin::check();
237 $ldap = $this->config->get_ldap_link();
238 $ldap->cd($this->config->current['BASE']);
240 $names = array();
242 foreach($this->Devices as $DevName => $device){
244 /* skip checking empty attributes */
245 if(count($this->Devices[$DevName]['RECORDS']) == 0){
246 return;
247 }
249 /* Checking entry name
250 */
251 if(!preg_match("/^[a-z0-9_\.-]+$/i", $DevName) || (empty($DevName))){
252 $message[] = sprintf(_("Entry name '%s' contains invalid characters."), $DevName);
253 }
255 /* Renaming check for existing devices
256 */
257 if(isset($device['OrigCn']) && ($DevName != $device['OrigCn'] )){
258 $ldap->cd($this->dn);
259 $ldap->search("(relativeDomainName=".$DevName.")",array("relativeDomainName"));
260 if($ldap->count()){
261 $message[] = sprintf(_("Can not rename '%s' to '%s',the destination name already exists."),$device['OrigCn'],$DevName);
262 }
263 }elseif(!isset($device['OrigCn'])){
264 $ldap->cd($this->dn);
265 $ldap->search("(relativeDomainName=".$DevName.")",array("relativeDomainName"));
266 if($ldap->count()){
267 $message[] = sprintf(_("Can not create '%s',the destination name already exists."),$DevName);
268 }
269 }
271 /* Check names
272 */
273 if(!isset($names[$DevName])){
274 $names[$DevName] = "";
275 }else{
276 $message[] = sprintf(_("The name '%s' is used more than once."),$DevName);
277 }
279 /* Names should be written in lowercase
280 */
283 if(strtolower($DevName) != $DevName){
284 $message[] = sprintf(_("The host name '%s' should be written in lowercase."), $DevName);
285 }
287 /* Check records
288 */
289 $singleEntries = array("pTRRecord");
291 $tmp = array();
292 $tmp2 = array();
293 foreach($device['RECORDS'] as $Num => $Rec){
295 /* Check for multiple use of unique record types
296 */
297 if(in_array($Rec['type'],$singleEntries)){
298 if(!isset($tmp[$Rec['type']])){
299 $tmp[$Rec['type']] = "";
300 }else{
301 $message[] = sprintf(_("The record type '%s' is a unique type and can't be defined twice."),$Rec['type']);
302 }
303 }
305 /* Check for empty / duplicate entries in record array
306 */
307 if(empty($Rec['value'])){
308 $message[] = sprintf(_("There is an empty '%s' for host '%s'."),$Rec['type'],$DevName);
309 }
311 /* Check for duplicate record entries
312 */
313 if(!isset($tmp[$Rec['type']][$Rec['value']])){
314 $tmp[$Rec['type']][$Rec['value']] = "";
315 }else{
316 $message[] = sprintf(_("There is a duplicate entry in '%s' for '%s'."),$Rec['type'],$DevName);
317 }
318 }
319 }
320 return ($message);
321 }
323 function save()
324 {
325 if($this->disableDialog) return;
327 $todo = array();
330 /* Create todolist
331 */
332 foreach($this->Devices as $name => $dev){
333 if(isset($dev['OrigCn'])){
334 if(count($dev['RECORDS'])){
335 $todo[] = getDNSHostEntriesDiff($this->config,$dev['OrigCn'],$dev,$name);
336 }else{
337 $dev['exists'] = false;
338 $todo[] = getDNSHostEntriesDiff($this->config,$dev['OrigCn'],$dev,$name);
339 }
340 }else{
341 if(count($dev['RECORDS'])){
342 $todo[] = getDNSHostEntriesDiff($this->config,"",$dev,$name);
343 }else{
344 $dev['exists'] = false;
345 $todo[] = getDNSHostEntriesDiff($this->config,"",$dev,$name);
346 }
347 }
348 }
350 $tmp = array();
351 $tmp['del'] = array();
352 $tmp['add'] = array();
353 $tmp['move'] = array();
354 foreach($todo as $to){
355 foreach($to as $type => $entries){
356 $tmp[$type] = array_merge($tmp[$type],$entries);
357 }
358 }
360 /* Get ldap link
361 */
362 $ldap = $this->config->get_ldap_link();
363 $ldap->cd ($this->config->current['BASE']);
365 /* move follwoing entries
366 */
367 foreach($tmp['move'] as $src => $dst){
368 $this->recursive_move($src,$dst);
369 }
371 /* Delete dns */
372 foreach($tmp['del'] as $dn => $del){
373 $ldap->cd($dn);
374 $ldap->rmdir_recursive($dn);
375 }
377 /* Add || Update new DNS entries
378 */
379 foreach($tmp['add'] as $dn => $attrs){
380 $ldap->cd($dn);
381 $ldap->cat($dn, array('dn'));
382 if(count($ldap->fetch())){
383 $ldap->cd($dn);
384 $ldap->modify ($attrs);
385 }else{
386 $ldap->cd($dn);
387 $ldap->add($attrs);
388 }
389 }
390 }
393 /* Create html table out of given entry
394 */
395 function generateRecordConfigurationRow($objKey){
397 /* Get some basic informations
398 */
399 $obj = $this->Devices[$objKey];
400 $objectName = $objKey;
402 /* Abort if emtpy
403 */
404 if(count($obj['RECORDS']) == 0) return "";
406 /* Set title
407 */
408 $str= "<br>";
410 $hostNameOnce = true;
412 /* Walk through all defined records
413 */
414 $str.= "<table cellspacing='0' cellpadding='0'>";
415 foreach($obj['RECORDS'] as $id => $record){
417 /* Skip not selectable entries */
418 if(!isset($this->RecordTypes [$record['type']])) {
419 continue;
420 }
422 /* Create unique post name
423 */
424 $name = base64_encode($objKey)."|".$id;
426 $str .= "<tr><td style='width:170px;'>\n";
428 /* Only first host entry name should be editable
429 */
430 if($hostNameOnce){
431 $hostNameOnce = false;
432 $field1 ="<input style='width:250px;' type='text' name='RenameHost_".$name."' value='".$objectName."'>\n";
433 }else{
434 $field1 = "";
435 }
437 /* Create rest. Selectbox, icons ...
438 */
439 $field2 = $this->createRecordTypeSelection($record['type'],$name);
440 $field3 = "<input type='text' value='".$record['value']."' name='ValueSelection_".$name."' style='width:250px;'>";
441 $acl =" <input type='image' name='AddRecord_".$name."'
442 src='images/list_new.png' alt='"._("Add")."' title='"._("Add")."'>
443 <input type='image' name='RemoveRecord_".$name."'
444 src='images/edittrash.png' alt='"._("Remove")."' title='"._("Remove")."'>";
446 if($record['type'] == "cNAMERecord"){
447 $str .= "
448 <tr>
449 <td style='width:250px;text-align:right;'>".$field3."</td>
450 <td style='width:90px;'>".$field2."</td>
451 <td>".$objectName."</td>
452 <td>".$acl."</td>
453 </tr>";
454 }else{
455 $str .= "
456 <tr>
457 <td style='width:75px;text-align:right;'>".$field1."</td>
458 <td style='width:90px;'>".$field2."</td>
459 <td>".$field3."</td>
460 <td>".$acl."</td>
461 </tr>";
462 }
463 }
464 return($str);
465 }
468 /* Create selectbox with all available option types
469 */
470 function createRecordTypeSelection($id,$refID){
472 $str = "\n<select name='RecordTypeSelection_".$refID."' onChange='document.mainform.submit();'>";
473 foreach($this->RecordTypes as $type => $atr) {
474 if($id == $type){
475 $str .="\n<option value='".$type."' selected >".strtoupper(preg_replace("/record/i","",$type))."</option>";
476 }else{
477 $str .="\n<option value='".$type."'>".strtoupper(preg_replace("/record/i","",$type))."</option>";
478 }
479 }
480 $str.= "\n</select>";
481 return($str);
482 }
485 function remove_from_parent()
486 {
487 }
489 }
491 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
492 ?>