~ubuntu-branches/ubuntu/vivid/gosa/vivid

« back to all changes in this revision

Viewing changes to dns/admin/systems/services/dns/class_servDNSeditZone.inc

Tags: 2.7.1-1
* New upstream release
* Updated packaging to not include smarty (Closes: #620489)
* Fixed case of POSIX (Closes: #620486)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?php
 
2
 
 
3
class servdnseditZone extends plugin
 
4
{
 
5
    /* attribute list for save action */
 
6
    var $ignore_account= TRUE;
 
7
    var $attributes     = array("zoneName","ReverseZone","dNSClass",
 
8
            "sOAprimary","sOAmail","sOAserial","sOArefresh","sOAretry","sOAexpire","sOAttl"); 
 
9
    var $objectclasses  = array("whatever");
 
10
 
 
11
    var $RecordTypes              = array();
 
12
 
 
13
    var $ReverseZone              = "";
 
14
    var $zoneName                 = "";
 
15
    var $dNSClass                 = "IN";
 
16
 
 
17
    var $sOAprimary               = "";
 
18
    var $sOAmail                  = "";
 
19
    var $sOAserial                = "";
 
20
    var $sOArefresh               = "3600";
 
21
    var $sOAretry                 = "1800";
 
22
    var $sOAexpire                = "720000";
 
23
    var $sOAttl                   = "6400";
 
24
 
 
25
    var $Records                  = array();
 
26
    var $mXRecords                = array();
 
27
 
 
28
    var $OldZoneName              = ""; // To detect changes made with this edit
 
29
    var $OldReverseZone           = "";
 
30
 
 
31
    var $InitialReverseZone       = "";
 
32
    var $InitialzoneName          = "";
 
33
    var $NetworkClass                = "A" ; // One out of A,B,C
 
34
 
 
35
    var $dialog                   = false;
 
36
 
 
37
    var $zoneEditor               = NULL;
 
38
 
 
39
    var $isNew                    = true;
 
40
 
 
41
    var $ZoneObject               = array();
 
42
    var $Zone_is_used             = FALSE;
 
43
 
 
44
    function servdnseditZone (&$config, $dn= NULL,$attrs = array())
 
45
    {
 
46
        plugin::plugin ($config, $dn);
 
47
 
 
48
        /* All types with required attrs */
 
49
        $this->RecordTypes = DNS::getDnsRecordTypes(true); 
 
50
 
 
51
        if(!count($attrs)){
 
52
            $this->OldZoneName        = "";
 
53
            $this->OldReverseZone     = "";
 
54
            $this->isNew              = true;
 
55
            $this->sOAserial          = date("Ymd")."1";
 
56
 
 
57
            $this->InitialzoneName    = "";//$attrs['InitialzoneName'];
 
58
            $this->InitialReverseZone = "";//$attrs['InitialReverseZone'];
 
59
        }else{
 
60
            $this->ZoneObject         = $attrs;
 
61
 
 
62
            if(isset($attrs['zoneEditor'])){
 
63
                $this->zoneEditor         = $attrs['zoneEditor'];
 
64
            }
 
65
            $this->OldZoneName        = $attrs['zoneName'];
 
66
            $this->OldReverseZone     = $attrs['ReverseZone'];
 
67
 
 
68
            $this->InitialzoneName    = $attrs['InitialzoneName'];
 
69
            $this->InitialReverseZone = $attrs['InitialReverseZone'];
 
70
 
 
71
            $this->isNew                  = false;
 
72
 
 
73
            foreach($this->attributes as $value){
 
74
                $this->$value = $attrs[$value];
 
75
            }
 
76
 
 
77
            $this->sOAmail            = preg_replace("/\./","@",$this->sOAmail,1);
 
78
            $this->sOAmail            = preg_replace("/\.$/","",$this->sOAmail);
 
79
            $this->sOAprimary         = preg_replace("/\.$/","",$this->sOAprimary);
 
80
            $this->zoneName           = preg_replace("/\.$/","",$this->zoneName);
 
81
 
 
82
            if(isset($attrs['RECORDS'])){
 
83
                $this->Records = $attrs['RECORDS']; 
 
84
 
 
85
                $tmp2 = array();
 
86
                $usedPrio = array();
 
87
                foreach($this->Records as $key => $rec){
 
88
                    if($rec['type'] == "mXRecord"){
 
89
                        $tmp = explode(" ",$rec['value']);
 
90
                        $rec['value'] = $rec['value'];
 
91
                        $tmp2[$tmp[0]] = $rec;
 
92
                        unset($this->Records[$key]);
 
93
                    }
 
94
                    if($rec['type'] == "nSRecord" && preg_match("/".preg_quote($this->sOAprimary, '/')."/",$rec['value'])){
 
95
                        unset($this->Records[$key]);
 
96
                    }
 
97
                }
 
98
                if(count($tmp2) != 0){
 
99
                    reset($tmp2);
 
100
                    ksort($tmp2);
 
101
                }
 
102
                $this->mXRecords = $tmp2;
 
103
            }else{
 
104
                $this->mXRecords  = array();
 
105
                $this->Records    = array();
 
106
            }
 
107
 
 
108
            $str = date("Ymd");
 
109
            if(preg_match("/^".$str."/",$this->sOAserial)){
 
110
                $this->sOAserial = $this->sOAserial + 1;
 
111
            }else{
 
112
                $this->sOAserial = date("Ymd")."01";
 
113
            }
 
114
 
 
115
            /* Check if this used, in this case disable forward and reverse configuration */
 
116
            $tmp = $this->getUsedZoneNames();
 
117
            $this->Zone_is_used = FALSE;
 
118
            if(isset($tmp[DNS::FlipIp($this->InitialReverseZone).".in-addr.arpa."])){
 
119
                $this->Zone_is_used = TRUE;
 
120
            }
 
121
        }
 
122
 
 
123
        /* Detect Network class */
 
124
        if(!empty($this->ReverseZone)){
 
125
 
 
126
            $dots = count(explode(".",$this->ReverseZone));
 
127
            if($dots == 1){
 
128
                $this->NetworkClass = "A";  
 
129
                $this->ReverseZone .= ".0.0.0"; 
 
130
            }elseif($dots == 2){
 
131
                $this->NetworkClass = "B";  
 
132
                $this->ReverseZone .= ".0.0"; 
 
133
            }else{
 
134
                $this->NetworkClass = "C";  
 
135
                $this->ReverseZone .= ".0"; 
 
136
            }
 
137
        }
 
138
 
 
139
        // Prepare lists
 
140
        $this->mxList = new sortableListing();
 
141
        $this->mxList->setDeleteable(true);
 
142
        $this->mxList->setInstantDelete(true);
 
143
        $this->mxList->setEditable(false);
 
144
        $this->mxList->setWidth("100%");
 
145
        $this->mxList->setHeight("100px");
 
146
        $this->mxList->setHeader(array(_("Priority"),_("Record")));
 
147
        $this->mxList->setColspecs(array('40px','*','20px'));
 
148
        $this->mxList->setDefaultSortColumn(0);
 
149
 
 
150
    }
 
151
 
 
152
 
 
153
    function execute()
 
154
    {
 
155
        /* Call parent execute */
 
156
        plugin::execute();
 
157
 
 
158
        /* Fill templating stuff */
 
159
        $smarty= get_smarty();
 
160
 
 
161
        $smarty->assign("Zone_is_used",$this->Zone_is_used);
 
162
        $ui = get_userinfo();
 
163
 
 
164
        /* Assign ACLs 
 
165
           All acls are defined in our parent class.
 
166
         */
 
167
        $tmp = $this->parent->plInfo();
 
168
        foreach($tmp['plProvidedAcls'] as $name => $desc){
 
169
            $smarty->assign($name."ACL", $this->parent->getacl($name));
 
170
        }
 
171
 
 
172
        $display= "";
 
173
 
 
174
        /* Open Zone Entry Edit Dialog
 
175
         */
 
176
        if(!count($this->ZoneObject)){
 
177
            $smarty->assign("AllowZoneEdit" , false);
 
178
        }else{
 
179
            $smarty->assign("AllowZoneEdit" , true);
 
180
 
 
181
            if(isset($_POST['EditZoneEntries']) && $this->parent->acl_is_readable("zoneEditor")){
 
182
                if($this->zoneEditor == NULL){
 
183
                    $this->zoneEditor= new servDNSeditZoneEntries($this->config,$this->dn,$this->ZoneObject); 
 
184
                    $this->zoneEditor->acl = $this->parent->getacl("zoneEditor");
 
185
                    $this->zoneEditor->parent = $this;
 
186
                }
 
187
                $this->dialog = $this->zoneEditor;
 
188
            }
 
189
        }
 
190
 
 
191
        /* Save Zone Entry Edit Dialog
 
192
         */
 
193
        if(isset($_POST['SaveZoneEntryChanges'])){
 
194
            $this->dialog->save_object();
 
195
            if(count($this->dialog->check())){
 
196
                $msgs = $this->dialog->check();
 
197
                foreach($msgs as $msg){
 
198
                    msg_dialog::display(_("Error"), $msg , ERROR_DIALOG);
 
199
                }
 
200
            }else{
 
201
                $this->zoneEditor = clone $this->dialog;
 
202
                $this->dialog = FALSE;
 
203
#       $rev = DNS::FlipIp(DNS::getNameFromMix($this->InitialReverseZone)).".in-addr.arpa";
 
204
#       $for = DNS::getNameFromMix($this->InitialzoneName);
 
205
#      
 
206
#       $this->parent->handle_post_events("modify",array("dn" => $this->dn,"zoneName" => $rev));
 
207
#       $this->parent->handle_post_events("modify",array("dn" => $this->dn,"zoneName" => $for));
 
208
#       $this->dialog = false;
 
209
            }
 
210
        }
 
211
 
 
212
        /* Cancel Zone Entrie Edit Dialog
 
213
         */
 
214
        if(isset($_POST['CancelZoneEntryChanges'])){
 
215
            $this->dialog = false;
 
216
        }
 
217
 
 
218
        /* Display any type of open dialogs 
 
219
         */
 
220
        if(is_object($this->dialog)){
 
221
            $this->dialog->save_object();
 
222
            return($this->dialog->execute());
 
223
        }
 
224
 
 
225
 
 
226
        $this->mxList->save_object();
 
227
        $action = $this->mxList->getAction();
 
228
        if($action['action'] == 'delete' || $action['action'] == 'reorder'){
 
229
            $this->mXRecords = $this->mxList->getMaintainedData();
 
230
        }
 
231
 
 
232
        if($this->parent->acl_is_writeable("mXRecord")){
 
233
            if((isset($_POST['AddMXRecord'])) && (!empty($_POST['StrMXRecord']))){
 
234
                $rec = get_post('StrMXRecord');
 
235
                if(preg_match("/^[0-9]* /", $rec) && count(preg_split("/ /", $rec)) == 2){
 
236
                    list($prio,$value) = preg_split("/ /", $rec);
 
237
                    $this->mXRecords[$prio] = array("type"=>"mXRecord","value"=>trim($rec));
 
238
                }else{
 
239
                    msg_dialog::display(_("Warning"), msgPool::invalid(_("MxRecord"), "","", "20 mx.record.entry"), WARNING_DIALOG);
 
240
                }
 
241
            }
 
242
 
 
243
            /* Handle Post events */
 
244
            $once = true;
 
245
            foreach($_POST as $name => $value){
 
246
 
 
247
                /* Delete record if requested */
 
248
                if((preg_match("/RemoveRecord_/",$name))&&($once)){
 
249
                    $once = false;
 
250
                    $id= preg_replace("/RemoveRecord_/","",$name);
 
251
                    unset($this->Records[$id]);
 
252
                }
 
253
            }
 
254
 
 
255
            /* Add new Zonerecord */
 
256
            if(isset($_POST['AddNewRecord'])){
 
257
                $this->Records[] = array("type"=>"aRecord","value"=>"");
 
258
            }
 
259
        }
 
260
 
 
261
        /* Fill in values */
 
262
        foreach($this->attributes as $name){
 
263
            $smarty->assign($name, set_post($this->$name));
 
264
        }
 
265
 
 
266
 
 
267
        $this->mxList->setAcl($this->parent->getacl("mXRecord"));
 
268
        $lData = array();
 
269
        foreach($this->mXRecords as $key => $record){
 
270
            list($prio, $value) = preg_split("/ /", $record['value']);
 
271
            $lData[$prio] = array('data'=>array($prio, $value));
 
272
        }
 
273
        $this->mxList->setListData($this->mXRecords, $lData);
 
274
        $this->mxList->update();
 
275
 
 
276
        /* Assign records list */
 
277
        $smarty->assign("NotNew", false);
 
278
        $smarty->assign("Mxrecords",     $this->mxList->render());
 
279
        $smarty->assign("records"  ,     $this->generateRecordsList());
 
280
        $smarty->assign("NetworkClass",  set_post($this->NetworkClass));
 
281
        $smarty->assign("NetworkClasses",  array("A"=>"255.0.0.0 (Class A)","B"=>"255.255.0.0 (Class B)","C"=>"255.255.255.0 (Class C)"));
 
282
 
 
283
        /* Display tempalte */
 
284
        $display.= $smarty->fetch(get_template_path('servdnseditzone.tpl', TRUE, dirname(__FILE__)));
 
285
        return($display);
 
286
    }
 
287
 
 
288
    function remove_from_parent()
 
289
    {
 
290
    }
 
291
 
 
292
    /* Save data to object */
 
293
    function save_object()
 
294
    {
 
295
        plugin::save_object();
 
296
 
 
297
        if(!is_object($this->parent)) return;
 
298
 
 
299
        if($this->parent->acl_is_writeable("zoneRecords")){
 
300
            foreach($this->Records as $id => $value){  
 
301
                if(isset($_POST['RecordTypeSelectedFor_'.$id])){
 
302
                    $this->Records[$id]['type'] = get_post('RecordTypeSelectedFor_'.$id);
 
303
                }
 
304
                if(isset($_POST['RecordValue_'.$id])){
 
305
                    $this->Records[$id]['value'] = get_post('RecordValue_'.$id);
 
306
                }
 
307
            }
 
308
        }
 
309
        if(isset($_POST['NetworkClass']) && !$this->Zone_is_used && $this->parent->acl_is_writeable("NetworkClass")){
 
310
            $this->NetworkClass = get_post('NetworkClass');
 
311
        }
 
312
    }
 
313
 
 
314
 
 
315
    /* Check supplied data */
 
316
    function check()
 
317
    {
 
318
        /* Call common method to give check the hook */
 
319
        $message= plugin::check();
 
320
 
 
321
        /* Check if zoneName is already in use */
 
322
        $usedZones = $this->getUsedZoneNames();
 
323
        if($this->OldZoneName == "" && !empty($this->zoneName)){
 
324
            $tmp = trim($this->zoneName,".").".";
 
325
            if(isset($usedZones[$tmp])){
 
326
                $message[] = msgPool::duplicated(_("Zone name"));
 
327
            }
 
328
        }
 
329
 
 
330
        if(empty($this->zoneName)){
 
331
            $message[] = msgPool::required(_("Zone name"));
 
332
        }
 
333
 
 
334
        if(empty($this->ReverseZone)){
 
335
            $message[] = msgPool::required(_("Reverse zone"));
 
336
        }
 
337
 
 
338
        if($this->zoneName != strtolower($this->zoneName)){
 
339
            $message[] = msgPool::invalid(_("Zone name"),"","",_("Only lowercase allowed"));
 
340
        }
 
341
 
 
342
        if(!is_numeric($this->sOAserial)){
 
343
            $message[] = msgPool::invalid(_("Serial"),$this->sOAserial,"/[0-9]/");
 
344
        }
 
345
 
 
346
        if(!is_numeric($this->sOArefresh)){
 
347
            $message[] = msgPool::invalid(_("Refresh"),$this->sOArefresh,"/[0-9]/");
 
348
        }
 
349
 
 
350
        if(!is_numeric($this->sOAttl)){
 
351
            $message[] = msgPool::invalid(_("Time to life"),$this->sOAttl,"/[0-9]/");
 
352
        }
 
353
 
 
354
        if(!is_numeric($this->sOAexpire)){
 
355
            $message[] = msgPool::invalid(_("Expire"),$this->sOAexpire,"/[0-9]/");
 
356
        }
 
357
 
 
358
        if(!is_numeric($this->sOAretry)){
 
359
            $message[] = msgPool::invalid(_("Retry"),$this->sOAretry,"/[0-9]/");
 
360
        }
 
361
 
 
362
        foreach($this->Records as $name => $values){
 
363
            /* only lower-case is allowed in record entries ... */
 
364
            if($values['value'] != strtolower($values['value'])){
 
365
                $message[] = msgPool::invalid($values['type'],"","",_("Only lowercase allowed"));
 
366
            }
 
367
        }
 
368
 
 
369
        /* Check class for given Zone Address */
 
370
        $addr = preg_replace("/^[^\/]*+\//","",$this->ReverseZone);
 
371
 
 
372
        /* Check for valid&complete IP address */
 
373
        if(!tests::is_ip($addr)){
 
374
            $message[] = msgPool::invalid(_("Network address"));
 
375
        }
 
376
 
 
377
        // Ensure that we do not use reverse zones twice. 
 
378
        //  this currently not supported by GOsa.
 
379
        $zones = DNS::getDNSZoneEntries($this->config,$this->dn);
 
380
        switch($this->NetworkClass){
 
381
            case 'C' : $test = preg_replace("/\.[0-9]*$/","",$this->ReverseZone);break;
 
382
            case 'B' : $test = preg_replace("/\.[0-9]*\.[0-9]*$/","",$this->ReverseZone);break;
 
383
            case 'A' : $test = preg_replace("/\.[0-9]*\.[0-9]*\.[0-9]*$/","",$this->ReverseZone);break;
 
384
            default : trigger_error("Invalid network class given '".$this->NetworkClass."'");
 
385
        }
 
386
        foreach($zones as $name => $data){
 
387
            if($data['ReverseZone'] == $test && $data['zoneName'] != $this->InitialzoneName){
 
388
                $message[] = msgPool::duplicated(_("Network address"));
 
389
            }
 
390
        }
 
391
 
 
392
        /* Check if given address matches selected network class */
 
393
        switch($this->NetworkClass){
 
394
            case 'A': { 
 
395
                          if(!preg_match("/^[0-9]*\.0\.0\.0$/",$addr)){
 
396
                              $message[] = sprintf(_("The specified network address and the network class (%s/%s) do not match!"), $this->NetworkClass, "255.0.0.0");
 
397
                          }
 
398
                      }
 
399
                      break;
 
400
            case 'B': {
 
401
                          if(!preg_match("/^[0-9]*\.[0-9]*\.0\.0$/",$addr)){
 
402
                              $message[] = sprintf(_("The specified network address and the network class (%s/%s) do not match!"), $this->NetworkClass, "255.255.0.0");
 
403
                          }
 
404
                      }
 
405
                      break;
 
406
            case 'C': {
 
407
                          if(!preg_match("/^[0-9]*\.[0-9]*\.[0-9]*\.0$/",$addr)){
 
408
                              $message[] = sprintf(_("The specified network address and the network class (%s/%s) do not match!"), $this->NetworkClass, "255.255.255.0");
 
409
                          }
 
410
                      }
 
411
                      break;
 
412
            default : $message[] = msgPool::invalid(_("Network class"),$this->NetworkClass);
 
413
        }
 
414
 
 
415
        return ($message);
 
416
    }
 
417
 
 
418
 
 
419
    /* This funtion returns all used Zonenames
 
420
     */
 
421
    function getUsedZoneNames()
 
422
    {
 
423
        $ret = array();
 
424
        $ldap = $this->config->get_ldap_link();
 
425
        $ldap->cd($this->config->current['BASE']);
 
426
        $ldap->search("(&(objectClass=dNSZone)(!(relativeDomainName=@))(zoneName=*))",array("zoneName","relativeDomainName"));
 
427
        while($attr = $ldap->fetch()){
 
428
            $ret[$attr['zoneName'][0]][] = $attr['dn'];
 
429
        }
 
430
        return($ret);
 
431
    }
 
432
 
 
433
 
 
434
    /* Save to LDAP */
 
435
    function save()
 
436
    {
 
437
        $ret =array();
 
438
        foreach($this->attributes as $name){
 
439
            $ret[$name] = $this->$name;
 
440
        }
 
441
 
 
442
        /* Create mx records 
 
443
         */
 
444
        foreach($this->mXRecords as $key => $rec){
 
445
            $this->Records[] = $rec;
 
446
        }
 
447
 
 
448
        $ret['RECORDS'] = $this->Records; 
 
449
 
 
450
        switch($this->NetworkClass){
 
451
            case 'C' : $ret['ReverseZone']= preg_replace("/\.[0-9]*$/","",$this->ReverseZone);break;
 
452
            case 'B' : $ret['ReverseZone']= preg_replace("/\.[0-9]*\.[0-9]*$/","",$this->ReverseZone);break;
 
453
            case 'A' : $ret['ReverseZone']= preg_replace("/\.[0-9]*\.[0-9]*\.[0-9]*$/","",$this->ReverseZone);break;
 
454
            default : trigger_error("Invalid network class given '".$this->NetworkClass."'");
 
455
        }
 
456
 
 
457
        $ret['InitialReverseZone']=  $this->InitialReverseZone;
 
458
        $ret['InitialzoneName']   =  $this->InitialzoneName;
 
459
 
 
460
        $ret['sOAmail']            = preg_replace("/\@/",".",$this->sOAmail);
 
461
 
 
462
        foreach(array("sOAprimary","zoneName","sOAmail") as $attr){
 
463
 
 
464
            // Append trailing dots if we've full qualified host names.
 
465
            if(!preg_match("/\.$/",$ret[$attr])){
 
466
                if(!tests::is_ip($ret[$attr]) && preg_match("/\./",$ret[$attr])){
 
467
                    $ret[$attr] = $ret[$attr].".";
 
468
                }
 
469
            }
 
470
        }
 
471
 
 
472
        $ret['RECORDS'][] = array("type" => "nSRecord","value" => $ret['sOAprimary']) ;
 
473
 
 
474
        $ret['zoneEditor'] = $this->zoneEditor;
 
475
        return($ret);
 
476
    }
 
477
 
 
478
 
 
479
    /* This function generate a table row for each used record.
 
480
       This table row displays the recordtype in a select box
 
481
       and the specified value for the record, and a remove button.
 
482
       The last element of the table also got an 'add' button.
 
483
     */
 
484
    function generateRecordsList($changeStateForRecords="")
 
485
    {
 
486
        $changeStateForRecords = "";
 
487
 
 
488
        $str = "<table summary=''>";
 
489
        foreach($this->Records as $key => $entry){
 
490
 
 
491
            if($entry['type'] == "mXRecord") continue;
 
492
 
 
493
            $changeStateForRecords.= "changeState('RecordTypeSelectedFor_".$key."');\n";
 
494
            $changeStateForRecords.= "changeState('RecordValue_".$key."');\n";
 
495
            $changeStateForRecords.= "changeState('RemoveRecord_".$key."');\n";
 
496
 
 
497
            $str.=
 
498
                " <tr>".
 
499
                "   <td>".$this->generateRecordListBox($entry['type'],"RecordTypeSelectedFor_".$key)."</td>".
 
500
                "   <td>".
 
501
                "     <input type='text' value='".$entry['value']."' ".
 
502
                "       name='RecordValue_".$key."' id='RecordValue_".$key."'>".
 
503
                "   </td>".
 
504
                "   <td>".
 
505
                "     <button type='submit' name='RemoveRecord_".$key."' id='RemoveRecord_".$key."'>"._("Delete")."</button>".
 
506
                "  </td>".
 
507
                "</tr>";
 
508
        }
 
509
 
 
510
        $str.= 
 
511
            "  <tr>".
 
512
            "    <td colspan=2></td><td>".
 
513
            "      <button type='submit' name='AddNewRecord'>"._("Add")."</button>".
 
514
            "    </td>".
 
515
            "  </tr>".
 
516
            "</table>";
 
517
        return($str);
 
518
    }
 
519
 
 
520
    /* This function generates a select box out of $this->RecordTypes options.
 
521
       The Parameter $selected is used to predefine an attribute.
 
522
       $name is used to specify a post name
 
523
     */
 
524
    function generateRecordListBox($selected,$name)
 
525
    {
 
526
        $str = "<select name='".$name."' id='".$name."'>";
 
527
        foreach($this->RecordTypes as $type => $value){
 
528
 
 
529
            if(preg_match("/^mXRecord$/i",$value)) continue;
 
530
 
 
531
            $use = "";
 
532
            if($type == $selected){
 
533
                $use = " selected ";
 
534
            }
 
535
            $str.="\n <option value='".$type."' ".$use.">".strtoupper(preg_replace("/record/i","",$type))."</option>";
 
536
        }
 
537
        $str.="</select>";
 
538
        return($str);
 
539
    }
 
540
 
 
541
 
 
542
    function acl_is_writeable($attribute,$skip_write = FALSE)
 
543
    {
 
544
        if($this->read_only) return(FALSE);
 
545
        $ui= get_userinfo();
 
546
        return preg_match('/w/', $ui->get_permissions($this->acl_base, $this->acl_category."servdns", $attribute,      $skip_write));
 
547
    }
 
548
 
 
549
}
 
550
// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
 
551
?>