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

« back to all changes in this revision

Viewing changes to gosa-core/include/class_configRegistry.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 configRegistry{
 
4
 
 
5
    public $config = NULL;
 
6
    public $properties = array();
 
7
    public $ldapStoredProperties = array(); 
 
8
    public $fileStoredProperties = array(); 
 
9
    public $classToName = array(); 
 
10
 
 
11
    public $status = 'none';
 
12
 
 
13
    // Excludes property values defined in ldap 
 
14
    public $ignoreLdapProperties = FALSE;
 
15
 
 
16
    // Contains all classes with plInfo
 
17
    public $classesWithInfo = array();
 
18
    public $pluginRequirements  = array();
 
19
    public $categoryToClass  = array();
 
20
 
 
21
    public $objectClasses = array();
 
22
 
 
23
    public $detectedSchemaIssues = array();
 
24
    public $schemaCheckFailed = FALSE;
 
25
    public $schemaCheckFinished = FALSE;
 
26
    public $pluginsDeactivated = array();
 
27
 
 
28
    // Name of enabled plugins found in gosa.conf.
 
29
    private $activePlugins = array();
 
30
 
 
31
 
 
32
    /*! \brief      Constructs the config registry 
 
33
     *  @param      config  The configuration object
 
34
     *  @return     
 
35
     */
 
36
    function __construct($config)
 
37
    {
 
38
        $this->config = &$config;
 
39
 
 
40
        // Detect classes that have a plInfo method 
 
41
        global $class_mapping;
 
42
        foreach ($class_mapping as $cname => $path){
 
43
            $cmethods = get_class_methods($cname);
 
44
            if (is_array($cmethods) && in_array_ics('plInfo',$cmethods)){
 
45
 
 
46
                // Get plugin definitions
 
47
                $def = call_user_func(array($cname, 'plInfo'));;
 
48
 
 
49
                // Register Post Events (postmodfiy,postcreate,postremove,checkhook)
 
50
                if(count($def)){
 
51
                    $this->classesWithInfo[$cname] = $def;
 
52
                }
 
53
            }
 
54
        }
 
55
 
 
56
        // (Re)Load properties
 
57
        $this->reload();
 
58
    }
 
59
 
 
60
    
 
61
    /*! \brief      Returns a list of plugins used by GOsa.
 
62
        @return     Array       An array containing all plugins with theis plInfo data.
 
63
     */
 
64
    function getListOfPlugins()
 
65
    {
 
66
        return($this->classesWithInfo);
 
67
    }
 
68
 
 
69
 
 
70
    /*! \brief      Checks whether the schema check was called in the current session or not.
 
71
     *  @return     Boolean     True if check was already called
 
72
     */
 
73
    function schemaCheckFinished()
 
74
    {
 
75
        return($this->schemaCheckFinished);
 
76
    }
 
77
 
 
78
 
 
79
    /*! \brief      Starts the schema validation
 
80
     *  @param      Boolean     'force' Force a re-check.
 
81
     *  @param      Boolean     'disableIncompatiblePlugins' Disables of incompatible GOsa-plugins.
 
82
     *  @return     Boolean     True on success else FALSE
 
83
     */
 
84
    function validateSchemata($force = FALSE, $disableIncompatiblePlugins = FALSE, $objectClassesToUse = array())
 
85
    {
 
86
        // Read objectClasses from ldap
 
87
        if(count($objectClassesToUse)){
 
88
            $this->setObjectClasses($objectClassesToUse);
 
89
        }elseif(!count($this->objectClasses)){
 
90
            $ldap = $this->config->get_ldap_link();
 
91
            $ldap->cd($this->config->current['BASE']);
 
92
            $this->setObjectClasses($ldap->get_objectclasses());
 
93
        }
 
94
 
 
95
        return($this->_validateSchemata($force, $disableIncompatiblePlugins));
 
96
    }
 
97
 
 
98
 
 
99
    /*! \brief      Sets the list object classes to use while validation the schema. (See 'validateSchemata')
 
100
     *              This is called from the GOsa-Setup
 
101
     *  @param      Array       The list of object classes (usually LDAP::get_objectlclasses()).
 
102
     *  @return     void  
 
103
     */
 
104
    function setObjectClasses($ocs)
 
105
    {
 
106
        $this->objectClasses = $ocs;
 
107
    }
 
108
 
 
109
 
 
110
    /*! \brief      Returns an array which contains all unresolved schemata requirements.
 
111
     *  @return     Array       An array containing all errors/issues  
 
112
     */
 
113
    function getSchemaResults()
 
114
    {
 
115
        return($this->detectedSchemaIssues);
 
116
    }
 
117
 
 
118
 
 
119
    /*! \brief      This method checks if the installed ldap-schemata matches the plugin requirements.
 
120
     *  @param      Boolean     'force' Force a re-check.
 
121
     *  @param      Boolean     'disableIncompatiblePlugins' Disables of incompatible GOsa-plugins.
 
122
     *  @return     String  
 
123
     */
 
124
    private function _validateSchemata($force = FALSE, $disableIncompatiblePlugins = FALSE)
 
125
    {
 
126
        // We cannot check without readable schema info
 
127
        if(!count($this->objectClasses)){
 
128
            return(TRUE); 
 
129
        }
 
130
 
 
131
        // Don't do things twice unless forced
 
132
        if($this->schemaCheckFinished && !$force) return($this->schemaCheckFailed); 
 
133
 
 
134
        // Prepare result array
 
135
        $this->detectedSchemaIssues = array();
 
136
        $this->detectedSchemaIssues['missing'] = array();
 
137
        $this->detectedSchemaIssues['versionMismatch'] = array();
 
138
 
 
139
        // Clear last results 
 
140
        $this->pluginsDeactivated = array();
 
141
 
 
142
        // Collect required schema infos
 
143
        $this->pluginRequirements = array('ldapSchema' => array());
 
144
        $this->categoryToClass = array();
 
145
 
 
146
        // Walk through plugins with requirements, but only check for active plugins.
 
147
        foreach($this->classesWithInfo as $cname => $defs){
 
148
            if(isset($defs['plRequirements'])){
 
149
 
 
150
                // Check only if required plugin is enabled in gosa.conf
 
151
                // Normally this is the class name itself, but may be overridden
 
152
                //  in plInfo using the plRequirements::activePlugin statement.
 
153
                $requiresActivePlugin = $cname;
 
154
                if(isset($defs['plRequirements']['activePlugin'])){
 
155
                    $requiresActivePlugin = $defs['plRequirements']['activePlugin'];
 
156
                }
 
157
 
 
158
                // Only queue checks for active plugins. 
 
159
                if(isset($this->activePlugins[strtolower($requiresActivePlugin)])){
 
160
                    $this->pluginRequirements[$cname] = $defs['plRequirements'];
 
161
                }else{
 
162
                    if($cname == $requiresActivePlugin){
 
163
                        @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, "", 
 
164
                                "Skipped schema check for '{$cname}' plugin is inactive!");
 
165
                    }else{
 
166
                        @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, "", 
 
167
                                "Skipped schema check for class '{$cname}' skipped,".
 
168
                                " required plugin '{$requiresActivePlugin}' is inactive!");
 
169
                    }
 
170
                }
 
171
            }
 
172
        }
 
173
 
 
174
        // Check schema requirements now        $missing = $invalid = array();
 
175
        foreach($this->pluginRequirements as $cname => $requirements){
 
176
 
 
177
            // Check LDAP schema requirements for this plugins
 
178
            $failure = FALSE;
 
179
            if(isset($requirements['ldapSchema'])){
 
180
                foreach($requirements['ldapSchema'] as $oc => $version){
 
181
                    if(!$this->ocAvailable($oc)){
 
182
                        $this->detectedSchemaIssues['missing'][$oc] = $oc;
 
183
                    
 
184
                        $this->schemaCheckFailed = TRUE;
 
185
                        $failure = TRUE;
 
186
 
 
187
                        new log("debug","","LDAP objectClass missing '{$oc}'!",
 
188
                                array(),'');
 
189
 
 
190
                    }elseif(!empty($version)){
 
191
                        $currentVersion = $this->getObjectClassVersion($oc);
 
192
                        if(!empty($currentVersion) && !$this->ocVersionMatch($version, $currentVersion)){
 
193
                            if($currentVersion == -1){
 
194
                                $currentVersion = _("unknown");
 
195
                            }
 
196
                            $this->detectedSchemaIssues['versionMismatch'][$oc] = 
 
197
                                sprintf(_("%s has version %s but %s is required!"), bold($oc),bold($currentVersion),bold($version));
 
198
                            $this->schemaCheckFailed = TRUE;
 
199
                            $failure = TRUE;
 
200
 
 
201
                            new log("debug","","LDAP objectClass version mismatch '{$oc}' ".
 
202
                                    "has '{$currentVersion}' but {$version} required!",
 
203
                                    array(),'');
 
204
                        }
 
205
                    }
 
206
                }
 
207
            }
 
208
 
 
209
            // Display corresponding plugins now 
 
210
            if($disableIncompatiblePlugins && $failure && isset($requirements['onFailureDisablePlugin'])){
 
211
                foreach($requirements['onFailureDisablePlugin'] as $name){
 
212
                    $this->pluginsDeactivated[$name] = $name;
 
213
                } 
 
214
            }
 
215
        }
 
216
        $this->schemaCheckFinished =TRUE;
 
217
        session::un_set('plist');
 
218
        return(!$this->schemaCheckFailed);
 
219
    }
 
220
 
 
221
    
 
222
    /*! \brief      The function 'validateSchemata' may has disabled some GOsa-Plugins, 
 
223
     *               the list of disabled plugins will be returned here.
 
224
     *  @return     Array       The list of plugins disabled by 'validateSchemata'
 
225
     */
 
226
    function getDisabledPlugins()
 
227
    {
 
228
        return($this->pluginsDeactivated);
 
229
    }
 
230
 
 
231
        
 
232
    /*! \brief      Displays an error message with all issues detect during the schema validation.
 
233
     */
 
234
    function displayRequirementErrors()
 
235
    {
 
236
        $message = "";
 
237
        if(count($this->detectedSchemaIssues['missing'])){
 
238
            $message.= "<br>".
 
239
                _("The following object classes are missing:").
 
240
                "<div class='scrollContainer' style='height:100px'>".
 
241
                msgPool::buildList(array_values($this->detectedSchemaIssues['missing'])).
 
242
                "</div>";
 
243
        }    
 
244
        if(count($this->detectedSchemaIssues['versionMismatch'])){
 
245
            $message.= "<br>".
 
246
                _("The following object classes are outdated:").
 
247
                "<div class='scrollContainer' style='height:100px'>".
 
248
                msgPool::buildList(array_values($this->detectedSchemaIssues['versionMismatch'])).
 
249
                "</div>";
 
250
        }    
 
251
        if($message != ""){
 
252
            $message.= "<br>"._("Plugins that require one or more of the object classes above will be disabled until the object classes get updated.");
 
253
 
 
254
            msg_dialog::display(_("Schema validation error"),$message, ERROR_DIALOG);
 
255
        }
 
256
    }
 
257
 
 
258
 
 
259
    /*! \brief      Checks to version strings (e.g. '>=v2.8' and '2.9')
 
260
     *  @param      String      The required version with operators (e.g. '>=2.8') 
 
261
     *  @param      String      The version to match for withOUT operators (e.g. '2.9') 
 
262
     *  @return     Boolean     True if version matches else false.  
 
263
     */
 
264
    private function ocVersionMatch($required, $installed)
 
265
    {
 
266
        $operator = preg_replace('/^([=<>]*).*$/',"\\1",$required);
 
267
        $required = preg_replace('/^[=<>]*(.*)$/',"\\1",$required);
 
268
        return(version_compare($installed,$required, $operator)); 
 
269
    }
 
270
 
 
271
    
 
272
    /*! \brief      Returns the currently installed version of a given object class.
 
273
     *  @param      String      The name of the objectClass to check for. 
 
274
     *  @return     String      The version string of the objectClass (e.g. v2.7) 
 
275
     */
 
276
    function getObjectClassVersion($oc)
 
277
    {
 
278
        if(!isset($this->objectClasses[$oc])){
 
279
            return(NULL);
 
280
        }else{
 
281
            $version = -1; // unknown
 
282
            if(preg_match("/(v[^)]*)/", $this->objectClasses[$oc]['DESC'])){
 
283
                $version = preg_replace('/^.*\(v([^)]*)\).*$/',"\\1", $this->objectClasses[$oc]['DESC']);
 
284
            }
 
285
        }
 
286
        return($version);
 
287
    }
 
288
    
 
289
 
 
290
    /*! \brief      Check whether the given object class is available or not. 
 
291
     *  @param      String      The name of the objectClass to check for (e.g. 'mailAccount') 
 
292
     *  @return     Boolean     Returns TRUE if the class exists else FALSE.
 
293
     */
 
294
    function ocAvailable($name)
 
295
    {
 
296
        return(isset($this->objectClasses[$name]));
 
297
    }
 
298
 
 
299
 
 
300
    /*! \brief      Re-loads the list of installed GOsa-Properties. 
 
301
     *  @param      Boolean     $force   If force is TRUE, the complete properties list is rebuild..
 
302
     */
 
303
    function reload($force = FALSE)
 
304
    {
 
305
        // Do not reload the properties everytime, once we have  
 
306
        //  everything loaded and registrered skip the reload.
 
307
        // Status is 'finished' once we had a ldap connection (logged in)
 
308
        if(!$force && $this->status == 'finished') return;
 
309
 
 
310
        // Reset everything
 
311
        $this->ldapStoredProperties = array();
 
312
        $this->fileStoredProperties = array();
 
313
        $this->properties = array();
 
314
        $this->mapByName = array();
 
315
        $this->activePlugins = array('core'=>'core');
 
316
 
 
317
        if(!$this->config) return;
 
318
 
 
319
        // Search for config flags defined in the config file (TAB section)
 
320
        foreach($this->config->data['TABS'] as $tabname => $tabdefs){
 
321
            foreach($tabdefs as $info){
 
322
 
 
323
                // Put plugin in list of active plugins
 
324
                if(isset($info['CLASS'])){
 
325
                    $class = strtolower($info['CLASS']);
 
326
                    $this->activePlugins[$class] = $class;
 
327
                }
 
328
 
 
329
                // Check if the info is valid
 
330
                if(isset($info['NAME']) && isset($info['CLASS'])){
 
331
                    
 
332
 
 
333
                    // Check if there is nore than just the plugin definition
 
334
                    if(count($info) > 2){
 
335
                        foreach($info as $name => $value){
 
336
                            
 
337
                            if(!in_array($name, array('CLASS','NAME'))){
 
338
                                $class= $info['CLASS'];    
 
339
                                $this->fileStoredProperties[$class][strtolower($name)] = $value;
 
340
                            }
 
341
                        }
 
342
                    }
 
343
                }
 
344
            }
 
345
        }
 
346
 
 
347
        foreach($this->config->data['MENU'] as $section => $entries){
 
348
            foreach($entries as $entry){
 
349
 
 
350
                if(isset($entry['CLASS'])){
 
351
 
 
352
                    // Put plugin to active plugins list.
 
353
                    $class = strtolower($entry['CLASS']);
 
354
                    $this->activePlugins[$class] = $class;
 
355
                
 
356
                    if(count($entry) > 2 ){
 
357
                        foreach($entry as $name => $value){
 
358
                            if(!in_array($name, array('CLASS','ACL'))){
 
359
                                $this->fileStoredProperties[strtolower($class)][strtolower($name)] = $value;
 
360
                            }
 
361
                        }
 
362
                    }
 
363
                }
 
364
            }
 
365
        }
 
366
 
 
367
        // Search for config flags defined in the config file (PATHMENU)
 
368
        foreach($this->config->data['PATHMENU'] as $entry){
 
369
 
 
370
            if(isset($entry['CLASS'])){
 
371
 
 
372
                // Put plugin to active plugins list.
 
373
                $class = strtolower($entry['CLASS']);
 
374
                $this->activePlugins[$class] = $class;
 
375
 
 
376
                if(count($entry) > 2 ){
 
377
                    foreach($entry as $name => $value){
 
378
                        if(!in_array($name, array('CLASS','ACL'))){
 
379
                            $this->fileStoredProperties[strtolower($class)][strtolower($name)] = $value;
 
380
                        }
 
381
                    }
 
382
                }
 
383
            }
 
384
        }
 
385
 
 
386
        // Search for config flags defined in the config file (MAIN section)
 
387
        foreach($this->config->data['MAIN'] as $name => $value){
 
388
            $this->fileStoredProperties['core'][strtolower($name)] = $value;
 
389
        }
 
390
 
 
391
        // Search for config flags defined in the config file (Current LOCATION section)
 
392
        if(isset($this->config->current)){
 
393
            foreach($this->config->current as $name => $value){
 
394
                $this->fileStoredProperties['core'][strtolower($name)] = $value;
 
395
            }
 
396
        }
 
397
 
 
398
        // Skip searching for LDAP defined properties if 'ignoreLdapProperties' is set to 'true'
 
399
        //  in the config. 
 
400
        $this->ignoreLdapProperties = FALSE;
 
401
        if(isset($this->fileStoredProperties['core'][strtolower('ignoreLdapProperties')]) && 
 
402
            preg_match("/(true|on)/i", $this->fileStoredProperties['core'][strtolower('ignoreLdapProperties')])){
 
403
            $this->ignoreLdapProperties = TRUE;
 
404
        }
 
405
 
 
406
        // Search for all config flags defined in the LDAP - BUT only if we ARE logged in. 
 
407
        if(!empty($this->config->current['CONFIG'])){
 
408
            $ldap = $this->config->get_ldap_link();
 
409
            $ldap->cd($this->config->current['CONFIG']);
 
410
            $ldap->search('(&(objectClass=gosaConfig)(gosaSetting=*))', array('cn','gosaSetting'));
 
411
            while($attrs = $ldap->fetch()){
 
412
                $class = $attrs['cn'][0];
 
413
                for($i=0; $i<$attrs['gosaSetting']['count']; $i++){
 
414
                    list($name,$value) = preg_split("/:/",$attrs['gosaSetting'][$i],2);
 
415
                    $this->ldapStoredProperties[$class][$name] = $value;
 
416
                }
 
417
            }
 
418
        }
 
419
 
 
420
        // Register plugin properties.
 
421
        foreach ($this->classesWithInfo as $cname => $def){
 
422
 
 
423
            // Detect class name
 
424
            $name = $cname;
 
425
            $name = (isset($def['plShortName'])) ? $def['plShortName'] : $cname;
 
426
            $name = (isset($def['plDescription'])) ? $def['plDescription'] : $cname;
 
427
 
 
428
            // Register post events
 
429
            $this->classToName[$cname] = $name;
 
430
            $data = array('name' => 'postcreate','type' => 'command');
 
431
            $this->register($cname, $data);    
 
432
            $data = array('name' => 'postremove','type' => 'command');
 
433
            $this->register($cname, $data);    
 
434
            $data = array('name' => 'postmodify','type' => 'command');
 
435
            $this->register($cname, $data);    
 
436
            $data = array('name' => 'precreate','type' => 'command');
 
437
            $this->register($cname, $data);    
 
438
            $data = array('name' => 'preremove','type' => 'command');
 
439
            $this->register($cname, $data);    
 
440
            $data = array('name' => 'premodify','type' => 'command');
 
441
            $this->register($cname, $data);    
 
442
            $data = array('name' => 'check', 'type' => 'command');
 
443
            $this->register($cname, $data);    
 
444
 
 
445
            // Register properties 
 
446
            if(isset($def['plProperties'])){
 
447
                foreach($def['plProperties'] as $property){
 
448
                    $this->register($cname, $property);
 
449
                }
 
450
            }
 
451
        }
 
452
 
 
453
        // We are only finsihed once we are logged in.
 
454
        if(!empty($this->config->current['CONFIG'])){
 
455
            $this->status = 'finished';
 
456
        }
 
457
    }
 
458
 
 
459
   
 
460
    /*! \brief      Returns TRUE if the property registration has finished without any error.
 
461
     */ 
 
462
    function propertyInitializationComplete()
 
463
    {
 
464
        return($this->status == 'finished');
 
465
    }
 
466
 
 
467
 
 
468
    /*! \brief      Registers a GOsa-Property and thus makes it useable by GOsa and its plugins.
 
469
     *  @param      String      $class  The name of the class/plugin that wants to register this property.
 
470
     *  @return     Array       $data   An array containing all data set in plInfo['plProperty]
 
471
     */
 
472
    function register($class,$data)
 
473
    {
 
474
        $id = count($this->properties);
 
475
        $this->properties[$id] = new gosaProperty($this,$class,$data);
 
476
        $p = strtolower("{$class}::{$data['name']}");
 
477
        $this->mapByName[$p] = $id;
 
478
    }
 
479
 
 
480
 
 
481
    /*! \brief      Returns all registered properties.
 
482
     *  @return     Array   A list of all properties.
 
483
     */
 
484
    public function getAllProperties()
 
485
    {
 
486
        return($this->properties);
 
487
    }
 
488
 
 
489
 
 
490
    /*! \brief      Checks whether a property exists or not.
 
491
     *  @param      String      $class  The class name (e.g. 'core' or 'mailAccount') 
 
492
     *  @param      String      $name   The property name (e.g. 'sessionTimeout' or 'mailMethod')
 
493
     *  @return     Boolean     TRUE if it exists else FALSE.
 
494
     */
 
495
    function propertyExists($class,$name)
 
496
    {       
 
497
        $p = strtolower("{$class}::{$name}");
 
498
        return(isset($this->mapByName[$p]));
 
499
    }
 
500
 
 
501
 
 
502
    /*! \brief      Returns the id of a registered property.
 
503
     *  @param      String      $class  The class name (e.g. 'core' or 'mailAccount') 
 
504
     *  @param      String      $name   The property name (e.g. 'sessionTimeout' or 'mailMethod')
 
505
     *  @return     Integer     The id for the given property.  
 
506
     */
 
507
    private function getId($class,$name)
 
508
    {
 
509
        $p = strtolower("{$class}::{$name}");
 
510
        if(!isset($this->mapByName[$p])){
 
511
            return(-1);
 
512
        }       
 
513
        return($this->mapByName[$p]);    
 
514
    }
 
515
 
 
516
 
 
517
    /*! \brief      Returns a given property, if it exists.
 
518
     *  @param      String      $class  The class name (e.g. 'core' or 'mailAccount') 
 
519
     *  @param      String      $name   The property name (e.g. 'sessionTimeout' or 'mailMethod')
 
520
     *  @return     GOsaPropery     The property or 'NULL' if it doesn't exists.
 
521
     */
 
522
    function getProperty($class,$name)
 
523
    {
 
524
        if($this->propertyExists($class,$name)){
 
525
            return($this->properties[$this->getId($class,$name)]);
 
526
        }
 
527
        return(NULL); 
 
528
    }
 
529
 
 
530
 
 
531
    /*! \brief      Returns the value for a given property, if it exists.
 
532
     *  @param      String      $class  The class name (e.g. 'core' or 'mailAccount') 
 
533
     *  @param      String      $name   The property name (e.g. 'sessionTimeout' or 'mailMethod')
 
534
     *  @return     GOsaPropery     The property value or an empty string if it doesn't exists.
 
535
     */
 
536
    function getPropertyValue($class,$name)
 
537
    {   
 
538
        if($this->propertyExists($class,$name)){
 
539
            $tmp = $this->getProperty($class,$name);
 
540
            return($tmp->getValue());
 
541
        }
 
542
        return("");
 
543
    }
 
544
 
 
545
 
 
546
    /*! \brief      Set a new value for a given property, if it exists.
 
547
     *  @param      String      $class  The class name (e.g. 'core' or 'mailAccount') 
 
548
     *  @param      String      $name   The property name (e.g. 'sessionTimeout' or 'mailMethod')
 
549
     *  @return     
 
550
     */
 
551
    function setPropertyValue($class,$name, $value)
 
552
    {   
 
553
        if($this->propertyExists($class,$name)){
 
554
            $tmp = $this->getProperty($class,$name);
 
555
            return($tmp->setValue($value));
 
556
        }
 
557
        return("");
 
558
    }
 
559
 
 
560
 
 
561
    /*! \brief      Save all temporary made property changes and thus make them useable/effective.
 
562
     *  @return     Array       Returns a list of plugins that have to be migrated before they can be saved.
 
563
     */
 
564
    function saveChanges()
 
565
    {
 
566
        $migrate = array();
 
567
        foreach($this->properties as $prop){
 
568
 
 
569
            // Is this property modified
 
570
            if(in_array($prop->getStatus(),array('modified','removed'))){
 
571
 
 
572
                // Check if we've to migrate something before we can make the changes effective. 
 
573
                if($prop->migrationRequired()){
 
574
                    $migrate[] = $prop;
 
575
                }else{
 
576
                    $prop->save();
 
577
                }
 
578
            }
 
579
        }
 
580
        return($migrate);
 
581
    }
 
582
}
 
583
 
 
584
 
 
585
class gosaProperty
 
586
{
 
587
    protected $name = "";
 
588
    protected $class = "";
 
589
    protected $value = "";
 
590
    protected $tmp_value = "";  // Used when modified but not saved 
 
591
    protected $type = "string";
 
592
    protected $default = "";
 
593
    protected $defaults = "";
 
594
    protected $description = "";
 
595
    protected $check = "";
 
596
    protected $migrate = "";
 
597
    protected $mandatory = FALSE;
 
598
    protected $group = "default";
 
599
    protected $parent = NULL;
 
600
    protected $data = array();
 
601
 
 
602
    protected $migrationClass = NULL;
 
603
 
 
604
    /*!  The current property status
 
605
     *     'ldap'       Property is stored in ldap 
 
606
     *     'file'       Property is stored in the config file
 
607
     *     'undefined'  Property is currently not stored anywhere
 
608
     *     'modified'   Property has been modified (should be saved)
 
609
     */
 
610
    protected $status = 'undefined';
 
611
 
 
612
    protected $attributes = array('name','type','default','description','check',
 
613
            'migrate','mandatory','group','defaults');
 
614
 
 
615
 
 
616
 
 
617
 
 
618
    function __construct($parent,$classname,$data)
 
619
    {
 
620
        // Set some basic infos 
 
621
        $this->parent = &$parent;
 
622
        $this->class = $classname;
 
623
        $this->data  = $data;
 
624
 
 
625
        // Get all relevant information from the data array (comes from plInfo)    
 
626
        foreach($this->attributes as $aName){
 
627
            if(isset($data[$aName])){
 
628
                $this->$aName = $data[$aName];
 
629
            }
 
630
        }      
 
631
 
 
632
        // Initialize with the current value
 
633
        $this->_restoreCurrentValue(); 
 
634
 
 
635
    }
 
636
 
 
637
    function migrationRequired()
 
638
    {
 
639
        // Instantiate migration class 
 
640
        if(!empty($this->migrate) && $this->migrationClass == NULL){
 
641
            if(!class_available($this->migrate)){
 
642
                trigger_error("Cannot start migration for gosaProperty::'{$this->getName()}' class not found ({$this->migrate})!");
 
643
            }else{
 
644
                $class = $this->migrate;
 
645
                $tmp = new $class($this->parent->config,$this);
 
646
                if(! $tmp instanceof propertyMigration){ 
 
647
                    trigger_error("Cannot start migration for gosaProperty::'{$this->getName()}' doesn't implement propertyMigration!");
 
648
                }else{
 
649
                    $this->migrationClass = $tmp;
 
650
                }
 
651
            }
 
652
        }
 
653
        if(empty($this->migrate) || $this->migrationClass == NULL){
 
654
            return(FALSE);
 
655
        }
 
656
        return($this->migrationClass->checkForIssues());
 
657
    }
 
658
 
 
659
    function getMigrationClass()
 
660
    {
 
661
        return($this->migrationClass);
 
662
    }
 
663
 
 
664
    function check()
 
665
    {
 
666
        $val = $this->getValue(TRUE);
 
667
        $return = TRUE;
 
668
        if($this->mandatory && empty($val)){
 
669
            $return = FALSE;
 
670
        }
 
671
 
 
672
        $check = $this->getCheck();
 
673
        if(!empty($val) && !empty($check)){
 
674
            $res = call_user_func(preg_split("/::/", $this->check),$messages=TRUE, $this->class,$this->name,$val, $this->type);
 
675
            if(!$res){
 
676
                $return = FALSE;
 
677
            }
 
678
        }
 
679
        return($return);
 
680
    }
 
681
 
 
682
    static function isBool($message,$class,$name,$value, $type)
 
683
    {
 
684
        $match = in_array($value,array('true','false',''));
 
685
 
 
686
        // Display the reason for failing this check.         
 
687
        if($message && ! $match){
 
688
            msg_dialog::display(_("Warning"), 
 
689
                    sprintf(_("The value %s specified for %s:%s needs to be a bool value!"), 
 
690
                        bold($value),bold($class),bold($name)), 
 
691
                    WARNING_DIALOG);
 
692
        }
 
693
    
 
694
        return($match);
 
695
    }
 
696
 
 
697
    static function isString($message,$class,$name,$value, $type)
 
698
    {
 
699
        $match = TRUE;
 
700
    
 
701
        // Display the reason for failing this check.         
 
702
        if($message && ! $match){
 
703
            msg_dialog::display(_("Warning"), 
 
704
                    sprintf(_("The value %s specified for %s:%s needs to be a string!"), 
 
705
                        bold($value),bold($class),bold($name)), 
 
706
                    WARNING_DIALOG);
 
707
        }
 
708
 
 
709
        return($match);
 
710
    }
 
711
 
 
712
    static function isInteger($message,$class,$name,$value, $type)
 
713
    {
 
714
        $match = is_numeric($value) && !preg_match("/[^0-9]/", $value);
 
715
 
 
716
        // Display the reason for failing this check.         
 
717
        if($message && ! $match){
 
718
            msg_dialog::display(_("Warning"), 
 
719
                    sprintf(_("The value %s specified for %s:%s needs to be numeric!"), 
 
720
                        bold($value),bold($class),bold($name)), 
 
721
                    WARNING_DIALOG);
 
722
        }
 
723
 
 
724
        return($match);
 
725
    }
 
726
 
 
727
    static function isPath($message,$class,$name,$value, $type)
 
728
    {
 
729
        $match = preg_match("#^(/[^/]*/){1}#", $value);
 
730
    
 
731
        // Display the reason for failing this check.         
 
732
        if($message && ! $match){
 
733
            msg_dialog::display(_("Warning"), 
 
734
                    sprintf(_("The path %s specified for %s:%s is invalid!"), 
 
735
                        bold($value),bold($class),bold($name)), 
 
736
                    WARNING_DIALOG);
 
737
        }
 
738
 
 
739
        return($match);
 
740
    }
 
741
 
 
742
    static function isReadablePath($message,$class,$name,$value, $type)
 
743
    {
 
744
        $match = !empty($value)&&is_dir($value)&&is_writeable($value);
 
745
   
 
746
        // Display the reason for failing this check.         
 
747
        if($message && ! $match){
 
748
            if(!is_dir($value)){
 
749
                msg_dialog::display(_("Warning"), 
 
750
                        sprintf(_("The folder %s specified for %s:%s does not exists!"), 
 
751
                            bold($value),bold($class),bold($name)), 
 
752
                        WARNING_DIALOG);
 
753
            }elseif(!is_readable($value)){
 
754
                msg_dialog::display(_("Warning"), 
 
755
                        sprintf(_("The folder %s specified for %s:%s is not readable!"), 
 
756
                            bold($value),bold($class),bold($name)), 
 
757
                        WARNING_DIALOG);
 
758
            }
 
759
        }
 
760
 
 
761
        return($match);
 
762
    }
 
763
 
 
764
    static function isWriteableFile($message,$class,$name,$value, $type)
 
765
    {
 
766
        $match = (file_exists($value) && is_writeable($value)) || 
 
767
                 (!file_exists($value) && is_writeable(dirname($value)));
 
768
                
 
769
   
 
770
        // Display the reason for failing this check.         
 
771
        if($message && ! $match){
 
772
 
 
773
            if(!file_exists($value) && !is_writeable(dirname($value))){
 
774
                msg_dialog::display(_("Warning"), 
 
775
                        sprintf(_("The file %s specified for %s:%s is not writeable!"), 
 
776
                            bold($value),bold($class),bold($name)), 
 
777
                        WARNING_DIALOG);
 
778
            }elseif(file_exists($value) && !is_writeable($value)){
 
779
                msg_dialog::display(_("Warning"), 
 
780
                        sprintf(_("The file %s specified for %s:%s is not writeable!"), 
 
781
                            bold($value),bold($class),bold($name)), 
 
782
                        WARNING_DIALOG);
 
783
            }
 
784
        }
 
785
 
 
786
        return($match);
 
787
    }
 
788
 
 
789
    static function isWriteablePath($message,$class,$name,$value, $type)
 
790
    {
 
791
        $match = !empty($value)&&is_dir($value)&&is_writeable($value);
 
792
   
 
793
        // Display the reason for failing this check.         
 
794
        if($message && ! $match){
 
795
            if(!is_dir($value)){
 
796
                msg_dialog::display(_("Warning"), 
 
797
                        sprintf(_("The folder %s specified for %s:%s does not exists!"), 
 
798
                            bold($value),bold($class),bold($name)), 
 
799
                        WARNING_DIALOG);
 
800
            }elseif(!is_writeable($value)){
 
801
                msg_dialog::display(_("Warning"), 
 
802
                        sprintf(_("The folder %s specified for %s:%s is not writeable!"), 
 
803
                            bold($value),bold($class),bold($name)), 
 
804
                        WARNING_DIALOG);
 
805
            }
 
806
        }
 
807
 
 
808
        return($match);
 
809
    }
 
810
 
 
811
    static function isReadableFile($message,$class,$name,$value, $type)
 
812
    {
 
813
        $match = !empty($value) && is_readable($value) && is_file($value);
 
814
 
 
815
        // Display the reason for failing this check.         
 
816
        if($message && ! $match){
 
817
                
 
818
            if(!is_file($value)){
 
819
                msg_dialog::display(_("Warning"), 
 
820
                        sprintf(_("The file %s specified for %s:%s does not exists!"), 
 
821
                            bold($value),bold($class),bold($name)), 
 
822
                        WARNING_DIALOG);
 
823
            }elseif(!is_readable($value)){
 
824
                msg_dialog::display(_("Warning"), 
 
825
                        sprintf(_("The file %s specified for %s:%s is not readable!"), 
 
826
                            bold($value),bold($class),bold($name)), 
 
827
                        WARNING_DIALOG);
 
828
            }
 
829
        }
 
830
 
 
831
        return($match);
 
832
    }
 
833
 
 
834
    static function isCommand($message,$class,$name,$value, $type)
 
835
    {
 
836
        $match = TRUE;
 
837
 
 
838
        // Display the reason for failing this check.         
 
839
        if($message && ! $match){
 
840
            msg_dialog::display(_("Warning"), 
 
841
                    sprintf(_("The command %s specified for %s:%s is invalid!"), 
 
842
                        bold($value),bold($class),bold($name)), 
 
843
                    WARNING_DIALOG);
 
844
        }
 
845
        
 
846
        return($match);
 
847
    }
 
848
 
 
849
    static function isDn($message,$class,$name,$value, $type)
 
850
    {
 
851
        $match = preg_match("/^([a-z]*=[^=,]*,)*[^=]*=[^=]*$/i", $value);
 
852
 
 
853
        // Display the reason for failing this check.         
 
854
        if($message && ! $match){
 
855
            msg_dialog::display(_("Warning"), 
 
856
                    sprintf(_("The DN %s specified for %s:%s is invalid!"), 
 
857
                        bold($value),bold($class),bold($name)), 
 
858
                    WARNING_DIALOG);
 
859
        }
 
860
        
 
861
        return($match);
 
862
    }
 
863
 
 
864
    static function isRdn($message,$class,$name,$value, $type)
 
865
    {
 
866
        $match = preg_match("/^([a-z]*=[^=,]*,)*[^=]*=[^=,]*,?$/i", $value);
 
867
 
 
868
        // Display the reason for failing this check.         
 
869
        if($message && ! $match){
 
870
            msg_dialog::display(_("Warning"), 
 
871
                    sprintf(_("The RDN %s specified for %s:%s is invalid!"), 
 
872
                        bold($value),bold($class),bold($name)), 
 
873
                    WARNING_DIALOG);
 
874
        }
 
875
        
 
876
        return($match);
 
877
    }
 
878
 
 
879
    private function _restoreCurrentValue()
 
880
    {
 
881
        // First check for values in the LDAP Database.
 
882
        if(isset($this->parent->ldapStoredProperties[$this->class][$this->name])){
 
883
            $this->setStatus('ldap');
 
884
            $this->value = $this->parent->ldapStoredProperties[$this->class][$this->name];
 
885
            return;
 
886
        }
 
887
 
 
888
        // Second check for values in the config file.
 
889
        if(isset($this->parent->fileStoredProperties[strtolower($this->class)][strtolower($this->name)])){
 
890
            $this->setStatus('file');
 
891
            $this->value = $this->parent->fileStoredProperties[strtolower($this->class)][strtolower($this->name)];
 
892
            return;
 
893
        }
 
894
 
 
895
        // If there still wasn't found anything then fallback to the default.
 
896
        if($this->getStatus() == 'undefined'){
 
897
            $this->value = $this->getDefault();
 
898
        }
 
899
    }
 
900
 
 
901
    function getMigrate() { return($this->migrate); }
 
902
    function getCheck() { return($this->check); }
 
903
    function getName() { return($this->name); }
 
904
    function getClass() { return($this->class); }
 
905
    function getGroup() { return($this->group); }
 
906
    function getType() { return($this->type); }
 
907
    function getDescription() { return($this->description); }
 
908
    function getDefault() { return($this->default); }
 
909
    function getDefaults() { return($this->defaults); }
 
910
    function getStatus() { return($this->status); }
 
911
    function isMandatory() { return($this->mandatory); }
 
912
 
 
913
    function setValue($str) 
 
914
    {
 
915
        if(in_array($this->getStatus(), array('modified'))){
 
916
            $this->tmp_value = $str; 
 
917
        }elseif($this->value != $str){
 
918
            $this->setStatus('modified'); 
 
919
            $this->tmp_value = $str; 
 
920
        }
 
921
    }
 
922
 
 
923
    function getValue($temporary = FALSE) 
 
924
    { 
 
925
        if($temporary){
 
926
            if(in_array($this->getStatus(), array('modified','removed'))){
 
927
                return($this->tmp_value); 
 
928
            }else{
 
929
                return($this->value); 
 
930
            }
 
931
        }else{ 
 
932
 
 
933
            // Do not return ldap values if we've to ignore them.
 
934
            if($this->parent->ignoreLdapProperties){
 
935
                if(isset($this->parent->fileStoredProperties[strtolower($this->class)][strtolower($this->name)])){
 
936
                    return($this->parent->fileStoredProperties[strtolower($this->class)][strtolower($this->name)]);
 
937
                }else{
 
938
                    return($this->getDefault());
 
939
                }
 
940
            }else{
 
941
                return($this->value); 
 
942
            }
 
943
        }
 
944
    }
 
945
 
 
946
    function restoreDefault() 
 
947
    {
 
948
        if(in_array($this->getStatus(),array('ldap'))){
 
949
            $this->setStatus('removed'); 
 
950
 
 
951
            // Second check for values in the config file.
 
952
            if(isset($this->parent->fileStoredProperties[strtolower($this->class)][strtolower($this->name)])){
 
953
                $this->tmp_value = $this->parent->fileStoredProperties[strtolower($this->class)][strtolower($this->name)];
 
954
            }else{
 
955
                $this->tmp_value = $this->getDefault();
 
956
            }
 
957
        }
 
958
    }
 
959
 
 
960
    function save()
 
961
    {
 
962
        if($this->getStatus() == 'modified'){
 
963
            $ldap = $this->parent->config->get_ldap_link();
 
964
            $ldap->cd($this->parent->config->current['BASE']);
 
965
            $dn = "cn={$this->class},".$this->parent->config->current['CONFIG'];
 
966
            $ldap->cat($dn);
 
967
            if(!$ldap->count()){
 
968
                $ldap->cd($dn);
 
969
                $data = array(
 
970
                        'cn' => $this->class, 
 
971
                        'objectClass' => array('top','gosaConfig'),
 
972
                        'gosaSetting' => $this->name.":".$this->tmp_value);
 
973
 
 
974
                $ldap->add($data);
 
975
                if(!$ldap->success()){
 
976
                    echo $ldap->get_error();
 
977
                }
 
978
 
 
979
            }else{
 
980
                $attrs = $ldap->fetch();
 
981
                $data = array();
 
982
                $found = false;
 
983
                if(isset($attrs['gosaSetting']['count'])){
 
984
                    for($i = 0;$i<$attrs['gosaSetting']['count']; $i ++){
 
985
                        $set = $attrs['gosaSetting'][$i];
 
986
                        if(preg_match("/^{$this->name}:/", $set)){
 
987
                            $set = "{$this->name}:{$this->tmp_value}";
 
988
                            $found = true;
 
989
                        }
 
990
                        $data['gosaSetting'][] = $set;
 
991
                    }
 
992
                }
 
993
                if(!$found) $data['gosaSetting'][] = "{$this->name}:{$this->tmp_value}";
 
994
                $ldap->cd($dn);
 
995
                $ldap->modify($data);
 
996
                if(!$ldap->success()){
 
997
                    echo $ldap->get_error();
 
998
                }
 
999
            }
 
1000
            $this->value = $this->tmp_value;
 
1001
            $this->setStatus('ldap'); 
 
1002
        }elseif($this->getStatus() == 'removed'){
 
1003
            $ldap = $this->parent->config->get_ldap_link();
 
1004
            $ldap->cd($this->parent->config->current['BASE']);
 
1005
            $dn = "cn={$this->class},".$this->parent->config->current['CONFIG'];
 
1006
            $ldap->cat($dn);
 
1007
            $attrs = $ldap->fetch();
 
1008
            $data = array('gosaSetting' => array());
 
1009
            for($i = 0;$i<$attrs['gosaSetting']['count']; $i ++){
 
1010
                $set = $attrs['gosaSetting'][$i];
 
1011
                if(preg_match("/^{$this->name}:/", $set)){
 
1012
                    continue;
 
1013
                }
 
1014
                $data['gosaSetting'][] = $set;
 
1015
            }
 
1016
            $ldap->cd($dn);
 
1017
            $ldap->modify($data);
 
1018
            if(!$ldap->success()){
 
1019
                echo $ldap->get_error();
 
1020
            }
 
1021
            $this->_restoreCurrentValue();
 
1022
        }
 
1023
    }
 
1024
 
 
1025
    private function setStatus($state) 
 
1026
    {
 
1027
        if(!in_array($state, array('ldap','file','undefined','modified','removed'))) {
 
1028
            trigger_error("Unknown property status given '{$state}' for {$this->class}:{$this->name}!");
 
1029
        }else{
 
1030
            $this->status = $state; 
 
1031
        }
 
1032
    }
 
1033
 
 
1034
    function isValid() 
 
1035
    { 
 
1036
        return(TRUE);    
 
1037
    }
 
1038
}
 
1039
 
 
1040
 
 
1041
 
 
1042
interface propertyMigration
 
1043
{
 
1044
    function __construct($config,$property);
 
1045
}
 
1046
 
 
1047
 
 
1048
?>