class_management.inc 32 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
      $this->registerAction("saveSnapshot",     "saveSnapshot");
      $this->registerAction("restoreSnapshot",  "restoreSnapshot");
      $this->registerAction("cancelSnapshot",   "closeDialogs");
    }
144
145
  }

146
  /*!
147
   * \brief  Execute this plugin
148
149
150
151
152
153
   *          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$/');
154
    session::set('LOCK_VARS_TO_USE', $vars);
155
156

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

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

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

178
179
    // Handle actions (POSTs and GETs)
    $str = $this->handleActions($this->detectPostActions());
180
181
182
    if ($str) {
      return $this->getHeader().$str;
    }
183
184

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

    // Display tab object.
197
    if ($this->tabObject instanceOf simpleTabs) {
198
      $this->tabObject->save_object();
199
      $display = $this->tabObject->execute();
200
201
      $display .= $this->_getTabFooter();
      return $this->getHeader().$display;
202
203
204
    }

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

211
      // No bases specified? Try base
212
      if (!count($bases)) $bases[] = $this->headpage->getBase();
213
214
215

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

217
    // Display list
218
    return $this->renderList();
219
  }
220

221
222
223
224
  function renderList()
  {
    $this->headpage->update();
    $display = $this->headpage->render();
225
    return $this->getHeader().$display;
226
227
228
229
  }

  function getHeadpage()
  {
230
    return $this->headpage;
231
232
233
234
  }

  function getFilter()
  {
235
    return $this->filter;
236
237
  }

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

    if (in_array_ics('plInfo', get_class_methods(get_class($this)))) {
249
250
251
      $plInfos  = $this->plInfo();
      $plTitle  = $plInfos['plTitle'];
      $plIcon   = $plInfos['plIcon'];
252
    } else {
253
254
      $plTitle  = $this->plDescription;
      $plIcon   = $this->plIcon;
255
    }
256

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


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

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

    // Skip footer if requested;
291
292
293
    if ($this->skipFooter) {
      return "";
    }
294
295
296

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


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

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

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

    // We've at least one entry to delete.
349
    if (count($this->dns)) {
350
351

      // check locks
352
353
      if ($user = get_multiple_locks($this->dns)) {
        return gen_locked_message($user, $this->dns);
354
355
356
357
      }

      // Add locks
      $dns_names = array();
358
359
      foreach ($this->dns as $dn) {
        $dns_names[] = LDAP::fix($dn);
360
361
362
363
364
      }
      add_lock ($this->dns, $this->ui->dn);

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


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

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

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

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

        // Delete the object
        $this->dn = $dn;
407
408
409
410
        $this->openTabObject(
          new $tabClass($this->config, $this->config->data['TABS'][$tabType], $this->dn, $aclCategory),
          $this->dn
        );
411
412
413
        $this->tabObject->delete ();

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

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


427
  /*!
428
   * \brief  Detects actions/events send by the ui
429
430
431
432
   *           and the corresponding targets.
   */
  function detectPostActions()
  {
433
    if (!is_object($this->headpage)) {
434
      trigger_error("No valid headpage given....!");
435
      return array();
436
    }
437
438
439
440
441
442
    $action = $this->headpage->getAction();
    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 (isset($_POST['delete_confirmed'])) $action['action'] = "removeConfirmed";
    if (isset($_POST['delete_cancel'])) $action['action'] = "cancelDelete";
443
444

    // Detect Snapshot actions
445
446
    if (isset($_POST['CreateSnapshot'])) $action['action'] = "saveSnapshot";
    if (isset($_POST['CancelSnapshot'])) $action['action'] = "cancelSnapshot";
447
    $matches = array();
448
449
    foreach ($_POST as $name => $value) {
      if (preg_match("/^RestoreSnapshot_(.*)_[xy]/", $name, $matches)) {
450
451
452
453
454
        $entry = intval($matches[1]);
        if (isset($this->dialogObject->last_list[$entry])) {
          $action['action'] = "restoreSnapshot";
          $action['targets'] = array($this->dialogObject->last_list[$entry]['dn']);
        }
455
      }
456
457
    }

458
    return $action;
459
460
461
  }


462
463
  /*!
   *  \brief  Calls the registered method for a given action/event.
464
465
466
   */
  function handleActions($action)
  {
467
    // Start action
468
    if (isset($this->actions[$action['action']])) {
469
      $func = $this->actions[$action['action']];
470
471
472
473
      if (!isset($action['targets'])) {
        $action['targets'] = array();
      }
      return $this->$func($action['action'], $action['targets'], $action);
474
    }
475
  }
476
477


478
  /*!
479
   * \brief  Opens the snapshot creation dialog for the given target.
480
   *
481
   * \param  String  $action  The name of the action which was the used as trigger.
482
   *
483
   * \param  Array   $target  A list of object dns, which should be affected by this method.
484
   *
485
   * \param  Array   $all     A combination of both 'action' and 'target'.
486
   */
487
  function createSnapshotDialog($action = "", $target = array(), $all = array())
488
  {
489
    @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $target, "Snaptshot creation initiated!");
490

491
492
493
    foreach ($target as $entry) {
      if (!empty($entry) && $this->ui->allow_snapshot_create($entry, $this->aclCategory)) {
        $this->dialogObject = new SnapShotDialog($this->config, $entry, $this);
494
495
        $this->dialogObject->aclCategories = array($this->aclCategory);
        $this->dialogObject->parent = &$this;
496
497
      } else {
        msg_dialog::display(_("Permission"), sprintf(_("You are not allowed to create a snapshot for %s."), $entry),
498
499
500
501
502
503
            ERROR_DIALOG);
      }
    }
  }


504
  /*!
505
506
   * \brief  Creates a snapshot new entry - This method is called when the somebody
   *           clicks 'save' in the "Create snapshot dialog" (see management::createSnapshotDialog).
507
   *
508
   *  \param  String  $action  The name of the action which was the used as trigger.
509
   *
510
   *  \param  Array   $target  A list of object dns, which should be affected by this method.
511
   *
512
   *  \param  Array   $all     A combination of both 'action' and 'target'.
513
   */
514
  function saveSnapshot($action = "", $target = array(), $all = array())
515
  {
516
517
518
    if (!is_object($this->dialogObject)) {
      return;
    }
519
520
    $this->dialogObject->save_object();
    $msgs = $this->dialogObject->check();
521
522
    if (count($msgs)) {
      foreach ($msgs as $msg) {
523
524
        msg_dialog::display(_("Error"), $msg, ERROR_DIALOG);
      }
525
526
527
528
    } else {
      $this->dn = $this->dialogObject->dn;
      $this->snapHandler->create_snapshot($this->dn, $this->dialogObject->CurrentDescription);
      @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $this->dn, "Snaptshot created!");
529
530
531
532
533
      $this->closeDialogs();
    }
  }


534
535
536
  /*!
   * \brief  Restores a snapshot object.
   *         The dn of the snapshot entry has to be given as ['target'] parameter.
537
   *
538
   * \param  String  $action  The name of the action which was the used as trigger.
539
   *
540
   * \param  Array   $target  A list of object dns, which should be affected by this method.
541
   *
542
   * \param  Array   $all     A combination of both 'action' and 'target'.
543
   */
544
  function restoreSnapshot($action = "", $target = array(), $all = array())
545
546
  {
    $entry = array_pop($target);
547
    if (!empty($entry) && $this->ui->allow_snapshot_restore($entry, $this->aclCategory)) {
548
      $this->snapHandler->restore_snapshot($entry);
549
      @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $entry, 'Snaptshot restored');
550
      $this->closeDialogs();
551
552
    } else {
      msg_dialog::display(_("Permission"), sprintf(_("You are not allowed to restore a snapshot for %s."), $entry),
553
554
555
556
557
          ERROR_DIALOG);
    }
  }


558
  /*!
559
   * \brief  Displays the "Restore snapshot dialog" for a given target.
560
   *          If no target is specified, open the restore removed object
561
   *           dialog.
562
   * \param  String  $action  The name of the action which was the used as trigger.
563
   *
564
   * \param  Array   $target  A list of object dns, which should be affected by this method.
565
   *
566
   * \param  Array   $all'     A combination of both 'action' and 'target'.
567
   */
568
  function restoreSnapshotDialog($action = "", $target = array(), $all = array())
569
570
  {
    // Set current restore base for snapshot handling.
571
    if (is_object($this->snapHandler)) {
572
      $bases = array();
573
      foreach ($this->storagePoints as $sp) {
574
575
576
577
        $bases[] = $sp.$this->headpage->getBase();
      }
    }

578
    // No bases specified? Try base
579
    if (!count($bases)) $bases[] = $this->headpage->getBase();
580

581
582
    if (!count($target)) {
      // No target, open the restore removed object dialog.
583
      $entry = $this->headpage->getBase();
584
    } else {
585
      // Display the restore points for a given object.
586
      $entry = $target[0];
587
588
589
590
591
592
593
594
595
596
597
598
    }

    if (!empty($entry) && $this->ui->allow_snapshot_restore($entry, $this->aclCategory)) {
      @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $entry, "Snaptshot restoring initiated!");
      $this->dialogObject = new SnapShotDialog($this->config, $entry, $this);
      $this->dialogObject->set_snapshot_bases($bases);
      $this->dialogObject->display_all_removed_objects  = !count($target);
      $this->dialogObject->display_restore_dialog       = TRUE;
      $this->dialogObject->parent                       = &$this;
    } else {
      msg_dialog::display(_("Permission"), sprintf(_("You are not allowed to restore a snapshot for %s."), $entry),
          ERROR_DIALOG);
599
600
601
602
    }
  }


603
604
605
606
  /*!
   * \brief  This method intiates the object creation.
   *
   * \param  String  $action  The name of the action which was the used as trigger.
607
   *
608
609
610
   * \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'.
611
   *
612
   * \param String $altTabClass Empty string.
613
   *
614
   * \param String $altTabType Empty string.
615
   *
616
   * \param String $altAclCategory Empty string.
617
   */
618
  function newEntry($action = "", $target = array(), $all = array(), $altTabClass = "", $altTabType = "", $altAclCategory = "")
619
620
621
622
623
  {
    /* To handle mutliple object types overload this method.
     * ...
     *   registerAction('newUser', 'newEntry');
     *   registerAction('newGroup','newEntry');
624
625
     * ...
     *
626
     * function newEntry($action = "", $target= array(), $all=array(), $altTabClass ="", $altTabType = "", $altAclCategory)
627
     * {
628
     *   switch($action) {
629
     *     case 'newUser' : {
630
     *       mangement::newEntry($action,$target,$all,"usertabs","USERTABS","user");
631
632
     *     }
     *     case 'newGroup' : {
633
     *       mangement::newEntry($action,$target,$all,"grouptabs","GROUPTABS","group");
634
635
636
     *     }
     *   }
     * }
637
     **/
638
639
640
641
642
643
    $tabType      = $this->tabType;
    $tabClass     = $this->tabClass;
    $aclCategory  = $this->aclCategory;
    if (!empty($altTabClass)) $tabClass = $altTabClass;
    if (!empty($altTabType)) $tabType = $altTabType;
    if (!empty($altAclCategory)) $aclCategory = $altAclCategory;
644

645
    // Check locking & lock entry if required
646
647
648
649
    $this->displayApplyBtn  = FALSE;
    $this->dn               = "new";
    $this->is_new           = TRUE;
    $this->is_single_edit   = FALSE;
650
651
652
653

    set_object_info($this->dn);

    // Open object.
654
    if (empty($tabClass) || empty($tabType)) {
655
      // No tab type defined
656
    } else {
657
      if (isset($this->config->data['TABS'][$tabType])) {
658
659
660
661
        $this->openTabObject(
          new $tabClass($this->config,$this->config->data['TABS'][$tabType], $this->dn, $aclCategory),
          $this->headpage->getBase()
        );
662
        @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $this->dn, "Create new entry initiated!");
663
664
665
666
667
668
669
      } else {
        msg_dialog::display(_("Error"), sprintf(_("No tab declaration for '%s' found in your configuration file. Cannot create plugin instance!"), $tabType), ERROR_DIALOG);
      }
    }
  }


670
  /*!
671
   * \brief  This method opens an existing object or a list of existing objects to be edited.
672
   *
673
   * \param  String  $action  The name of the action which was the used as trigger.
674
   *
675
   * \param  Array   $target  A list of object dns, which should be affected by this method.
676
   *
677
   * \param  Array   $all     A combination of both 'action' and 'target'.
678
   *
679
   * \param String $altTabClass Empty string.
680
   *
681
   * \param String $altTabType Empty string.
682
   *
683
   * \param String $altAclCategory Empty string.
684
   */
685
  function editEntry($action = "", $target = array(), $all = array(), $altTabClass = "", $altTabType = "", $altAclCategory = "")
686
687
688
689
690
  {
    /* To handle mutliple object types overload this method.
     * ...
     *   registerAction('editUser', 'editEntry');
     *   registerAction('editGroup','editEntry');
691
692
     * ...
     *
693
     * function editEntry($action = "", $target= array(), $all=array(), $altTabClass ="", $altTabType = "", $altAclCategory)
694
     * {
695
     *   switch($action) {
696
     *     case 'editUser' : {
697
     *       mangement::editEntry($action,$target,$all,"usertabs","USERTABS","user");
698
699
     *     }
     *     case 'editGroup' : {
700
     *       mangement::editEntry($action,$target,$all,"grouptabs","GROUPTABS","group");
701
702
703
704
705
706
707
     *     }
     *   }
     * }
     **/

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

712
713
714
715
716
717
    $tabType      = $this->tabType;
    $tabClass     = $this->tabClass;
    $aclCategory  = $this->aclCategory;
    if (!empty($altTabClass)) $tabClass = $altTabClass;
    if (!empty($altTabType)) $tabType = $altTabType;
    if (!empty($altAclCategory)) $aclCategory = $altAclCategory;
718
719
720
721

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

    // Single edit - we only got one object dn.
722
    if (count($target) == 1) {
723
      $this->is_new         = FALSE;
724
725
726
727
728
729
      $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);
730
731
      if ($user != "") {
        return gen_locked_message($user, $this->dn, TRUE);
732
733
734
735
      }
      add_lock ($this->dn, $this->ui->dn);

      // Open object.
736
      if (empty($tabClass) || empty($tabType)) {
737
        trigger_error("We can't edit any object(s). 'tabClass' or 'tabType' is empty!");
738
      } else {
739
        $tab = $tabClass;
740
741
742
743
        $this->openTabObject(
          new $tab($this->config, $this->config->data['TABS'][$tabType], $this->dn, $aclCategory),
          $this->dn
        );
744
        @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $this->dn, "Edit entry initiated!");
745
746
747
748
749
      }
    }
  }


750
  /*!
751
   * \brief  Save object modifications and closes dialogs (returns to object listing).
752
753
   *          - Calls 'tab::check' to validate the given input.
   *          - Calls 'tab::save' to save back object modifications (e.g. to ldap).
754
755
   *          - Calls 'management::remove_locks' to remove eventually created locks.
   *          - Calls 'management::closeDialogs' to return to the object listing.
756
757
758
   */
  protected function saveChanges()
  {
759
    if ($this->tabObject instanceOf simpleTabs) {
760
761
      $this->tabObject->save_object();
      $msgs = $this->tabObject->check();
762
      if (count($msgs)) {
763
        msg_dialog::displayChecks($msgs);
764
        return;
765
      } else {
766
        $this->tabObject->save();
767
        @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $this->dns, "Entry saved!");
768
769
770
        $this->remove_lock();
        $this->closeDialogs();
      }
771
    } elseif ($this->dialogObject instanceOf plugin) {
772
773
      $this->dialogObject->save_object();
      $msgs = $this->dialogObject->check();
774
      if (count($msgs)) {
775
        msg_dialog::displayChecks($msgs);
776
        return;
777
      } else {
778
        $this->dialogObject->save();
779
        @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $this->dns, "Entry saved!");
780
781
782
783
784
785
786
        $this->remove_lock();
        $this->closeDialogs();
      }
    }
  }


787
788
789
790
  /*!
   *  \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).
791
792
793
   */
  protected function applyChanges()
  {
794
    if ($this->tabObject instanceOf simpleTabs) {
795
796
      $this->tabObject->save_object();
      $msgs = $this->tabObject->check();
797
      if (count($msgs)) {
798
        msg_dialog::displayChecks($msgs);
799
800
        return "";
      } else {
801
        $this->tabObject->save();
802
        @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $this->dns, "Modifications applied!");
803
804
805
806
807
808
        $this->tabObject->re_init();
      }
    }
  }


809
810
811
  /*!
   * \brief  This method closes dialogs
   *          and cleans up the cached object info and the ui.
812
   */
813
  public function closeDialogs()
814
  {
815
816
    $this->last_dn  = $this->dn;
    $this->dn       = "";
817
    $this->last_dns = $this->dns;
818
819
820
821
822
823
824
825
    $this->dns      = array();

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

    $this->skipFooter   = FALSE;
826
827
828
829
    set_object_info();
  }


830
831
  /*!
   * \brief  Editing an object was caneled.
832
833
834
835
836
837
838
839
840
   *          Close dialogs/tabs and remove locks.
   */
  protected function cancelEdit()
  {
    $this->remove_lock();
    $this->closeDialogs();
  }


841
842
843
844
  /*!
   *  \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')
845
   *          When the action/event new is send, the method 'createUser'
846
   *          will be called.
847
   */
848
  function registerAction($action, $target)
849
850
851
852
853
  {
    $this->actions[$action] = $target;
  }


854
  /*!
855
856
857
858
   * \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.
859
860
861
   */
  function remove_lock()
  {
862
    if (!empty($this->dn) && $this->dn != "new") {
863
864
      del_lock($this->dn);
    }
865
    if (count($this->dns)) {
866
867
868
869
870
      del_lock($this->dns);
    }
  }


871
  /*!
872
873
   * \brief  This method is used to queue and process copy&paste actions.
   *         Allows to copy, cut and paste mutliple entries at once.
874
   *
875
   * \param String $action The name of the action which was the used as trigger.
876
   *
877
   * \param Array $target A list of object dns, which should be affected by this method.
878
   *
879
   * \param Array $all A combination of both 'action' and 'target'.
880
   *
881
   * \param String $altTabClass Empty string.
882
   *
883
   * \param $altTabType Empty string.
884
   *
885
   * \param $altAclCategory Empty string.
886
   *
887
   * \param $altAclPlugin Empty string.
888
   */
889
890
  function copyPasteHandler($action = "", $target = array(), $all = array(),
      $altTabClass = "", $altTabType = "", $altAclCategory = "", $altAclPlugin = "")
891
892
  {
    // Return without any actions while copy&paste handler is disabled.
893
    if (!is_object($this->cpHandler)) <