class_management.inc 31.4 KB
Newer Older
1
2
3
4
<?php
/*
  This code is part of FusionDirectory (http://www.fusiondirectory.org/)
  Copyright (C) 2003-2010  Cajus Pollmeier
5
  Copyright (C) 2011-2015  FusionDirectory
6
7
8
9
10
11
12
13
14
15
16
17
18

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
19
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
20
21
*/

22
23
24
25
26
/*!
 * \file class_management.inc
 * Source code for the class management
 */

27
/*!
28
 * \brief This class contains all the function needed to manage various
Benoit Mortier's avatar
Benoit Mortier committed
29
 * functions like new,save, edit, apply, cut/copy/paste , snapshot etc...
Benoit Mortier's avatar
Benoit Mortier committed
30
 */
31
32
class management
{
33
  // Public
34
35
  public $config = NULL;
  public $ui     = NULL;
36
37
38
39
40
41
42
43

  // The plugin description
  public $plugname      = "unconfigured";
  public $plIcon        = "unconfigured";
  public $plDescription = "unconfigured";
  public $plHeadline    = "unconfigured";

  // The currently used object(s) (e.g. in edit, removal)
44
45
  public $dn      = "";  // this is public due to some compatibility problems with class plugin..
  protected $dns  = array();
46
47

  // The last used object(s).
48
  protected $last_dn  = "";
49
50
51
52
53
54
  protected $last_dns = array();

  // The common places the displayed objects are stored in. (e.g. array("ou=groups,",".."))
  protected $storagePoints = array();

  // The tab definitions to use for the current object.
55
56
57
  protected $tabClass     = "";      // e.g. usertabs
  protected $tabType      = "";      // e.g. USERTABS
  protected $aclPlugin    = "";      // e.g. generic
58
  protected $aclCategory  = "";      // e.g. user
59
  protected $objectName   = "";      // e.g. users
60
61

  // The opened object.
62
63
  protected $tabObject    = NULL;
  protected $dialogObject = NULL;
64
65

  // The last opened object.
66
67
  protected $last_tabObject     = NULL;
  protected $last_dialogObject  = NULL;
68
69
70
71
72

  // Whether to display the apply button or not
  protected $displayApplyBtn = FALSE;

  // Whether to display a header or not.
73
  protected $skipHeader = FALSE;
74
75

  // Whether to display a footer or not.
76
  protected $skipFooter = FALSE;
77

78
79
80
  protected $skipCpHandler    = FALSE;
  protected $skipSnapHandler  = FALSE;

81
  // Copy&Paste handler
82
  protected $cpHandler = NULL;
83
84
85
86
87

  // Indicates that we want to paste objects right now.
  protected $cpPastingStarted = FALSE;

  // The Snapshot handler class.
88
  protected $snapHandler = NULL;
89
90

  // The listing handlers
91
92
  protected $headpage = NULL;
  protected $filter   = NULL;
93
94
95
96
97

  // A list of configured actions/events
  protected $actions = array();

  // Attributes managed by this plugin, can be used in post events;
98
  public $attributes = array();
99

100
101
102
  // Some management classes are used in tab groups and needs this set to FALSE.
  var $is_template    = FALSE;

103
  function  __construct(&$config, $ui, $plugname, $headpage)
104
105
106
  {
    $this->plugname = $plugname;
    $this->headpage = $headpage;
107
108
    $this->ui       = $ui;
    $this->config   = $config;
109

110
    // Add copy&paste and snapshot handler.
111
    if (!$this->skipCpHandler) {
112
113
114
      $this->cpHandler = new CopyPasteHandler($this->config);
      $this->headpage->setCopyPasteHandler($this->cpHandler);
    }
115
    if (!$this->skipSnapHandler && ($this->config->get_cfg_value("enableSnapshots") == "TRUE")) {
116
117
      $this->snapHandler = new SnapshotHandler($this->config);
      $this->headpage->setSnapshotHandler($this->snapHandler);
118
119
120
121
122
123
124
    }

    // Register default actions
    $this->registerAction("new",    "newEntry");
    $this->registerAction("edit",   "editEntry");
    $this->registerAction("apply",  "applyChanges");
    $this->registerAction("save",   "saveChanges");
125
126

    $this->registerAction("cancel",       "cancelEdit");
127
    $this->registerAction("cancelDelete", "cancelEdit");
128
129
130

    $this->registerAction("remove",           "removeEntryRequested");
    $this->registerAction("removeConfirmed",  "removeEntryConfirmed");
131

132
133
134
    $this->registerAction("copy",   "copyPasteHandler");
    $this->registerAction("cut",    "copyPasteHandler");
    $this->registerAction("paste",  "copyPasteHandler");
135

136
137
138
    if ($this->config->get_cfg_value('enableSnapshots') == 'TRUE') {
      $this->registerAction('snapshot', 'createSnapshotDialog');
      $this->registerAction('restore',  'restoreSnapshotDialog');
139
    }
140
141
  }

142
  /*!
143
   * \brief  Execute this plugin
144
145
146
147
148
149
   *          Handle actions/events, locking, snapshots, dialogs, tabs,...
   */
  function execute()
  {
    // Ensure that html posts and gets are kept even if we see a 'Entry islocked' dialog.
    $vars = array('/^act$/','/^listing/','/^PID$/','/^FILTER_PID$/');
150
    session::set('LOCK_VARS_TO_USE', $vars);
151
152

    /* Display the copy & paste dialog, if it is currently open */
153
154
155
    $ret = $this->copyPasteHandler("", array());
    if ($ret) {
      return $this->getHeader().$ret;
156
157
158
159
160
161
162
    }

    // Update filter
    if ($this->filter) {
      $this->filter->update();
      session::global_set(get_class($this)."_filter", $this->filter);
      session::set('autocomplete', $this->filter);
163
      if (!$this->filter->isValid()) {
164
165
166
167
        msg_dialog::display(_("Filter error"), _("The filter is incomplete!"), ERROR_DIALOG);
      }
    }

168
169
    // Pre-render list to init things if a dn is gonna be opened on first load
    if (isset($_REQUEST['dn'])) {
170
      $this->headpage->filter->setCurrentScope('sub');
171
172
173
      $this->renderList();
    }

174
175
    // Handle actions (POSTs and GETs)
    $str = $this->handleActions($this->detectPostActions());
176
177
178
    if ($str) {
      return $this->getHeader().$str;
    }
179
180

    // Open single dialog objects
181
182
183
184
185
    if (is_object($this->dialogObject)) {
      if (method_exists($this->dialogObject, 'save_object')) {
        $this->dialogObject->save_object();
      }
      if (method_exists($this->dialogObject, 'execute')) {
186
        $display = $this->dialogObject->execute();
187
188
        $display .= $this->_getTabFooter();
        return $this->getHeader().$display;
189
      }
190
191
192
    }

    // Display tab object.
193
    if ($this->tabObject instanceOf simpleTabs) {
194
      $this->tabObject->save_object();
195
      $display = $this->tabObject->execute();
196
197
      $display .= $this->_getTabFooter();
      return $this->getHeader().$display;
198
199
200
    }

    // Set current restore base for snapshot handling.
201
    if (is_object($this->snapHandler)) {
202
      $bases = array();
203
      foreach ($this->storagePoints as $sp) {
204
205
206
        $bases[] = $sp.$this->headpage->getBase();
      }

207
      // No bases specified? Try base
208
      if (!count($bases)) $bases[] = $this->headpage->getBase();
209
210
211

      $this->snapHandler->setSnapshotBases($bases);
    }
212

213
    // Display list
214
    return $this->renderList();
215
  }
216

217
218
219
220
  function renderList()
  {
    $this->headpage->update();
    $display = $this->headpage->render();
221
    return $this->getHeader().$display;
222
223
224
225
  }

  function getHeadpage()
  {
226
    return $this->headpage;
227
228
229
230
  }

  function getFilter()
  {
231
    return $this->filter;
232
233
  }

234
  /*!
235
   * \brief  Generates the plugin header which is displayed whenever a tab object is
236
237
238
239
   *           opened.
   */
  protected function getHeader()
  {
240
241
242
243
244
    if ($this->skipHeader) {
      return "";
    }

    if (in_array_ics('plInfo', get_class_methods(get_class($this)))) {
245
246
247
      $plInfos  = $this->plInfo();
      $plTitle  = $plInfos['plTitle'];
      $plIcon   = $plInfos['plIcon'];
248
    } else {
249
250
      $plTitle  = $this->plDescription;
      $plIcon   = $this->plIcon;
251
    }
252

253
254
255
    if (!preg_match('/^geticon/', $plIcon)) {
      $plIcon = get_template_path($plIcon);
    }
256
257
    if (get_object_info() != '') {
      $display = print_header($plIcon, _($plTitle),
258
          '<img alt="" class="center" src="geticon.php?context=status&amp;icon=object-locked&amp;size=16"/>'.
259
260
          LDAP::fix(get_object_info()));
    } else {
261
      $display = print_header($plIcon, _($plTitle));
262
    }
263
    return $display;
264
265
266
  }


267
  /*!
268
   * \brief  Generates the footer which is used whenever a tab object is
269
270
271
272
   *           displayed.
   */
  protected function _getTabFooter()
  {
273
    // Do not display tab footer for non tab objects
274
    if (!($this->tabObject instanceOf simpleTabs)) {
275
      return "";
276
277
    }

278
    // Check if there is a dialog opened - We don't need any buttons in this case.
279
    if ($this->tabObject->by_object[$this->tabObject->current]) {
280
      $current = $this->tabObject->by_object[$this->tabObject->current];
281
282
      if (isset($current->dialog) && (is_object($current->dialog) || $current->dialog)) {
        return "";
283
284
285
286
      }
    }

    // Skip footer if requested;
287
288
289
    if ($this->skipFooter) {
      return "";
    }
290
291
292

    // In case an of locked entry, we may have opened a read-only tab.
    $str = "";
293
294
295
296
    if (isset($this->tabObject->read_only) && ($this->tabObject->read_only == TRUE)) {
      $str .= '<p class="plugbottom">'."\n".
        '<input type="submit" name="edit_cancel" value="'.msgPool::cancelButton().'">'."\n".
        '</p>';
297
298
      return $str;
    } else {
299
      // Display ok, (apply) and cancel buttons
300
301
      $str .= '<p class="plugbottom">'."\n";
      $str .= '<input type="submit" name="edit_finish" style="width:80px" value="'.msgPool::okButton().'"/>'."\n";
302
303
      $str .= "&nbsp;\n";
      if ($this->displayApplyBtn) {
304
        $str .= '<input type="submit" name="edit_apply" value="'.msgPool::applyButton().'"/>'."\n";
305
        $str .= "&nbsp;\n";
306
      }
307
308
      $str .= '<input type="submit" name="edit_cancel" value="'.msgPool::cancelButton().'"/>'."\n";
      $str .= '</p>';
309
    }
310
    return $str;
311
312
313
  }


314
  /*!
315
   * \brief  Initiates the removal for the given entries
316
   *           and displays a confirmation dialog.
317
   *
318
   * \param  String  $action  The name of the action which was the used as trigger.
319
   *
320
   * \param  Array   $target  A list of object dns, which should be affected by this method.
321
   *
322
   * \param  Array   $all     A combination of both 'action' and 'target'.
323
   */
324
  protected function removeEntryRequested($action = "", $target = array(), $all = array())
325
326
327
328
  {
    $disallowed = array();
    $this->dns = array();

329
    @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $target, "Entry removel requested!");
330

331
    // Check permissons for each target
332
    foreach ($target as $dn) {
333
      $acl = $this->ui->get_permissions($dn, $this->aclCategory."/".$this->aclPlugin);
334
      if (preg_match("/d/", $acl)) {
335
        $this->dns[] = $dn;
336
      } else {
337
338
339
        $disallowed[] = $dn;
      }
    }
340
341
    if (count($disallowed)) {
      msg_dialog::display(_("Permission"), msgPool::permDelete($disallowed), INFO_DIALOG);
342
343
344
    }

    // We've at least one entry to delete.
345
    if (count($this->dns)) {
346
347

      // check locks
348
349
      if ($user = get_multiple_locks($this->dns)) {
        return gen_locked_message($user, $this->dns);
350
351
352
353
      }

      // Add locks
      $dns_names = array();
354
355
      foreach ($this->dns as $dn) {
        $dns_names[] = LDAP::fix($dn);
356
357
358
359
360
      }
      add_lock ($this->dns, $this->ui->dn);

      // Display confirmation dialog.
      $smarty = get_smarty();
361
362
363
      $smarty->assign("info", msgPool::deleteInfo($dns_names, _($this->objectName)));
      $smarty->assign("multiple", TRUE);
      return $smarty->fetch(get_template_path('remove.tpl', TRUE));
364
    }
365
  }
366
367


368
  /*!
369
   * \brief  Object removal was confirmed, now remove the requested entries.
370
   *
371
   * \param  String  $action  The name of the action which was the used as trigger.
372
   *
373
   * \param  Array   $target  A list of object dns, which should be affected by this method.
374
   *
375
   * \param  Array   $all     A combination of both 'action' and 'target'.
376
   *
377
   * \param String $altTabClass Empty string.
378
   *
379
   * \param String $altTabType Empty string.
380
   *
381
   * \param String $altAclCategory Empty string.
382
   */
383
384
  function removeEntryConfirmed($action = "", $target = array(), $all = array(),
      $altTabClass = "", $altTabType = "", $altAclCategory = "")
385
  {
386
387
388
389
390
391
392
    $tabType      = $this->tabType;
    $tabClass     = $this->tabClass;
    $aclCategory  = $this->aclCategory;

    if (!empty($altTabClass)) $tabClass = $altTabClass;
    if (!empty($altTabType)) $tabType = $altTabType;
    if (!empty($altAclCategory)) $aclCategory = $altAclCategory;
393

394
    @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $target, "Entry removal confirmed!");
395

396
    foreach ($this->dns as $dn) {
397
      // Check permissions, are we allowed to remove this object?
398
      $acl = $this->ui->get_permissions($dn, $aclCategory."/".$this->aclPlugin);
399
      if (preg_match("/d/", $acl)) {
400
401
402

        // Delete the object
        $this->dn = $dn;
403
404
405
406
        $this->openTabObject(
          new $tabClass($this->config, $this->config->data['TABS'][$tabType], $this->dn, $aclCategory),
          $this->dn
        );
407
408
409
        $this->tabObject->delete ();

        // Remove the lock for the current object.
410
        del_lock($this->dn);
411
412
      } else {
        msg_dialog::display(_("Permission error"), msgPool::permDelete(), ERROR_DIALOG);
413
        new log("security", "group/".get_class($this), $dn, array(), "Tried to trick deletion.");
414
415
416
417
418
419
420
421
422
      }
    }

    // Cleanup
    $this->remove_lock();
    $this->closeDialogs();
  }


423
  /*!
424
   * \brief  Detects actions/events send by the ui
425
426
427
428
   *           and the corresponding targets.
   */
  function detectPostActions()
  {
429
    if (!is_object($this->headpage)) {
430
      trigger_error("No valid headpage given....!");
431
      return array();
432
    }
433
    $action = $this->headpage->getAction();
434
435
436
437
438
439
440
441
442
    if (isset($_POST['edit_apply']))  $action['action'] = 'apply';
    if (isset($_POST['edit_finish'])) $action['action'] = 'save';
    if (isset($_POST['edit_cancel'])) $action['action'] = 'cancel';
    if (!$this->is_modal_dialog()) {
      if (isset($_POST['delete_confirmed'])) {
        $action['action'] = 'removeConfirmed';
      }
      if (isset($_POST['delete_cancel'])) {
        $action['action'] = 'cancelDelete';
443
      }
444
445
    }

446
    return $action;
447
448
449
  }


450
451
  /*!
   *  \brief  Calls the registered method for a given action/event.
452
453
454
   */
  function handleActions($action)
  {
455
    // Start action
456
    if (isset($this->actions[$action['action']])) {
457
      $func = $this->actions[$action['action']];
458
459
460
461
      if (!isset($action['targets'])) {
        $action['targets'] = array();
      }
      return $this->$func($action['action'], $action['targets'], $action);
462
    }
463
  }
464

465
  /*!
466
   * \brief  Opens the snapshot creation dialog for the given target.
467
   *
468
   * \param  String  $action  The name of the action which was the used as trigger.
469
   *
470
   * \param  Array   $target  A list of object dns, which should be affected by this method.
471
   *
472
   * \param  Array   $all     A combination of both 'action' and 'target'.
473
   */
474
  function createSnapshotDialog($action = '', $target = array(), $all = array())
475
  {
476
    @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $target, 'Snaptshot creation initiated!');
477

478
479
480
481
482
483
484
485
486
    if (count($target) == 1) {
      $this->dn = array_pop($target);
      if (empty($this->dn)) {
        return;
      }
      $aclCategory = $this->aclCategory;
      if ($this->ui->allow_snapshot_create($this->dn, $aclCategory)) {
        $this->dialogObject = new SnapshotCreateDialog($this->config, $this->dn, $this, $aclCategory);
        $this->dialogObject->set_acl_base($this->dn);
487
      } else {
488
        msg_dialog::display(_('Permission'), sprintf(_('You are not allowed to create a snapshot for %s.'), $this->dn),
489
490
491
492
493
            ERROR_DIALOG);
      }
    }
  }

494
  /*!
495
   * \brief  Creates a new snapshot entry
496
   */
497
  function createSnapshot($dn, $description)
498
  {
499
500
    if ($this->dn !== $dn) {
      trigger_error('There was a problem with the snapshot workflow');
501
502
      return;
    }
503
504
505
    if (!empty($dn) && $this->ui->allow_snapshot_create($dn, $this->dialogObject->aclCategory)) {
      $this->snapHandler->createSnapshot($dn, $description);
      @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $dn, 'Snaptshot created!');
506
    } else {
507
508
      msg_dialog::display(_('Permission'), sprintf(_('You are not allowed to restore a snapshot for %s.'), $dn),
          ERROR_DIALOG);
509
510
511
    }
  }

512
513
  /*!
   * \brief  Restores a snapshot object.
514
   *
515
   * \param  String  $dn  The DN of the snapshot
516
   */
517
  function restoreSnapshot($dn)
518
  {
519
520
521
    if (!empty($dn) && $this->ui->allow_snapshot_restore($dn, $this->dialogObject->aclCategory)) {
      $this->snapHandler->restoreSnapshot($dn);
      @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $dn, 'Snaptshot restored');
522
      $this->closeDialogs();
523
    } else {
524
      msg_dialog::display(_('Permission'), sprintf(_('You are not allowed to restore a snapshot for %s.'), $dn),
525
526
527
528
529
          ERROR_DIALOG);
    }
  }


530
  /*!
531
   * \brief  Displays the "Restore snapshot dialog" for a given target.
532
   *          If no target is specified, open the restore removed object
533
   *           dialog.
534
   * \param  String  $action  The name of the action which was the used as trigger.
535
   *
536
   * \param  Array   $target  A list of object dns, which should be affected by this method.
537
   *
538
   * \param  Array   $all'     A combination of both 'action' and 'target'.
539
   */
540
  function restoreSnapshotDialog($action = '', $target = array(), $all = array())
541
542
  {
    // Set current restore base for snapshot handling.
543
    if (is_object($this->snapHandler)) {
544
      $bases = array();
545
      foreach ($this->storagePoints as $sp) {
546
547
548
549
        $bases[] = $sp.$this->headpage->getBase();
      }
    }

550
    // No bases specified? Try base
551
    if (!count($bases)) $bases[] = $this->headpage->getBase();
552

553
554
    if (!count($target)) {
      // No target, open the restore removed object dialog.
555
      $this->dn = $this->headpage->getBase();
556
    } else {
557
      // Display the restore points for a given object.
558
559
560
561
      $this->dn = $target[0];
    }
    if (empty($this->dn)) {
      return;
562
563
    }

564
565
566
567
568
569
    $aclCategory = $this->aclCategory;
    if ($this->ui->allow_snapshot_restore($this->dn, $aclCategory)) {
      @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $this->dn, 'Snaptshot restoring initiated!');
      $this->snapHandler->setSnapshotBases($bases);
      $this->dialogObject = new SnapshotRestoreDialog($this->config, $this->dn, $this, !count($target), $aclCategory);
      $this->dialogObject->set_acl_base($this->dn);
570
    } else {
571
      msg_dialog::display(_('Permission'), sprintf(_('You are not allowed to restore a snapshot for %s.'), $this->dn),
572
          ERROR_DIALOG);
573
574
575
    }
  }

576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
  /*!
   * \brief Get all deleted snapshots
   *
   * \param string $base The base
   *
   * \param string boolean $raw
   */
  function getAllDeletedSnapshots($raw = FALSE)
  {
    $tmp = array();
    $snapshotBases = $this->snapHandler->getSnapshotBases();
    if (is_array($snapshotBases)) {
      foreach ($snapshotBases as $base) {
        $tmp = array_merge($tmp, $this->snapHandler->getAllDeletedSnapshots($base, $raw));
      }
    } else {
      $tmp = $this->snapHandler->getAllDeletedSnapshots($snapshotBases, $raw);
    }
    return $tmp;
  }

  /*
   * \brief Return available snapshots for the given base
   *
   * \param string $dn The DN
   *
   * \param string boolean $raw
   */
  function getAvailableSnapsShots($dn, $raw = FALSE)
  {
    return $this->snapHandler->getAvailableSnapsShots($dn, $raw);
  }

  /*!
   * \brief Delete a snapshot
   *
   * \param string $dn DN of the snapshot
   */
  function removeSnapshot($dn)
  {
    $this->snapHandler->removeSnapshot($dn);
  }
618

619
620
621
622
  /*!
   * \brief  This method intiates the object creation.
   *
   * \param  String  $action  The name of the action which was the used as trigger.
623
   *
624
625
626
   * \param  Array   $target  A list of object dns, which should be affected by this method.
   *
   * \param  Array   $all     A combination of both 'action' and 'target'.
627
   *
628
   * \param String $altTabClass Empty string.
629
   *
630
   * \param String $altTabType Empty string.
631
   *
632
   * \param String $altAclCategory Empty string.
633
   */
634
  function newEntry($action = "", $target = array(), $all = array(), $altTabClass = "", $altTabType = "", $altAclCategory = "")
635
636
637
638
639
  {
    /* To handle mutliple object types overload this method.
     * ...
     *   registerAction('newUser', 'newEntry');
     *   registerAction('newGroup','newEntry');
640
641
     * ...
     *
642
     * function newEntry($action = "", $target= array(), $all=array(), $altTabClass ="", $altTabType = "", $altAclCategory)
643
     * {
644
     *   switch($action) {
645
     *     case 'newUser' : {
646
     *       mangement::newEntry($action,$target,$all,"usertabs","USERTABS","user");
647
648
     *     }
     *     case 'newGroup' : {
649
     *       mangement::newEntry($action,$target,$all,"grouptabs","GROUPTABS","group");
650
651
652
     *     }
     *   }
     * }
653
     **/
654
655
656
657
658
659
    $tabType      = $this->tabType;
    $tabClass     = $this->tabClass;
    $aclCategory  = $this->aclCategory;
    if (!empty($altTabClass)) $tabClass = $altTabClass;
    if (!empty($altTabType)) $tabType = $altTabType;
    if (!empty($altAclCategory)) $aclCategory = $altAclCategory;
660

661
    // Check locking & lock entry if required
662
663
664
    $this->displayApplyBtn  = FALSE;
    $this->dn               = "new";
    $this->is_single_edit   = FALSE;
665
666
667
668

    set_object_info($this->dn);

    // Open object.
669
    if (empty($tabClass) || empty($tabType)) {
670
      // No tab type defined
671
    } else {
672
      if (isset($this->config->data['TABS'][$tabType])) {
673
674
675
676
        $this->openTabObject(
          new $tabClass($this->config,$this->config->data['TABS'][$tabType], $this->dn, $aclCategory),
          $this->headpage->getBase()
        );
677
        @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $this->dn, "Create new entry initiated!");
678
679
680
681
682
683
684
      } else {
        msg_dialog::display(_("Error"), sprintf(_("No tab declaration for '%s' found in your configuration file. Cannot create plugin instance!"), $tabType), ERROR_DIALOG);
      }
    }
  }


685
  /*!
686
   * \brief  This method opens an existing object or a list of existing objects to be edited.
687
   *
688
   * \param  String  $action  The name of the action which was the used as trigger.
689
   *
690
   * \param  Array   $target  A list of object dns, which should be affected by this method.
691
   *
692
   * \param  Array   $all     A combination of both 'action' and 'target'.
693
   *
694
   * \param String $altTabClass Empty string.
695
   *
696
   * \param String $altTabType Empty string.
697
   *
698
   * \param String $altAclCategory Empty string.
699
   */
700
  function editEntry($action = "", $target = array(), $all = array(), $altTabClass = "", $altTabType = "", $altAclCategory = "")
701
702
703
704
705
  {
    /* To handle mutliple object types overload this method.
     * ...
     *   registerAction('editUser', 'editEntry');
     *   registerAction('editGroup','editEntry');
706
707
     * ...
     *
708
     * function editEntry($action = "", $target= array(), $all=array(), $altTabClass ="", $altTabType = "", $altAclCategory)
709
     * {
710
     *   switch($action) {
711
     *     case 'editUser' : {
712
     *       mangement::editEntry($action,$target,$all,"usertabs","USERTABS","user");
713
714
     *     }
     *     case 'editGroup' : {
715
     *       mangement::editEntry($action,$target,$all,"grouptabs","GROUPTABS","group");
716
717
718
719
720
721
722
     *     }
     *   }
     * }
     **/

    // Do not create a new tabObject while there is already one opened,
    //  the user may have just pressed F5 to reload the page.
723
    if (is_object($this->tabObject)) {
724
725
      return;
    }
726

727
728
729
730
731
732
    $tabType      = $this->tabType;
    $tabClass     = $this->tabClass;
    $aclCategory  = $this->aclCategory;
    if (!empty($altTabClass)) $tabClass = $altTabClass;
    if (!empty($altTabType)) $tabType = $altTabType;
    if (!empty($altAclCategory)) $aclCategory = $altAclCategory;
733
734
735
736

    $this->displayApplyBtn = count($target) == 1;

    // Single edit - we only got one object dn.
737
    if (count($target) == 1) {
738
739
740
741
742
743
      $this->is_single_edit = TRUE;

      // Get the dn of the object and creates lock
      $this->dn = array_pop($target);
      set_object_info($this->dn);
      $user = get_lock($this->dn);
744
745
      if ($user != "") {
        return gen_locked_message($user, $this->dn, TRUE);
746
747
748
749
      }
      add_lock ($this->dn, $this->ui->dn);

      // Open object.
750
      if (empty($tabClass) || empty($tabType)) {
751
        trigger_error("We can't edit any object(s). 'tabClass' or 'tabType' is empty!");
752
      } else {
753
        $tab = $tabClass;
754
755
756
757
        $this->openTabObject(
          new $tab($this->config, $this->config->data['TABS'][$tabType], $this->dn, $aclCategory),
          $this->dn
        );
758
        @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $this->dn, "Edit entry initiated!");
759
760
761
762
763
      }
    }
  }


764
  /*!
765
   * \brief  Save object modifications and closes dialogs (returns to object listing).
766
767
   *          - Calls 'tab::check' to validate the given input.
   *          - Calls 'tab::save' to save back object modifications (e.g. to ldap).
768
769
   *          - Calls 'management::remove_locks' to remove eventually created locks.
   *          - Calls 'management::closeDialogs' to return to the object listing.
770
771
772
   */
  protected function saveChanges()
  {
773
    if ($this->tabObject instanceOf simpleTabs) {
774
775
      $this->tabObject->save_object();
      $msgs = $this->tabObject->check();
776
      if (count($msgs)) {
777
        msg_dialog::displayChecks($msgs);
778
        return;
779
      } else {
780
        $this->tabObject->save();
781
        @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $this->dns, 'Entry saved!');
782
783
784
        $this->remove_lock();
        $this->closeDialogs();
      }
785
    } elseif ($this->dialogObject instanceOf plugin) {
786
787
      $this->dialogObject->save_object();
      $msgs = $this->dialogObject->check();
788
      if (count($msgs)) {
789
        msg_dialog::displayChecks($msgs);
790
        return;
791
      } else {
792
        $this->dialogObject->save();
793
        @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $this->dns, 'Entry saved!');
794
795
796
797
798
799
800
        $this->remove_lock();
        $this->closeDialogs();
      }
    }
  }


801
802
803
804
  /*!
   *  \brief  Save object modifications and keep dialogs opened.
   *          - Calls 'ldap::check' to validate the given input.
   *          - Calls 'ldap::save' to save back object modifications (e.g. to ldap).
805
806
807
   */
  protected function applyChanges()
  {
808
    if ($this->tabObject instanceOf simpleTabs) {
809
810
      $this->tabObject->save_object();
      $msgs = $this->tabObject->check();
811
      if (count($msgs)) {
812
        msg_dialog::displayChecks($msgs);
813
814
        return "";
      } else {
815
        $this->tabObject->save();
816
        @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $this->dns, "Modifications applied!");
817
818
819
820
821
822
        $this->tabObject->re_init();
      }
    }
  }


823
824
825
  /*!
   * \brief  This method closes dialogs
   *          and cleans up the cached object info and the ui.
826
   */
827
  public function closeDialogs()
828
  {
829
830
    $this->last_dn  = $this->dn;
    $this->dn       = "";
831
    $this->last_dns = $this->dns;
832
833
834
835
836
837
838
839
    $this->dns      = array();

    $this->last_tabObject     = $this->tabObject;
    $this->tabObject          = NULL;
    $this->last_dialogObject  = $this->dialogObject;
    $this->dialogObject       = NULL;

    $this->skipFooter   = FALSE;
840
841
842
843
    set_object_info();
  }


844
845
  /*!
   * \brief  Editing an object was caneled.
846
847
848
849
850
851
852
853
854
   *          Close dialogs/tabs and remove locks.
   */
  protected function cancelEdit()
  {
    $this->remove_lock();
    $this->closeDialogs();
  }


855
856
857
858
  /*!
   *  \brief  Every click in the list user interface sends an event
   *          here can we connect those events to a method.
   *          eg. see management::registerEvent('new','createUser')
859
   *          When the action/event new is send, the method 'createUser'
860
   *          will be called.
861
   */
862
  function registerAction($action, $target)
863
864
865
866
867
  {
    $this->actions[$action] = $target;
  }


868
  /*!
869
870
871
872
   * \brief  Removes ldap object locks created by this class.
   *         Whenever an object is edited, we create locks to avoid
   *         concurrent modifications.
   *         This locks will automatically removed here.
873
874
875
   */
  function remove_lock()
  {
876
    if (!empty($this->dn) && $this->dn != "new") {
877
878
      del_lock($this->dn);
    }
879
    if (count($this->dns)) {
880
881
882
883
884
      del_lock($this->dns);
    }
  }


885
  /*!
886
887
   * \brief  This method is used to queue and process copy&paste actions.
   *         Allows to copy, cut and paste mutliple entries at once.
888
   *
889
   * \param String $action The name of the action which was the used as trigger.
890
   *
891
   * \param Array $target A list of object dns, which should be affected by this method.
892
   *
893
   * \param Array $all A combination of both 'action' and 'target'.
894
   *
895
   * \param String $altTabClass Empty string.
896
   *
897
   * \param $altTabType Empty string.
898
   *
899
   * \param $altAclCategory Empty string.
900
   *
901
   * \param $altAclPlugin Empty string.
902
   */
903
904
  function copyPasteHandler($action = "", $target = array(), $all = array(),
      $altTabClass = "", $altTabType = "", $altAclCategory = "", $altAclPlugin = "")
905
906
  {
    // Return without any actions while copy&paste handler is disabled.
907
    if (!is_object($this->cpHandler)) {
908
      return FALSE;
909
    }
910

911
912
913
914
    $tabType      = $this->tabType;
    $tabClass     = $this->tabClass;
    $aclCategory  = $this->aclCategory;
    $aclPlugin    = $this->aclPlugin;
915
    if (!empty($altTabClass) && !is_array($altTabClass)) {
916
917
      $tabClass = $altTabClass;
    }
918
    if (!empty($altTabType) && !is_array($altTabType)) {